pivy-0.6.5/0000755000175000017500000000000013606712377011261 5ustar kurtkurtpivy-0.6.5/interfaces/0000755000175000017500000000000013606712377013404 5ustar kurtkurtpivy-0.6.5/interfaces/simvoleon.i0000644000175000017500000000730513606712377015576 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %define SIMVOLEON_MODULE_DOCSTRING "The simvoleon module is a wrapper for the SIMVoleon library." %enddef %module(package="pivy", docstring=SIMVOLEON_MODULE_DOCSTRING) simvoleon %{ #if defined(_WIN32) || defined(__WIN32__) #include #undef max #undef ERROR #undef DELETE #undef ANY #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "coin_header_includes.h" %} /* let SWIG handle reference counting for all SoBase derived classes */ %feature("ref") SoBase "$this->ref();" %feature("unref") SoBase "$this->unref();" /* include the typemaps common to all pivy modules */ %include pivy_common_typemaps.i /* import the pivy main interface file */ %import coin.i %ignore SoVolumeData::setVolumeData(const SbVec3s &dimension, void *data, SoVolumeData::DataType type=SoVolumeData::UNSIGNED_BYTE, int significantbits=0); %ignore SoVRVolFileReader::setUserData(void * data); %extend SoVolumeData { void setVolumeData(SbVec3s dimension, char * data) { self->setVolumeData(dimension, data); } } %extend SoVRVolFileReader { void setUserData(char * filename) { self->setUserData(filename); } } %typemap(out) void * data = char *; %typemap(typecheck) void * data = char *; %include VolumeViz/details/SoVolumeRenderDetail.h %include VolumeViz/details/SoOrthoSliceDetail.h %include VolumeViz/details/SoObliqueSliceDetail.h %include VolumeViz/details/SoVolumeDetail.h %include VolumeViz/details/SoVolumeSkinDetail.h %include VolumeViz/readers/SoVRVolFileReader.h %include VolumeViz/readers/SoVolumeReader.h %include VolumeViz/nodes/SoTransferFunction.h %include VolumeViz/nodes/SoOrthoSlice.h %include VolumeViz/nodes/SoVolumeRender.h %include VolumeViz/nodes/SoVolumeRendering.h %include VolumeViz/nodes/SoObliqueSlice.h %include VolumeViz/nodes/SoVolumeIndexedFaceSet.h %include VolumeViz/nodes/SoVolumeFaceSet.h %include VolumeViz/nodes/SoVolumeData.h %include VolumeViz/nodes/SoVolumeIndexedTriangleStripSet.h %include VolumeViz/nodes/SoVolumeSkin.h %include VolumeViz/nodes/SoVolumeTriangleStripSet.h pivy-0.6.5/interfaces/soqt.i0000644000175000017500000003050713606712377014551 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %define SOQT_MODULE_DOCSTRING "The soqt module is a wrapper for the SoQt library. The module will try to import the shiboken module which is used for PySide. If found the involved wrapped Qt structures are converted to ones suitable for PySide, otherwise it will fall back to regular SWIG structures." %enddef %module(package="pivy.gui", docstring=SOQT_MODULE_DOCSTRING) soqt %{ /* Workaround for FILE* typemap. Import IO module instead of using extern PyTypeObject PyIOBase_Type, because the windows pyhton lib does not export PyIOBase_Type. Coppied from: https://github.com/Kagami/pygraphviz/commit/fe442dc16accb629c3feaf157af75f67ccabbd6e */ #if PY_MAJOR_VERSION >= 3 static PyObject *PyIOBase_TypeObj = NULL; static int init_file_emulator(void) { PyObject *io = PyImport_ImportModule("_io"); if (io == NULL) return -1; PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase"); if (PyIOBase_TypeObj == NULL) return -1; return 0; } #endif %} %init %{ #if PY_MAJOR_VERSION >= 3 if (init_file_emulator() < 0) { return NULL; } #endif %} %{ #if defined(_WIN32) || defined(__WIN32__) #include #undef max #undef ERROR #undef DELETE #undef ANY #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "coin_header_includes.h" /* make CustomCursor in SoQtCursor known to SWIG */ typedef SoQtCursor::CustomCursor CustomCursor; /* FIXME: there is a major pitfall reg. this solution, namely * thread safety! reconsider! 20030626 tamer. */ static void * Pivy_PythonInteractiveLoop(void *data) { PyRun_InteractiveLoop(stdin, ""); return NULL; } ////////////////////////////////////////////////////// //helper to get subclass name of qt-objects # include #if __unix #include template const char* get_typename(T& object) { return abi::__cxa_demangle(typeid(object).name(), 0, 0, 0); } #else template const char* get_typename(T& object) { return (typeid(object).name() + 6); // the +6 advanced the pointer 6 bytes (6 asc ii characters) to cut off prefix "class " from the object's class name } #endif ///////////////////////////////////////////////////// static const char * PYSIDE_QT = "pivy.gui.qt"; static PyObject* getShiboken() { // this function asumes shiboken is available directly // pip installs it in a wrong place // if you have installed shiboken with pip please symlink to correct directory PyObject * shiboken = NULL; if (!(shiboken = PyDict_GetItemString(PyModule_GetDict(PyImport_AddModule("__main__")), "shiboken2"))) { // simple import shiboken from python. shiboken = PyImport_ImportModule("shiboken2"); } return shiboken; } %} /* include the typemaps common to all pivy modules */ %include pivy_common_typemaps.i /* import the pivy main interface file */ %import coin.i /* typemaps to bridge against PySide */ %typemap(out) QEvent * { $result = NULL; { PyObject *qt = NULL; /* try to create a PySide QEvent instance through shiboken */ PyObject *shiboken = getShiboken(); if (shiboken && PyModule_Check(shiboken)) { /* check if the qt module is available and import it */ if (!(qt = PyDict_GetItemString(PyModule_GetDict(PyImport_AddModule("__main__")), PYSIDE_QT))) { qt = PyImport_ImportModule(PYSIDE_QT); } if (qt && PyModule_Check(qt)) { /* grab the wrapInstance(addr, type) function */ PyObject *shiboken_wrapinst_func = NULL; shiboken_wrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "wrapInstance"); if (PyCallable_Check(shiboken_wrapinst_func)) { PyObject *qevent_type = NULL, *arglist = NULL; qevent_type = PyDict_GetItemString(PyModule_GetDict(qt), "QEvent"); arglist = Py_BuildValue("(nO)", $1, qevent_type); if (!($result = PyEval_CallObject(shiboken_wrapinst_func, arglist))) { PyErr_Print(); } Py_DECREF(arglist); } } } /* if no QEvent could be created through shiboken return a swig QEvent type */ if (PyErr_ExceptionMatches(PyExc_ImportError) || !$result) { PyErr_Clear(); $result = SWIG_NewPointerObj((void *)($1), SWIGTYPE_p_QEvent, 0); } } } %typemap(out) QWidget * { $result = NULL; { PyObject *qt = NULL; /* try to create a PySide QWidget instance through shiboken */ PyObject *shiboken = getShiboken(); if (shiboken && PyModule_Check(shiboken)) { /* check if the qt module is available and import it */ if (!(qt = PyDict_GetItemString(PyModule_GetDict(PyImport_AddModule("__main__")), PYSIDE_QT))) { qt = PyImport_ImportModule(PYSIDE_QT); } if (qt && PyModule_Check(qt)) { /* grab the wrapInstance(addr, type) function */ PyObject *shiboken_wrapinst_func = NULL; shiboken_wrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "wrapInstance"); if (PyCallable_Check(shiboken_wrapinst_func)) { PyObject *qwidget_type = NULL, *arglist = NULL; qwidget_type = PyDict_GetItemString(PyModule_GetDict(qt), "QWidget"); arglist = Py_BuildValue("(nO)", $1, qwidget_type); if (!($result = PyEval_CallObject(shiboken_wrapinst_func, arglist))) { PyErr_Print(); } Py_DECREF(arglist); } } } /* if no QWidget could be created through shiboken return a swig QWidget type */ if (PyErr_ExceptionMatches(PyExc_ImportError) || !$result) { PyErr_Clear(); $result = SWIG_NewPointerObj((void *)($1), SWIGTYPE_p_QWidget, 0); } } } %typemap(in) QEvent * { { PyObject *shiboken = getShiboken(); if (shiboken && PyModule_Check(shiboken)) { /* grab the unwrapInstance(obj) function */ PyObject *shiboken_unwrapinst_func = NULL; shiboken_unwrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "getCppPointer"); if (PyCallable_Check(shiboken_unwrapinst_func)) { PyObject *arglist = NULL, *address = NULL; arglist = Py_BuildValue("(O)", $input); if (!(address = PyEval_CallObject(shiboken_unwrapinst_func, arglist))) { PyErr_Print(); } else if (PyNumber_Check(address)) { $1 = (QEvent*)PyLong_AsVoidPtr(address); } else if (PyTuple_Check(address)) { $1 = (QEvent*)PyLong_AsVoidPtr(PyTuple_GetItem(address, 0)); } Py_DECREF(arglist); } } } if (PyErr_ExceptionMatches(PyExc_ImportError) || !$1) { PyErr_Clear(); if ((SWIG_ConvertPtr($input, (void **)(&$1), SWIGTYPE_p_QEvent, SWIG_POINTER_EXCEPTION | 0)) == -1) SWIG_fail; } } %typemap(in) QWidget * { { if ($input == Py_None) { $1 = NULL; } else { PyObject *shiboken = getShiboken(); if (shiboken && PyModule_Check(shiboken)) { /* grab the unwrapInstance(obj) function */ PyObject *shiboken_unwrapinst_func = NULL; shiboken_unwrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "getCppPointer"); if (PyCallable_Check(shiboken_unwrapinst_func)) { PyObject *arglist = NULL, *address = NULL; arglist = Py_BuildValue("(O)", $input); if (!(address = PyEval_CallObject(shiboken_unwrapinst_func, arglist))) { PyErr_Print(); } else if (PyNumber_Check(address)) { $1 = (QWidget*)PyLong_AsVoidPtr(address); } else if (PyTuple_Check(address)) { $1 = (QWidget*)PyLong_AsVoidPtr(PyTuple_GetItem(address, 0)); } Py_DECREF(arglist); } } } if (PyErr_ExceptionMatches(PyExc_ImportError) || !$1) { PyErr_Clear(); if ((SWIG_ConvertPtr($input, (void **)(&$1), SWIGTYPE_p_QWidget, SWIG_POINTER_EXCEPTION | 0)) == -1) SWIG_fail; } } } class QEvent { QEvent(Type type); }; class QWidget { QWidget(QWidget* parent=0, const char* name=0, WFlags f=0); }; /* typemap typechecks for the overloaded constructors needed from SWIG 1.3.25 upwards */ %typemap(typecheck) QEvent * { void *ptr = NULL; { PyObject *shiboken = getShiboken(); if (shiboken && PyModule_Check(shiboken)) { /* grab the unwrapInstance(obj) function */ PyObject *shiboken_unwrapinst_func = NULL; shiboken_unwrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "getCppPointer"); if (PyCallable_Check(shiboken_unwrapinst_func)) { PyObject *arglist = NULL, *address = NULL; arglist = Py_BuildValue("(O)", $input); if (!(address = PyEval_CallObject(shiboken_unwrapinst_func, arglist))) { PyErr_Print(); } else if (PyNumber_Check(address)) { ptr = (QEvent*)PyLong_AsVoidPtr(address); } else if (PyTuple_Check(address)) { ptr = (QEvent*)PyLong_AsVoidPtr(PyTuple_GetItem(address, 0)); } Py_DECREF(arglist); } } } $1 = 1; if (PyErr_ExceptionMatches(PyExc_ImportError) || !ptr) { $1 = 0; PyErr_Clear(); if ((SWIG_ConvertPtr($input, (void **)(&ptr), SWIGTYPE_p_QEvent, 0)) != -1) { $1 = 1; } } } %typemap(typecheck) QWidget * { void *ptr = NULL; { PyObject *shiboken = getShiboken(); if (shiboken && PyModule_Check(shiboken)) { /* grab the unwrapInstance(obj) function */ PyObject *shiboken_unwrapinst_func = NULL; shiboken_unwrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "getCppPointer"); if (PyCallable_Check(shiboken_unwrapinst_func)) { PyObject *arglist = NULL, *address = NULL; arglist = Py_BuildValue("(O)", $input); if (!(address = PyEval_CallObject(shiboken_unwrapinst_func, arglist))) { PyErr_Print(); } else if (PyNumber_Check(address)) { ptr = (QWidget*)PyLong_AsVoidPtr(address); } else if (PyTuple_Check(address)) { ptr = (QWidget*)PyLong_AsVoidPtr(PyTuple_GetItem(address, 0)); } Py_DECREF(arglist); } } } $1 = 1; if (PyErr_ExceptionMatches(PyExc_ImportError) || !ptr) { $1 = 0; PyErr_Clear(); if ((SWIG_ConvertPtr($input, (void **)(&ptr), SWIGTYPE_p_QWidget, 0)) != -1) { $1 = 1; } } } %include Inventor/Qt/devices/SoQtDevice.h %include Inventor/Qt/devices/SoQtKeyboard.h %include Inventor/Qt/devices/SoQtMouse.h %include Inventor/Qt/SoQtBasic.h %include Inventor/Qt/SoQtObject.h %include Inventor/Qt/SoQt.h %include Inventor/Qt/SoQtGLWidget.h %include Inventor/Qt/viewers/SoQtPlaneViewer.h %include Inventor/Qt/viewers/SoQtViewer.h %include Inventor/Qt/viewers/SoQtExaminerViewer.h %include Inventor/Qt/viewers/SoQtFlyViewer.h %include Inventor/Qt/viewers/SoQtConstrainedViewer.h %include Inventor/Qt/viewers/SoQtFullViewer.h %include Inventor/Qt/widgets/SoQtPopupMenu.h %include Inventor/Qt/SoQtComponent.h %include Inventor/Qt/SoQtCursor.h %include Inventor/Qt/SoQtRenderArea.h pivy-0.6.5/interfaces/sogtk.i0000644000175000017500000000570013606712377014707 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %define SOGTK_MODULE_DOCSTRING "The sogtk module is a wrapper for the SoGtk library." %enddef %module(package="pivy.gui", docstring=SOGTK_MODULE_DOCSTRING) sogtk #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "coin_header_includes.h" /* FIXME: there is a major pitfall reg. this solution, namely * thread safety! reconsider! 20030626 tamer. */ static void *Pivy_PythonInteractiveLoop(void *data) { PyRun_InteractiveLoop(stdin, ""); return NULL; } %} /* include the typemaps common to all pivy modules */ %include pivy_common_typemaps.i /* import the pivy main interface file */ %import coin.i %include Inventor/Gtk/devices/SoGtkDevice.h %include Inventor/Gtk/devices/SoGtkKeyboard.h %include Inventor/Gtk/devices/SoGtkMouse.h %include Inventor/Gtk/widgets/SoGtkPopupMenu.h %include Inventor/Gtk/viewers/SoGtkViewer.h %include Inventor/Gtk/viewers/SoGtkConstrainedViewer.h %include Inventor/Gtk/viewers/SoGtkFullViewer.h %include Inventor/Gtk/viewers/SoGtkExaminerViewer.h %include Inventor/Gtk/viewers/SoGtkFlyViewer.h %include Inventor/Gtk/viewers/SoGtkPlaneViewer.h %include Inventor/Gtk/SoGtkGraphEditor.h %include Inventor/Gtk/SoGtkRoster.h %include Inventor/Gtk/SoGtk.h %include Inventor/Gtk/SoGtkBasic.h %include Inventor/Gtk/SoGtkObject.h %include Inventor/Gtk/SoGtkCursor.h %include Inventor/Gtk/SoGtkComponent.h %include Inventor/Gtk/SoGtkGLWidget.h %include Inventor/Gtk/SoGtkRenderArea.h pivy-0.6.5/interfaces/sowin.i0000644000175000017500000000560013606712377014716 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %module(package="pivy.gui") sowin %{ #if defined(_WIN32) || defined(__WIN32__) #include #undef max #undef ERROR #undef DELETE #undef ANY #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "coin_header_includes.h" /* make CustomCursor in SoWinCursor known to SWIG */ typedef SoWinCursor::CustomCursor CustomCursor; /* FIXME: there is a major pitfall reg. this solution, namely * thread safety! reconsider! 20030626 tamer. */ static void *Pivy_PythonInteractiveLoop(void *data) { PyRun_InteractiveLoop(stdin, ""); return NULL; } %} /* include the typemaps common to all pivy modules */ %include pivy_common_typemaps.i /* import the pivy main interface file */ %import coin.i %include Inventor/Win/devices/SoWinDevice.h %include Inventor/Win/devices/SoWinKeyboard.h %include Inventor/Win/devices/SoWinMouse.h %include Inventor/Win/viewers/SoWinViewer.h %include Inventor/Win/viewers/SoWinFullViewer.h %include Inventor/Win/viewers/SoWinExaminerViewer.h %include Inventor/Win/viewers/SoWinPlaneViewer.h %include Inventor/Win/viewers/SoWinConstrainedViewer.h %include Inventor/Win/viewers/SoWinFlyViewer.h %include Inventor/Win/widgets/SoWinPopupMenu.h %include Inventor/Win/SoWin.h %include Inventor/Win/SoWinBasic.h %include Inventor/Win/SoWinObject.h %include Inventor/Win/SoWinCursor.h %include Inventor/Win/SoWinComponent.h %include Inventor/Win/SoWinGLWidget.h %include Inventor/Win/SoWinRenderArea.h pivy-0.6.5/interfaces/coin.i0000644000175000017500000000636413606712377014517 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %define COIN_MODULE_DOCSTRING "Pivy is a Coin binding for Python. Coin is a high-level 3D graphics library with a C++ Application Programming Interface. Coin uses scene-graph data structures to render real-time graphics suitable for mostly all kinds of scientific and engineering visualization applications." %enddef %module(package="pivy", docstring=COIN_MODULE_DOCSTRING) coin // stdint is not wrapped automatically anymore with swig4.0 // https://stackoverflow.com/questions/40959436/swig-python-detected-a-memory-leak-of-type-uint32-t-no-destructor-found %include "stdint.i" %{ #if defined(_WIN32) || defined(__WIN32__) #include #undef max #undef ERROR #undef DELETE #endif #undef ANY #include "coin_header_includes.h" /* make GLState in SoGLLazyElement known to SWIG */ typedef SoGLLazyElement::GLState GLState; %} /* enable autodoc'ing for the generated wrapper */ %feature("autodoc", "1"); /* let SWIG handle reference counting for all SoBase derived classes */ %feature("ref") SoBase "$this->ref();" %feature("unref") SoBase "$this->unref();" %{ /* Workaround for FILE* typemap. Import IO module instead of using extern PyTypeObject PyIOBase_Type, because the windows pyhton lib does not export PyIOBase_Type. Coppied from: https://github.com/Kagami/pygraphviz/commit/fe442dc16accb629c3feaf157af75f67ccabbd6e */ #if PY_MAJOR_VERSION >= 3 static PyObject *PyIOBase_TypeObj; static int init_file_emulator(void) { PyObject *io = PyImport_ImportModule("_io"); if (io == NULL) return -1; PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase"); if (PyIOBase_TypeObj == NULL) return -1; return 0; } #endif %} %init %{ #if PY_MAJOR_VERSION >= 3 if (init_file_emulator() < 0) { return NULL; } #endif %} /* include the typemaps common to all pivy modules */ %include pivy_common_typemaps.i %include coin_header_includes.h /* removes all the properties for fields in classes derived from SoFieldContainer. this makes way for the dynamic access to fields as attributes. Note: this has to be the last code in the pivy file, therefore it is after all other SWIG declarations! */ %pythoncode %{ for x in list(locals()): value = locals()[x] try: if isinstance(value, type) and issubclass(value, SoFieldContainer): for name in list(value.__dict__): val = value.__dict__[name] if isinstance(val, property): delattr(value, name) except NameError: # value == SoSearchAction_duringSearchAll ??? pass %}pivy-0.6.5/interfaces/coin2.i0000644000175000017500000000455213606712377014576 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ // define PY_2 for c++ preprocessor #ifndef PY_2 #define PY_2 #endif // define PY_2 for swig preprocessor %{ #ifndef PY_2 #define PY_2 #endif %} %define COIN_MODULE_DOCSTRING "Pivy is a Coin binding for Python. Coin is a high-level 3D graphics library with a C++ Application Programming Interface. Coin uses scene-graph data structures to render real-time graphics suitable for mostly all kinds of scientific and engineering visualization applications." %enddef %module(package="pivy", docstring=COIN_MODULE_DOCSTRING) coin %{ #if defined(_WIN32) || defined(__WIN32__) #include #undef max #undef ERROR #undef DELETE #endif #undef ANY #include "coin_header_includes.h" /* make GLState in SoGLLazyElement known to SWIG */ typedef SoGLLazyElement::GLState GLState; %} /* enable autodoc'ing for the generated wrapper */ %feature("autodoc", "1"); /* let SWIG handle reference counting for all SoBase derived classes */ %feature("ref") SoBase "$this->ref();" %feature("unref") SoBase "$this->unref();" /* include the typemaps common to all pivy modules */ %include pivy_common_typemaps.i %include coin_header_includes.h /* removes all the properties for fields in classes derived from SoFieldContainer. this makes way for the dynamic access to fields as attributes. Note: this has to be the last code in the pivy file, therefore it is after all other SWIG declarations! */ %pythoncode %{ for x in locals().values(): if isinstance(x, type) and issubclass(x, SoFieldContainer): for name, thing in x.__dict__.items(): if isinstance(thing, property): delattr(x, name) %} pivy-0.6.5/interfaces/coin_header_includes.h0000644000175000017500000007662213606712377017720 0ustar kurtkurt#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if COIN_MAJOR_VERSION > 2 #include #include #endif #if COIN_MAJOR_VERSION == 3 #include #include #include #include #include #include #include #include #endif #if COIN_MAJOR_VERSION > 3 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif pivy-0.6.5/interfaces/soxt.i0000644000175000017500000000703513606712377014560 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %define SOXT_MODULE_DOCSTRING "The soxt module is a wrapper for the SoXt library." %enddef %module(package="pivy.gui", docstring=SOXT_MODULE_DOCSTRING) soxt %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "coin_header_includes.h" /* make CustomCursor in SoXtCursor known to SWIG */ typedef SoXtCursor::CustomCursor CustomCursor; /* FIXME: there is a major pitfall reg. this solution, namely * thread safety! reconsider! 20030626 tamer. */ static void * Pivy_PythonInteractiveLoop(void *data) { PyRun_InteractiveLoop(stdin, ""); return NULL; } %} /* include the typemaps common to all pivy modules */ %include pivy_common_typemaps.i /* import the pivy main interface file */ %import coin.i %include Inventor/Xt/devices/SoXtLinuxJoystick.h %include Inventor/Xt/devices/SoXtDevice.h %include Inventor/Xt/devices/SoXtKeyboard.h %include Inventor/Xt/devices/SoXtMouse.h %include Inventor/Xt/editors/SoXtColorEditor.h %include Inventor/Xt/editors/SoXtMaterialEditor.h %include Inventor/Xt/nodes/SoGuiColorEditor.h %include Inventor/Xt/nodes/SoGuiMaterialEditor.h %include Inventor/Xt/viewers/SoXtViewer.h %include Inventor/Xt/viewers/SoXtConstrainedViewer.h %include Inventor/Xt/viewers/SoXtFullViewer.h %include Inventor/Xt/viewers/SoXtExaminerViewer.h %include Inventor/Xt/viewers/SoXtFlyViewer.h %include Inventor/Xt/viewers/SoXtPlaneViewer.h %include Inventor/Xt/widgets/SoXtPopupMenu.h %include Inventor/Xt/SoXtResource.h %include Inventor/Xt/SoXt.h %include Inventor/Xt/SoXtBasic.h %include Inventor/Xt/SoXtObject.h %include Inventor/Xt/SoXtCursor.h %include Inventor/Xt/SoXtComponent.h %include Inventor/Xt/SoXtGLWidget.h %include Inventor/Xt/SoXtRenderArea.h %include Inventor/Xt/SoXtColorEditor.h %include Inventor/Xt/SoXtMaterialEditor.h pivy-0.6.5/interfaces/soqt2.i0000644000175000017500000003004413606712377014627 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ // define PY_2 for c++ preprocessor #ifndef PY_2 #define PY_2 #endif // define PY_2 for swig preprocessor %{ #ifndef PY_2 #define PY_2 #endif %} %define SOQT_MODULE_DOCSTRING "The soqt module is a wrapper for the SoQt library. The module will try to import the shiboken module which is used for PySide. If found the involved wrapped Qt structures are converted to ones suitable for PySide, otherwise it will fall back to regular SWIG structures." %enddef %module(package="pivy.gui", docstring=SOQT_MODULE_DOCSTRING) soqt %{ #if defined(_WIN32) || defined(__WIN32__) #include #undef max #undef ERROR #undef DELETE #undef ANY #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "coin_header_includes.h" /* make CustomCursor in SoQtCursor known to SWIG */ typedef SoQtCursor::CustomCursor CustomCursor; /* FIXME: there is a major pitfall reg. this solution, namely * thread safety! reconsider! 20030626 tamer. */ static void * Pivy_PythonInteractiveLoop(void *data) { PyRun_InteractiveLoop(stdin, ""); return NULL; } ////////////////////////////////////////////////////// //helper to get subclass name of qt-objects # include #if __unix #include template const char* get_typename(T& object) { return abi::__cxa_demangle(typeid(object).name(), 0, 0, 0); } #else template const char* get_typename(T& object) { return (typeid(object).name() + 6); // the +6 advanced the pointer 6 bytes (6 asc ii characters) to cut off prefix "class " from the object's class name } #endif ///////////////////////////////////////////////////// static const char * PYSIDE_QT = "pivy.gui.qt"; static PyObject* getShiboken() { // this function asumes shiboken is available directly // pip installs it in a wrong place // if you have installed shiboken with pip please symlink to correct directory PyObject * shiboken = NULL; if (!(shiboken = PyDict_GetItemString(PyModule_GetDict(PyImport_AddModule("__main__")), "shiboken2"))) { // simple import shiboken from python. shiboken = PyImport_ImportModule("shiboken2"); } return shiboken; } %} /* include the typemaps common to all pivy modules */ %include pivy_common_typemaps.i /* import the pivy main interface file */ %import coin.i /* typemaps to bridge against PySide */ %typemap(out) QEvent * { $result = NULL; { PyObject *qt = NULL; PyObject *shiboken = getShiboken(); /* try to create a PySide QEvent instance through shiboken */ if (shiboken && PyModule_Check(shiboken)) { /* check if the qt module is available and import it */ if (!(qt = PyDict_GetItemString(PyModule_GetDict(PyImport_AddModule("__main__")), PYSIDE_QT))) { qt = PyImport_ImportModule(PYSIDE_QT); } if (qt && PyModule_Check(qt)) { /* grab the wrapInstance(addr, type) function */ PyObject *shiboken_wrapinst_func = NULL; shiboken_wrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "wrapInstance"); if (PyCallable_Check(shiboken_wrapinst_func)) { PyObject *qevent_type = NULL, *arglist = NULL; qevent_type = PyDict_GetItemString(PyModule_GetDict(qt), "QEvent"); arglist = Py_BuildValue("(nO)", $1, qevent_type); if (!($result = PyEval_CallObject(shiboken_wrapinst_func, arglist))) { PyErr_Print(); } Py_DECREF(arglist); } } } /* if no QEvent could be created through shiboken return a swig QEvent type */ if (PyErr_ExceptionMatches(PyExc_ImportError) || !$result) { PyErr_Clear(); $result = SWIG_NewPointerObj((void *)($1), SWIGTYPE_p_QEvent, 0); } } } %typemap(out) QWidget * { $result = NULL; { PyObject *qt = NULL; PyObject *shiboken = getShiboken(); /* try to create a PySide QWidget instance through shiboken */ if (shiboken && PyModule_Check(shiboken)) { /* check if the qt module is available and import it */ if (!(qt = PyDict_GetItemString(PyModule_GetDict(PyImport_AddModule("__main__")), PYSIDE_QT))) { qt = PyImport_ImportModule(PYSIDE_QT); } if (qt && PyModule_Check(qt)) { /* grab the wrapInstance(addr, type) function */ PyObject *shiboken_wrapinst_func = NULL; shiboken_wrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "wrapInstance"); if (PyCallable_Check(shiboken_wrapinst_func)) { PyObject *qwidget_type = NULL, *arglist = NULL; qwidget_type = PyDict_GetItemString(PyModule_GetDict(qt), "QWidget"); arglist = Py_BuildValue("(nO)", $1, qwidget_type); if (!($result = PyEval_CallObject(shiboken_wrapinst_func, arglist))) { PyErr_Print(); } Py_DECREF(arglist); } } } /* if no QWidget could be created through shiboken return a swig QWidget type */ if (PyErr_ExceptionMatches(PyExc_ImportError) || !$result) { PyErr_Clear(); $result = SWIG_NewPointerObj((void *)($1), SWIGTYPE_p_QWidget, 0); } } } %typemap(in) QEvent * { { PyObject *shiboken = getShiboken(); if (shiboken && PyModule_Check(shiboken)) { /* grab the getCppPointer(obj) function */ PyObject *shiboken_unwrapinst_func = NULL; shiboken_unwrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "getCppPointer"); if (PyCallable_Check(shiboken_unwrapinst_func)) { PyObject *arglist = NULL, *address = NULL; arglist = Py_BuildValue("(O)", $input); if (!(address = PyEval_CallObject(shiboken_unwrapinst_func, arglist))) { PyErr_Print(); } else if (PyNumber_Check(address)) { $1 = (QEvent*)PyLong_AsVoidPtr(address); } else if (PyTuple_Check(address)) { $1 = (QEvent*)PyLong_AsVoidPtr(PyTuple_GetItem(address, 0)); } Py_DECREF(arglist); } } } if (PyErr_ExceptionMatches(PyExc_ImportError) || !$1) { PyErr_Clear(); if ((SWIG_ConvertPtr($input, (void **)(&$1), SWIGTYPE_p_QEvent, SWIG_POINTER_EXCEPTION | 0)) == -1) SWIG_fail; } } %typemap(in) QWidget * { { if ($input == Py_None) { $1 = NULL; } else { PyObject *shiboken = getShiboken(); /* check if the shiboken module is available and import it */ if (!(shiboken = PyDict_GetItemString(PyModule_GetDict(PyImport_AddModule("__main__")), "shiboken"))) { shiboken = PyImport_ImportModule("shiboken"); } if (shiboken && PyModule_Check(shiboken)) { /* grab the getCppPointer(obj) function */ PyObject *shiboken_unwrapinst_func = NULL; shiboken_unwrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "getCppPointer"); if (PyCallable_Check(shiboken_unwrapinst_func)) { PyObject *arglist = NULL, *address = NULL; arglist = Py_BuildValue("(O)", $input); if (!(address = PyEval_CallObject(shiboken_unwrapinst_func, arglist))) { PyErr_Print(); } else if (PyNumber_Check(address)) { $1 = (QWidget*)PyLong_AsVoidPtr(address); } else if (PyTuple_Check(address)) { $1 = (QWidget*)PyLong_AsVoidPtr(PyTuple_GetItem(address, 0)); } Py_DECREF(arglist); } } } if (PyErr_ExceptionMatches(PyExc_ImportError) || !$1) { PyErr_Clear(); if ((SWIG_ConvertPtr($input, (void **)(&$1), SWIGTYPE_p_QWidget, SWIG_POINTER_EXCEPTION | 0)) == -1) SWIG_fail; } } } class QEvent { QEvent(Type type); }; class QWidget { QWidget(QWidget* parent=0, const char* name=0, WFlags f=0); }; /* typemap typechecks for the overloaded constructors needed from SWIG 1.3.25 upwards */ %typemap(typecheck) QEvent * { void *ptr = NULL; { PyObject *shiboken = getShiboken() if (shiboken && PyModule_Check(shiboken)) { /* grab the getCppPointer(obj) function */ PyObject *shiboken_unwrapinst_func = NULL; shiboken_unwrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "getCppPointer"); if (PyCallable_Check(shiboken_unwrapinst_func)) { PyObject *arglist = NULL, *address = NULL; arglist = Py_BuildValue("(O)", $input); if (!(address = PyEval_CallObject(shiboken_unwrapinst_func, arglist))) { PyErr_Print(); } else if (PyNumber_Check(address)) { ptr = (QEvent*)PyLong_AsVoidPtr(address); } else if (PyTuple_Check(address)) { ptr = (QEvent*)PyLong_AsVoidPtr(PyTuple_GetItem(address, 0)); } Py_DECREF(arglist); } } } $1 = 1; if (PyErr_ExceptionMatches(PyExc_ImportError) || !ptr) { $1 = 0; PyErr_Clear(); if ((SWIG_ConvertPtr($input, (void **)(&ptr), SWIGTYPE_p_QEvent, 0)) != -1) { $1 = 1; } } } %typemap(typecheck) QWidget * { void *ptr = NULL; { PyObject *shiboken = getShiboken(); if (shiboken && PyModule_Check(shiboken)) { /* grab the getCppPointer(obj) function */ PyObject *shiboken_unwrapinst_func = NULL; shiboken_unwrapinst_func = PyDict_GetItemString(PyModule_GetDict(shiboken), "getCppPointer"); if (PyCallable_Check(shiboken_unwrapinst_func)) { PyObject *arglist = NULL, *address = NULL; arglist = Py_BuildValue("(O)", $input); if (!(address = PyEval_CallObject(shiboken_unwrapinst_func, arglist))) { PyErr_Print(); } else if (PyNumber_Check(address)) { ptr = (QWidget*)PyLong_AsVoidPtr(address); } else if (PyTuple_Check(address)) { ptr = (QWidget*)PyLong_AsVoidPtr(PyTuple_GetItem(address, 0)); } Py_DECREF(arglist); } } } $1 = 1; if (PyErr_ExceptionMatches(PyExc_ImportError) || !ptr) { $1 = 0; PyErr_Clear(); if ((SWIG_ConvertPtr($input, (void **)(&ptr), SWIGTYPE_p_QWidget, 0)) != -1) { $1 = 1; } } } %include Inventor/Qt/devices/SoQtDevice.h %include Inventor/Qt/devices/SoQtKeyboard.h %include Inventor/Qt/devices/SoQtMouse.h %include Inventor/Qt/SoQtBasic.h %include Inventor/Qt/SoQtObject.h %include Inventor/Qt/SoQt.h %include Inventor/Qt/SoQtGLWidget.h %include Inventor/Qt/viewers/SoQtPlaneViewer.h %include Inventor/Qt/viewers/SoQtViewer.h %include Inventor/Qt/viewers/SoQtExaminerViewer.h %include Inventor/Qt/viewers/SoQtFlyViewer.h %include Inventor/Qt/viewers/SoQtConstrainedViewer.h %include Inventor/Qt/viewers/SoQtFullViewer.h %include Inventor/Qt/widgets/SoQtPopupMenu.h %include Inventor/Qt/SoQtComponent.h %include Inventor/Qt/SoQtCursor.h %include Inventor/Qt/SoQtRenderArea.h pivy-0.6.5/interfaces/pivy_common_typemaps.i0000644000175000017500000003136513606712377020047 0ustar kurtkurt/* * Copyright (c) 2002-2007 Systems in Motion * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* header include needed to let nodekit extensions find the SbTime header */ %{ #include #if (PY_VERSION_HEX < 0x02050000) /* Py_ssize_t needed for Python 2.5 compatibility, but isn't defined * in earlier Python versions. */ typedef int Py_ssize_t; #endif #if PY_MAJOR_VERSION >= 3 #define IS_PY3K #endif /* a casting helper function */ SWIGEXPORT PyObject * cast(PyObject * self, PyObject * args) { swig_type_info * swig_type = 0; void * cast_obj = 0; char * type_name, * ptr_type; int type_len; PyObject * obj = 0; if (!PyArg_ParseTuple(args, "Os#:cast", &obj, &type_name, &type_len)) { SWIG_fail; } /* * add a pointer sign to the string coming from the interpreter * e.g. "SoSeparator" becomes "SoSeparator *" - so that SWIG_TypeQuery() * can do its job. */ if (!(ptr_type = (char*)malloc(type_len+3))) { SWIG_fail; } memset(ptr_type, 0, type_len+3); strncpy(ptr_type, type_name, type_len); strcat(ptr_type, " *"); if (!(swig_type = SWIG_TypeQuery(ptr_type))) { /* the britney maneuver: "baby one more time" by prefixing 'So' */ char * cast_name = (char*)malloc(type_len + 5); memset(cast_name, 0, type_len + 5); cast_name[0] = 'S'; cast_name[1] = 'o'; strncpy(cast_name+2, ptr_type, type_len+2); if (!(swig_type = SWIG_TypeQuery(cast_name))) { free(cast_name); free(ptr_type); SWIG_fail; } free(cast_name); } free(ptr_type); SWIG_ConvertPtr(obj, (void**)&cast_obj, NULL, SWIG_POINTER_EXCEPTION | 0); if (SWIG_arg_fail(1)) { SWIG_fail; } return SWIG_NewPointerObj((void*)cast_obj, swig_type, 0); fail: return NULL; } /* autocasting helper function for SoBase */ SWIGEXPORT PyObject * autocast_base(SoBase * base) { PyObject * result = NULL; /* autocast the result to the corresponding type */ if (base && base->isOfType(SoFieldContainer::getClassTypeId())) { PyObject * cast_args = NULL; PyObject * obj = NULL; SoType type = base->getTypeId(); /* in case of a non built-in type get the closest built-in parent */ while (!(type.isBad() || result)) { obj = SWIG_NewPointerObj((void*)base, SWIGTYPE_p_SoBase, 0); cast_args = Py_BuildValue("(Os)", obj, type.getName().getString()); result = cast(NULL, cast_args); Py_DECREF(cast_args); Py_DECREF(obj); if (!result) { type = type.getParent(); } } } if (!result) { Py_INCREF(Py_None); result = Py_None; } return result; } /* autocasting helper function for SoPath */ SWIGEXPORT PyObject * autocast_path(SoPath * path) { PyObject * result = NULL; /* autocast the result to the corresponding type */ if (path) { PyObject * cast_args = NULL; PyObject * obj = NULL; SoType type = path->getTypeId(); /* in case of a non built-in type get the closest built-in parent */ while (!(type.isBad() || result)) { obj = SWIG_NewPointerObj((void*)path, SWIGTYPE_p_SoPath, 0); cast_args = Py_BuildValue("(Os)", obj, type.getName().getString()); result = cast(NULL, cast_args); Py_DECREF(cast_args); Py_DECREF(obj); if (!result) { type = type.getParent(); } } } if (!result) { Py_INCREF(Py_None); result = Py_None; } return result; } /* autocasting helper function for SoField */ SWIGEXPORT PyObject * autocast_field(SoField * field) { PyObject * result = NULL; /* autocast the result to the corresponding type */ if (field) { PyObject * cast_args = NULL; PyObject * obj = NULL; SoType type = field->getTypeId(); /* in case of a non built-in type get the closest built-in parent */ while (!(type.isBad() || result)) { obj = SWIG_NewPointerObj((void*)field, SWIGTYPE_p_SoField, 0); cast_args = Py_BuildValue("(Os)", obj, type.getName().getString()); result = cast(NULL, cast_args); Py_DECREF(cast_args); Py_DECREF(obj); if (!result) { type = type.getParent(); } } } if (!result) { Py_INCREF(Py_None); result = Py_None; } return result; } /* autocasting helper function for SoEvent */ SWIGEXPORT PyObject * autocast_event(SoEvent * event) { PyObject * result = NULL; /* autocast the result to the corresponding type */ if (event) { PyObject * cast_args = NULL; PyObject * obj = NULL; SoType type = event->getTypeId(); /* in case of a non built-in type get the closest built-in parent */ while (!(type.isBad() || result)) { obj = SWIG_NewPointerObj((void*)event, SWIGTYPE_p_SoEvent, 0); cast_args = Py_BuildValue("(Os)", obj, type.getName().getString()); result = cast(NULL, cast_args); Py_DECREF(cast_args); Py_DECREF(obj); if (!result) { type = type.getParent(); } } } if (!result) { Py_INCREF(Py_None); result = Py_None; } return result; } %} /* typemaps for autocasting types through the Inventor type system */ %typemap(out) SoBase * { $result = autocast_base($1); } %typemap(out) SoFieldContainer * { $result = autocast_base($1); } %typemap(out) SoNode * { $result = autocast_base($1); } %typemap(out) SoPath * { $result = autocast_path($1); } %typemap(out) SoEngine * { $result = autocast_base($1); } %typemap(out) SoField * { $result = autocast_field($1); } %typemap(out) SoEvent * { $result = autocast_event($1); } %native(cast) PyObject * cast(PyObject * self, PyObject * args); /** * SWIG - interface includes and general typemap definitions **/ %include "typemaps.i" %include "cpointer.i" %pointer_class(char, charp); %pointer_class(int, intp); %pointer_class(long, longp); %pointer_class(float, floatp); %pointer_class(double, doublep); /* if SWIG determines the class abstract it doesn't generate * constructors of any kind. the following %feature * declarations take care about this for the classes we still * want a constructor for. */ %feature("notabstract") SoBoolOperation; %feature("notabstract") SoComposeRotation; %feature("notabstract") SoComposeVec3f; %feature("notabstract") SoDecomposeVec3f; %rename(output) print(FILE * fp) const; %rename(output) print(FILE * const fp) const; %rename(output) print(FILE * const file = stdout) const; %rename(srcFrom) from; %rename(destTo) to; /* generic typemaps to allow using python types instead of instances * within the python interpreter */ %typemap(in) int32_t = int; %typemap(out) int32_t = int; %typemap(typecheck) int32_t = int; %typemap(in) uint32_t = unsigned int; %typemap(out) uint32_t = unsigned int; %typemap(typecheck) uint32_t = unsigned int; %typemap(typecheck) SbName & { void *ptr = NULL; $1 = 1; #ifdef PY_2 if (!PyString_Check($input) && (SWIG_ConvertPtr($input, (void**)(&ptr), SWIGTYPE_p_SbName, 0) == -1)) #else if (!PyBytes_Check($input) && !PyUnicode_Check($input) && (SWIG_ConvertPtr($input, (void**)(&ptr), $descriptor(SbName *), 0) == -1)) #endif { $1 = 0; } } %typemap(in) SbName & { #ifdef PY_2 if (PyString_Check($input)) { $1 = new SbName(PyString_AsString($input)); } #else if (PyBytes_Check($input)) { $1 = new SbName(PyBytes_AsString($input)); } else if (PyUnicode_Check($input)){ $1 = new SbName(PyBytes_AsString(PyUnicode_AsEncodedString($input, "utf-8", "Error ~"))); } #endif else { SbName * tmp = NULL; $1 = new SbName; #ifdef PY_2 SWIG_ConvertPtr($input, (void**)&tmp, SWIGTYPE_p_SbName, 1); #else SWIG_ConvertPtr($input, (void**)&tmp, $descriptor(SbName *), 1); #endif *$1 = *tmp; } } %typemap(freearg) SbName & { if ($1) { delete $1; } } %typemap(typecheck) SbName { void *ptr = NULL; $1 = 1; #ifdef PY_2 if (!PyString_Check($input) && !PyUnicode_Check($input) && (SWIG_ConvertPtr($input, (void**)(&ptr), SWIGTYPE_p_SbName, 0) == -1)) #else // http://stackoverflow.com/questions/2807887/cs-char-by-swig-got-problem-in-python-3-0 if (!PyBytes_Check($input) && !PyUnicode_Check($input) && (SWIG_ConvertPtr($input, (void**)(&ptr), $descriptor(SbString *), 0) == -1)) #endif { $1 = 0; } } %typemap(in) SbName { #ifdef PY_2 if (PyString_Check($input)){ $1 = SbName(PyString_AsString($input)); } #else if (PyBytes_Check($input)){ $1 = SbName(PyBytes_AsString($input)); } else if (PyUnicode_Check($input)){ $1 = SbName(PyBytes_AsString(PyUnicode_AsEncodedString($input, "utf-8", "Error ~"))); } #endif else { SbName * namePtr; #ifdef PY_2 SWIG_ConvertPtr($input, (void**)&namePtr, SWIGTYPE_p_SbName, 1); #else SWIG_ConvertPtr($input, (void**)&namePtr, $descriptor(SbName *), 1); #endif $1 = *namePtr; } } %typemap(typecheck) SbString & { void *ptr = NULL; $1 = 1; #ifdef PY_2 if (!PyString_Check($input) && (SWIG_ConvertPtr($input, (void**)(&ptr), SWIGTYPE_p_SbString, 0) == -1)) #else if (!PyBytes_Check($input) && !PyUnicode_Check($input) && (SWIG_ConvertPtr($input, (void**)(&ptr), $descriptor(SbString *), 0) == -1)) #endif { $1 = 0; } } %typemap(in) SbString & { #ifdef PY_2 if (PyString_Check($input)) { $1 = new SbString(PyString_AsString($input)); } #else if (PyBytes_Check($input)) { $1 = new SbString(PyBytes_AsString($input)); } else if (PyUnicode_Check($input)){ $1 = new SbString(PyBytes_AsString(PyUnicode_AsEncodedString($input, "utf-8", "Error ~"))); } #endif else { SbString * tmp = NULL; $1 = new SbString; #ifdef PY_2 SWIG_ConvertPtr($input, (void**)&tmp, SWIGTYPE_p_SbString, 1); #else SWIG_ConvertPtr($input, (void**)&tmp, $descriptor(SbString *), 1); #endif *$1 = *tmp; } } %typemap(freearg) SbString & { if ($1) { delete $1; } } %typemap(typecheck) SbTime & { void *ptr = NULL; $1 = 1; #ifdef PY_2 if (!PyFloat_Check($input) && (SWIG_ConvertPtr($input, (void**)(&ptr), SWIGTYPE_p_SbTime, 0) == -1)) #else if (!PyFloat_Check($input) && (SWIG_ConvertPtr($input, (void**)(&ptr), $descriptor(SbTime *), 0) == -1)) #endif { $1 = 0; } } %typemap(in) SbTime & { if (PyFloat_Check($input)) { $1 = new SbTime(PyFloat_AsDouble($input)); } else { SbTime * tmp = NULL; $1 = new SbTime; #ifdef PY_2 SWIG_ConvertPtr($input, (void**)&tmp, SWIGTYPE_p_SbTime, 1); #else SWIG_ConvertPtr($input, (void**)&tmp, $descriptor(SbTime *), 1); #endif *$1 = *tmp; } } %typemap(freearg) SbTime & { if ($1) { delete $1; } } %typemap(in) FILE * { #ifdef PY_2 if (PyFile_Check($input)) { $1 = PyFile_AsFile($input); } #else if (PyObject_IsInstance($input, PyIOBase_TypeObj)) { int fd = PyObject_AsFileDescriptor($input); $1 = fdopen(fd, "w"); } #endif else { PyErr_SetString(PyExc_TypeError, "expected a file object."); } } %include Inventor/events/SoEvent.h %include Inventor/fields/SoField.h %include Inventor/SbString.h /* some ignores for missing COIN_DLL_API specifications */ %ignore cc_rbptree_init; %ignore cc_rbptree_clean; %ignore cc_rbptree_insert; %ignore cc_rbptree_remove; %ignore cc_rbptree_size; %ignore cc_rbptree_traverse; %ignore cc_rbptree_debug; %ignore so_plane_data::so_plane_data; %ignore SoGLRenderCache::SoGLRenderCache; %ignore SoGLRenderCache::open; %ignore SoGLRenderCache::close; %ignore SoGLRenderCache::call; %ignore SoGLRenderCache::getCacheContext; %ignore SoGLRenderCache::getPreLazyState; %ignore SoGLRenderCache::getPostLazyState; %ignore SoGLCacheList::SoGLCacheList; %ignore SoGLCacheList::~SoGLCacheList; %ignore SoGLCacheList::call; %ignore SoGLCacheList::open; %ignore SoGLCacheList::close; %ignore SoGLCacheList::invalidateAll; %ignore SoNormalBundle::SoNormalBundle; %ignore SoNormalBundle::~SoNormalBundle; %ignore SoNormalBundle::shouldGenerate; %ignore SoNormalBundle::initGenerator; %ignore SoNormalBundle::beginPolygon; %ignore SoNormalBundle::polygonVertex; %ignore SoNormalBundle::endPolygon; %ignore SoNormalBundle::triangle; %ignore SoNormalBundle::generate; %ignore SoNormalBundle::getGeneratedNormals; %ignore SoNormalBundle::getNumGeneratedNormals; %ignore SoNormalBundle::set; %ignore SoNormalBundle::get; %ignore SoNormalBundle::send; %ignore SoMultiTextureCoordinateElement::setFunction; %ignore SoGLMultiTextureCoordinateElement::setTexGen; pivy-0.6.5/NEWS0000644000175000017500000000265413606712377011767 0ustar kurtkurtNew in Pivy v0.5.0 (so far): * features: - purer and simpler OpenBSD'esque license - SIMVoleon support - Sc21 support - new contributed examples - out-of-the-box build support for SoQt on win32 - autocasting for SoSensor derived nodes - Python 2.5 support - PyQt4 support * bugfixes: - missing autocast invocation in SoCallbackActionPythonCB() for SoNode param - out parameter handling for SoCallbackAction::getMaterial() - proper handling of size[2] == 0 in SbImage::setValue(SbVec3s size,...) - callback handling for: + SoSensorManager::setChangedCallback() + SoSceneManager::setRenderCallback() - win32 build system fix: COIN3DDIR environment variable changed to COINDIR - pythonic SoFieldContainer::getFieldName() returning a PyString - SbMatrix.setValue() works again taking a ((ffff),(ffff),(ffff),(ffff)) - memleaks New in Pivy v0.3.0: * features: - SWIG 1.3.25 support - pivy installs now as Python package - SoPyScript node - numerous new test cases - improved basic type support - proper operator overloading handling - field = assignment operator support * bugfixes: - SoField::get() didn't return a string - no working embedded SoQtExaminerViewer example - import order of modules should not be significant - Mentor examples needs cleanup - removal of obsolete wrapping code - general code cleanup - autocasting of extension nodes to the first available parent node pivy-0.6.5/docs/0000755000175000017500000000000013606712377012211 5ustar kurtkurtpivy-0.6.5/docs/ChangeLog.20020000644000175000017500000010260513606712377014351 0ustar kurtkurt2002-08-24 02:33 tamer * Makefile, pivy.i, Inventor/Qt/SoQt.h, Inventor/Qt/SoQtCursor.h, examples/Mentor/python/02.1.HelloCone.py, examples/Mentor/python/02.2.EngineSpin.py, examples/Mentor/python/02.3.Trackball.py, examples/Mentor/python/02.4.Examiner.py, examples/Mentor/python/03.1.Molecule.py, examples/Mentor/python/03.2.Robot.py, examples/Mentor/python/04.1.Cameras.py, examples/Mentor/python/04.2.Lights.py, examples/Mentor/python/05.1.FaceSet.py, examples/Mentor/python/05.2.IndexedFaceSet.py, examples/Mentor/python/05.3.TriangleStripSet.py, examples/Mentor/python/05.4.QuadMesh.py, examples/Mentor/python/05.5.Binding.py, examples/Mentor/python/05.6.TransformOrdering.py, examples/Mentor/python/06.1.Text.py, examples/Mentor/python/06.2.Simple3DText.py, examples/Mentor/python/06.3.Complex3DText.py, examples/Mentor/python/07.1.BasicTexture.py, examples/Mentor/python/07.2.TextureCoordinates.py, examples/Mentor/python/07.3.TextureFunction.py, examples/Mentor/python/08.1.BSCurve.py, examples/Mentor/python/08.2.UniCurve.py, examples/Mentor/python/08.3.BezSurf.py, examples/Mentor/python/08.4.TrimSurf.py, examples/Mentor/python/09.1.Print.py, examples/Mentor/python/09.2.Texture.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/python/10.1.addEventCB.py, examples/Mentor/python/10.2.setEventCB.py, examples/Mentor/python/10.3and4.MotifList.py, examples/Mentor/python/10.5.SelectionCB.py, examples/Mentor/python/10.6.PickFilterTopLevel.py, examples/Mentor/python/10.7.PickFilterManip.py, examples/Mentor/python/10.8.PickFilterNodeKit.py, examples/Mentor/python/11.1.ReadFile.py, examples/Mentor/python/11.2.ReadString.py, examples/Mentor/python/12.1.FieldSensor.py, examples/Mentor/python/12.3.AlarmSensor.py, examples/Mentor/python/12.4.TimerSensor.py, examples/Mentor/python/13.1.GlobalFlds.py, examples/Mentor/python/13.2.ElapsedTime.py, examples/Mentor/python/13.3.TimeCounter.py, examples/Mentor/python/13.4.Gate.py, examples/Mentor/python/13.5.Boolean.py, examples/Mentor/python/13.6.Calculator.py, examples/Mentor/python/13.7.Rotor.py, examples/Mentor/python/13.8.Blinker.py, examples/Mentor/python/14.1.FrolickingWords.py, examples/Mentor/python/14.2.Editors.py, examples/Mentor/python/14.3.Balance.py, examples/Mentor/python/15.1.ConeRadius.py, examples/Mentor/python/15.2.SliderBox.py, examples/Mentor/python/15.3.AttachManip.py, examples/Mentor/python/15.4.Customize.py, examples/Mentor/python/16.1.Overlay.py, examples/Mentor/python/16.2.Callback.py, examples/Mentor/python/16.3.AttachEditor.py, examples/Mentor/python/16.4.OneWindow.py, examples/Mentor/python/16.5.Examiner.py, examples/Mentor/python/17.1.ColorIndex.py, examples/Mentor/python/17.2.GLCallback.py, fake_headers/qevent.h, fake_headers/qobject.h: SoQt is released as stable now. Therefore changed the Gui binding from SoGtk to SoQt. Tested with SoQt 1.0.1. 2002-07-19 05:37 tamer * pivy.i, Inventor/Gtk/SoGtkCursor.h: updated the source tree to work with the newest swig development version (1.3.13) and the newest cvs Coin3d SoGtk version. 2002-06-13 01:28 tamer * Makefile, pivy.i, Inventor/SbColor4f.h, Inventor/SbMatrix.h, Inventor/SbString.h, Inventor/SbTesselator.h, Inventor/SbVec2f.h, Inventor/SbVec2s.h, Inventor/SbVec3f.h, Inventor/SbVec4f.h, Inventor/Gtk/SoGtk.h, Inventor/Gtk/SoGtkCursor.h, Inventor/Gtk/SoGtkGraphEditor.h, Inventor/Gtk/SoGtkRenderArea.h, Inventor/Gtk/SoGtkRoster.h, Inventor/actions/SoCallbackAction.h, Inventor/draggers/SoDragger.h, Inventor/fields/SoFieldContainer.h, Inventor/fields/SoMFColor.h, Inventor/fields/SoMFFloat.h, Inventor/fields/SoMFInt32.h, Inventor/fields/SoMFString.h, Inventor/fields/SoMFVec2f.h, Inventor/fields/SoMFVec3f.h, Inventor/fields/SoMFVec4f.h, Inventor/fields/SoSFBool.h, Inventor/fields/SoSFEnum.h, Inventor/fields/SoSFFloat.h, Inventor/fields/SoSFInt32.h, Inventor/fields/SoSFName.h, Inventor/fields/SoSFRotation.h, Inventor/fields/SoSFShort.h, Inventor/fields/SoSFString.h, Inventor/fields/SoSFVec2f.h, Inventor/fields/SoSFVec3f.h, Inventor/fields/SoSFVec4f.h, Inventor/nodes/SoCallback.h, Inventor/nodes/SoEventCallback.h, Inventor/nodes/SoSelection.h, Inventor/sensors/SoSensor.h, examples/Mentor/python/12.2.NodeSensor.py, examples/Mentor/python/17.2.GLCallback.py: updated the source tree to work with the newest swig development version (1.3.12). some keywords changed and some functionality is in place now where workarounds were needed earlier in cvs versions of swig. I checked out the most recent SoGtk cvs version, included the newest headers from this tree and removed the now obsolete ones in the pivy Inventor/Gtk tree. fixed the getFieldName() issue in the SoFieldContainer class to return a tuple (SbBool, SbName) so that NodeSensors work properly now -> this fixed the 12.2.NodeSensor.py segfault. 2002-04-27 06:23 tamer * examples/Mentor/python/: 17.1.ColorIndex.py, 17.2.GLCallback.py, 17.3.GLFloor.py: updated GL Mentor examples so that they work with PyOpenGL. 2002-04-10 14:54 tamer * Inventor/fields/: SoMFColor.h, SoMFInt32.h, SoMFVec2f.h, SoMFVec3f.h, SoMFVec4f.h, SoSFRotation.h: added missing __call__ methods. 2002-04-10 14:36 tamer * Inventor/fields/: SoSFBool.h, SoSFInt32.h, SoSFRotation.h, SoSFVec2f.h, SoSFVec3f.h, SoSFVec4f.h: added __call__ methods to field classes. 2002-04-01 08:21 tamer * Inventor/SbViewVolume.h: added modified header file. 2002-04-01 08:20 tamer * pivy.i, Inventor/SbRotation.h, Inventor/SbTime.h, Inventor/SoOffscreenRenderer.h, Inventor/SoPath.h, Inventor/Gtk/SoGtk.h, Inventor/Gtk/SoGtkCursor.h, Inventor/Gtk/SoGtkRenderArea.h, Inventor/actions/SoCallbackAction.h, Inventor/draggers/SoDragger.h, Inventor/fields/SoField.h, Inventor/fields/SoMFColor.h, Inventor/fields/SoSFShort.h, Inventor/nodes/SoCallback.h, Inventor/nodes/SoCamera.h, Inventor/nodes/SoEventCallback.h, Inventor/nodes/SoSelection.h, Inventor/sensors/SoAlarmSensor.h, Inventor/sensors/SoDataSensor.h, Inventor/sensors/SoDelayQueueSensor.h, Inventor/sensors/SoFieldSensor.h, Inventor/sensors/SoIdleSensor.h, Inventor/sensors/SoNodeSensor.h, Inventor/sensors/SoOneShotSensor.h, Inventor/sensors/SoPathSensor.h, Inventor/sensors/SoSensor.h, Inventor/sensors/SoTimerQueueSensor.h, Inventor/sensors/SoTimerSensor.h, examples/Mentor/python/09.1.Print.py, examples/Mentor/python/09.2.Texture.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/python/09.5.GenSph.py, examples/Mentor/python/10.1.addEventCB.py, examples/Mentor/python/10.2.setEventCB.py, examples/Mentor/python/10.3and4.MotifList.py, examples/Mentor/python/10.5.SelectionCB.py, examples/Mentor/python/10.6.PickFilterTopLevel.py, examples/Mentor/python/10.7.PickFilterManip.py, examples/Mentor/python/10.8.PickFilterNodeKit.py, examples/Mentor/python/11.1.ReadFile.py, examples/Mentor/python/11.2.ReadString.py, examples/Mentor/python/12.1.FieldSensor.py, examples/Mentor/python/12.2.NodeSensor.py, examples/Mentor/python/12.3.AlarmSensor.py, examples/Mentor/python/12.4.TimerSensor.py, examples/Mentor/python/13.1.GlobalFlds.py, examples/Mentor/python/13.2.ElapsedTime.py, examples/Mentor/python/13.3.TimeCounter.py, examples/Mentor/python/13.4.Gate.py, examples/Mentor/python/13.5.Boolean.py, examples/Mentor/python/13.6.Calculator.py, examples/Mentor/python/13.7.Rotor.py, examples/Mentor/python/13.8.Blinker.py, examples/Mentor/python/14.1.FrolickingWords.py, examples/Mentor/python/14.2.Editors.py, examples/Mentor/python/14.3.Balance.py, examples/Mentor/python/15.1.ConeRadius.py, examples/Mentor/python/15.2.SliderBox.py, examples/Mentor/python/15.3.AttachManip.py, examples/Mentor/python/15.4.Customize.py, examples/Mentor/python/16.1.Overlay.py, examples/Mentor/python/16.2.Callback.py, examples/Mentor/python/16.3.AttachEditor.py, examples/Mentor/python/16.4.OneWindow.py, examples/Mentor/python/16.5.Examiner.py, examples/Mentor/python/17.1.ColorIndex.py, examples/Mentor/python/17.2.GLCallback.py, examples/Mentor/python/17.3.GLFloor.py, examples/Mentor/python/bookshelf.iv, examples/Mentor/python/desk.iv, examples/Mentor/python/dogDish.iv, examples/Mentor/python/duck.iv, examples/Mentor/python/eatAtJosies.iv, examples/Mentor/python/flower.iv, examples/Mentor/python/flowerPath.iv, examples/Mentor/python/luxo.iv, examples/Mentor/python/windmillTower.iv, examples/Mentor/python/windmillVanes.iv: converted all Inventor Mentor book examples to python as far as possible. added therefore all fixed coin3d header files. 2002-03-28 06:07 tamer * Makefile, Inventor/actions/SoAction.h, Inventor/actions/SoWriteAction.h, Inventor/events/SoEvent.h, Inventor/nodes/SoEventCallback.h, examples/Mentor/python/09.4.PickAction.py: FINALLY!!! fixed this damn segmentation fault in the callback handling, which nearly drove me nuts! wuuaaaaaaaaaaaaah!!!! i was capable of looking in the wrong place for nearly a weeeeeek!!!! aaaaaaaaaaah!!! and then it turns out to be a nasty typo! even more aaaaaaaaaaaaaah!!!! yaaaaaaaaaaaaaaah!!!! heiaaaaaaeeeeeeeeeeeeeh!!!! the most exciting iiiiiiiiaaaaaaaeeeeeeehhh!!!! but now i know swig, reeeaaally reeeeeaaaaally know it and every curse on this planet! *@#$)(*!@#$!!!* ~~~ NO SURRENDER :: NO GIVING UP ~~~ ha!!!! 2002-03-25 19:41 tamer * LICENSE, pivy.i, Inventor/nodes/SoEventCallback.h, Inventor/nodes/SoGroup.h, examples/Mentor/python/03.3.Naming.py, examples/Mentor/python/05.5.Binding.py, examples/Mentor/python/09.4.PickAction.py: fixed type casting and inventor mentor examples relying on it. 2002-03-21 10:09 tamer * pivy.i, Inventor/events/SoEvent.h, Inventor/nodes/SoEventCallback.h, examples/Mentor/python/02.1.HelloCone.py, examples/Mentor/python/09.2.Texture.py, examples/Mentor/python/09.3.Search.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/python/09.5.GenSph.py, examples/Mentor/python/bird.iv, examples/Mentor/python/jumpyMan.iv, examples/Mentor/python/star.iv: new inventor mentor examples pythonized. start of callback handling. (works but needs more work as it lets apps segfault under certain circumstances) 2002-03-19 17:24 tamer * Inventor/nodes/SoEventCallback.h, examples/Mentor/python/08.1.BSCurve.py, examples/Mentor/python/08.2.UniCurve.py, examples/Mentor/python/08.3.BezSurf.py, examples/Mentor/python/08.4.TrimSurf.py, examples/Mentor/python/09.1.Print.py, examples/Mentor/python/diamondRug.rgb: added new pythonized Inventor Mentor examples and necessary headers with the glue code. 2002-03-19 07:23 tamer * Inventor/SbRotation.h, Inventor/SbVec3f.h, Inventor/SoInput.h, Inventor/fields/SoMFFloat.h, Inventor/fields/SoMFString.h, Inventor/fields/SoSFRotation.h, examples/Mentor/python/06.2.Simple3DText.py, examples/Mentor/python/06.3.Complex3DText.py, examples/Mentor/python/07.1.BasicTexture.py, examples/Mentor/python/07.2.TextureCoordinates.py, examples/Mentor/python/07.3.TextureFunction.py, examples/Mentor/python/08.1.BSCurve.py, examples/Mentor/python/brick.1.rgb, examples/Mentor/python/oak.rgb, examples/Mentor/python/sillyFace.rgb: new Inventor Mentor examples pythonized. added headers with necessary modifications and glue code. 2002-03-19 01:43 tamer * pivy.i, Inventor/SbString.h, Inventor/fields/SoMFColor.h, Inventor/fields/SoMFInt32.h, Inventor/fields/SoMFVec2f.h, Inventor/fields/SoMFVec3f.h, Inventor/fields/SoMFVec4f.h, Inventor/fields/SoSFInt32.h, Inventor/fields/SoSFName.h, Inventor/fields/SoSFString.h, examples/Mentor/python/05.1.FaceSet.py, examples/Mentor/python/05.2.IndexedFaceSet.py, examples/Mentor/python/05.3.TriangleStripSet.py, examples/Mentor/python/05.4.QuadMesh.py, examples/Mentor/python/05.5.Binding.py, examples/Mentor/python/05.6.TransformOrdering.py, examples/Mentor/python/06.1.Text.py, examples/Mentor/python/06.2.Simple3DText.py, examples/Mentor/python/globe.rgb, examples/Mentor/python/temple.iv: new Inventor Mentor samples pythonized. added correspondig files and changed headers with glue code. 2002-03-18 07:04 tamer * Inventor/fields/SoMFVec3f.h, examples/Mentor/python/05.1.FaceSet.py: fixed setValues() in SoMFVec3f.h. 2002-03-18 06:25 tamer * Inventor/SbVec2f.h, Inventor/SbVec3f.h, Inventor/SbVec4f.h, Inventor/SbViewportRegion.h, Inventor/fields/SoMFColor.h, Inventor/fields/SoMFVec2f.h, Inventor/fields/SoMFVec3f.h, Inventor/fields/SoMFVec4f.h, examples/Mentor/python/03.1.Molecule.py, examples/Mentor/python/03.2.Robot.py, examples/Mentor/python/04.1.Cameras.py, examples/Mentor/python/04.2.Lights.py, examples/Mentor/python/05.1.FaceSet.py, examples/Mentor/python/parkbench.iv: new Mentor Inventor examples transformed to python -> added necessary files with appropriate glue code. added workaround with %typemap(out) for the %apply directive which got not applied on getValue(fff[f]) for SbVec3f.h and SbVec4f.h. (don't have a clue why it works for SbVec2f.h, though. bug(tm) in swig?) listening to "Not an Addict"! "Breathing iiiiin and breathing ooooooout..." 2002-03-16 05:27 tamer * Inventor/SbName.h: added fixed SbName.h. 2002-03-16 05:26 tamer * pivy.i, Inventor/fields/SoMFFloat.h, Inventor/fields/SoSFFloat.h, Inventor/fields/SoSFVec2f.h, Inventor/fields/SoSFVec3f.h, Inventor/fields/SoSFVec4f.h, examples/Mentor/python/01.1.Windmill.iv, examples/Mentor/python/03.1.Molecule.py, examples/Mentor/python/03.2.Robot.py, examples/Mentor/python/03.3.Naming.py, examples/Mentor/python/04.1.Cameras.py, examples/Mentor/python/04.2.Lights.py, examples/Mentor/python/05.1.FaceSet.py, examples/Mentor/python/05.2.IndexedFaceSet.py, examples/Mentor/python/05.3.TriangleStripSet.py, examples/Mentor/python/05.4.QuadMesh.py, examples/Mentor/python/05.5.Binding.py, examples/Mentor/python/05.6.TransformOrdering.py, examples/Mentor/python/06.1.Text.py, examples/Mentor/python/06.2.Simple3DText.py, examples/Mentor/python/06.3.Complex3DText.py, examples/Mentor/python/07.1.BasicTexture.py, examples/Mentor/python/07.2.TextureCoordinates.py, examples/Mentor/python/07.3.TextureFunction.py, examples/Mentor/python/08.1.BSCurve.py, examples/Mentor/python/08.2.UniCurve.py, examples/Mentor/python/08.3.BezSurf.py, examples/Mentor/python/08.4.TrimSurf.py, examples/Mentor/python/09.1.Print.py, examples/Mentor/python/09.2.Texture.py, examples/Mentor/python/09.3.Search.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/python/09.5.GenSph.py, examples/Mentor/python/10.1.addEventCB.py, examples/Mentor/python/10.2.setEventCB.py, examples/Mentor/python/10.3and4.MotifList.py, examples/Mentor/python/10.5.SelectionCB.py, examples/Mentor/python/10.6.PickFilterTopLevel.py, examples/Mentor/python/10.7.PickFilterManip.py, examples/Mentor/python/10.8.PickFilterNodeKit.py, examples/Mentor/python/11.1.ReadFile.py, examples/Mentor/python/11.2.ReadString.py, examples/Mentor/python/12.1.FieldSensor.py, examples/Mentor/python/12.2.NodeSensor.py, examples/Mentor/python/12.3.AlarmSensor.py, examples/Mentor/python/12.4.TimerSensor.py, examples/Mentor/python/13.1.GlobalFlds.py, examples/Mentor/python/13.2.ElapsedTime.py, examples/Mentor/python/13.3.TimeCounter.py, examples/Mentor/python/13.4.Gate.py, examples/Mentor/python/13.5.Boolean.py, examples/Mentor/python/13.6.Calculator.py, examples/Mentor/python/13.7.Rotor.py, examples/Mentor/python/13.8.Blinker.py, examples/Mentor/python/14.1.FrolickingWords.py, examples/Mentor/python/14.2.Editors.py, examples/Mentor/python/14.3.Balance.py, examples/Mentor/python/15.1.ConeRadius.py, examples/Mentor/python/15.2.SliderBox.py, examples/Mentor/python/15.3.AttachManip.py, examples/Mentor/python/15.4.Customize.py, examples/Mentor/python/16.1.Overlay.py, examples/Mentor/python/16.2.Callback.py, examples/Mentor/python/16.3.AttachEditor.py, examples/Mentor/python/16.4.OneWindow.py, examples/Mentor/python/16.5.Examiner.py, examples/Mentor/python/17.1.ColorIndex.py, examples/Mentor/python/17.2.GLCallback.py, examples/Mentor/python/17.3.GLFloor.py: fixed and wrote glue code for some headers to get the next 3 (pivy) Mentor working. added the rest of the C++ examples although they are still not rewritten to python. 2002-03-15 08:00 tamer * examples/Mentor/python/: 02.3.Trackball.py, 02.4.Examiner.py: I couldn't stop and pivied another 2 examples. it works so seamlessly that I am starting to get frightened... *huh* 2002-03-15 07:46 tamer * examples/Mentor/python/: 02.1.HelloCone.py, 02.2.EngineSpin.py: added the first 2 completely pivied Open Inventor Mentor examples. 2002-03-15 07:43 tamer * Makefile, Inventor/SbColor.h, Inventor/SbColor4f.h, Inventor/SbVec3f.h, Inventor/fields/SoMFColor.h, Inventor/fields/SoSFColor.h, Inventor/fields/SoSFEnum.h: for getting the first 2 examples of the Inventor Mentor book to run as closely to the C++ syntax I wrote glue code for as many headers as necessary. as there is no operator= in python I added a __call__ method to SoSFEnum to compensate for it. a initializer might now look like this: myRotXYZ.axis(SoRotationXYZ.X) # rotate around X axis or myRotXYZ.axis.setValue(SoRotationXYZ.X) 2002-03-15 03:31 tamer * Inventor/: SbDict.h, SbVec2f.h, SbVec2s.h, SbVec3f.h, SbVec4f.h: finished glue code for different basic types. (untested, just compiles...) 2002-03-15 01:31 tamer * Inventor/: SbMatrix.h, SbVec2f.h: finally fixed the SbMatrix swig cast problem, which resulted in wrong results in the matrix itself. an unnecessary (SbMat const &) cast was added by swig's code generator, which nearly drove me nuts and was responsible for the ugliest workaround in computing history ever. abused %typemap(argout) to fix it which now produces 2 calls to the same method or constructor once with the wrong cast and afterwards without the cast. *shrug* maybe i shouldn't blame swig alone, but the guy who thought it would be enough to have a SbMatrix::setValue(const SbMat & m) instead of a non bloody from hell C++ world crisis generating method like SbMatrix::setValue(const SbMat * m). grrrr!!! !@#&*(@#$^*&%^*&%^!!! aaaaahhhhh!!!! 2002-03-14 07:17 tamer * Makefile, Inventor/SbMatrix.h, Inventor/SbVec2f.h: typemapped SbVec2f and fixed SbMatrix. 2002-03-14 00:00 tamer * Makefile, pivy.i, Inventor/SbMatrix.h: fixed SbMatrix constructor overloading. 2002-03-12 23:15 tamer * AUTHORS, Makefile, pivy.i, Inventor/SbDict.h, Inventor/SbMatrix.h, Inventor/SbOctTree.h, Inventor/SbTesselator.h, Inventor/SbVec2f.h, Inventor/SbVec2s.h, Inventor/SbVec3f.h, Inventor/SbVec4f.h, Inventor/SoInput.h, Inventor/SoType.h, Inventor/Gtk/SoGtkCursor.h, Inventor/Gtk/SoGtkGraphEditor.h, Inventor/Gtk/SoGtkRoster.h, Inventor/engines/SoInterpolate.h, Inventor/lists/SbIntList.h, Inventor/lists/SbPList.h, Inventor/lists/SbStringList.h, Inventor/lists/SbVec3fList.h, Inventor/lists/SoAuditorList.h, Inventor/lists/SoDetailList.h, Inventor/lists/SoEngineOutputList.h, Inventor/lists/SoFieldList.h, Inventor/lists/SoPickedPointList.h, Inventor/lists/SoTypeList.h, Inventor/lists/SoVRMLInterpOutputList.h, Inventor/misc/SoNotification.h, fake_headers/assert.h, fake_headers/inttypes.h, fake_headers/math.h, fake_headers/stdarg.h, fake_headers/stddef.h, fake_headers/stdio.h, fake_headers/stdlib.h, fake_headers/time.h, fake_headers/Inventor/bundles/SoBundle.h, fake_headers/Inventor/bundles/SoMaterialBundle.h, fake_headers/Inventor/bundles/SoTextureCoordinateBundle.h, fake_headers/Inventor/caches/SoBoundingBoxCache.h, fake_headers/Inventor/caches/SoCache.h, fake_headers/Inventor/caches/SoConvexDataCache.h, fake_headers/Inventor/caches/SoGLCacheList.h, fake_headers/Inventor/caches/SoGLRenderCache.h, fake_headers/Inventor/caches/SoNormalCache.h, fake_headers/Inventor/caches/SoTextureCoordinateCache.h, fake_headers/Inventor/elements/SoAccumulatedElement.h, fake_headers/Inventor/elements/SoAmbientColorElement.h, fake_headers/Inventor/elements/SoAnnoText3CharOrientElement.h, fake_headers/Inventor/elements/SoAnnoText3FontSizeHintElement.h, fake_headers/Inventor/elements/SoAnnoText3RenderPrintElement.h, fake_headers/Inventor/elements/SoBBoxModelMatrixElement.h, fake_headers/Inventor/elements/SoCacheElement.h, fake_headers/Inventor/elements/SoClipPlaneElement.h, fake_headers/Inventor/elements/SoComplexityElement.h, fake_headers/Inventor/elements/SoComplexityTypeElement.h, fake_headers/Inventor/elements/SoCoordinateElement.h, fake_headers/Inventor/elements/SoCreaseAngleElement.h, fake_headers/Inventor/elements/SoCullElement.h, fake_headers/Inventor/elements/SoDecimationPercentageElement.h, fake_headers/Inventor/elements/SoDecimationTypeElement.h, fake_headers/Inventor/elements/SoDiffuseColorElement.h, fake_headers/Inventor/elements/SoDrawStyleElement.h, fake_headers/Inventor/elements/SoElement.h, fake_headers/Inventor/elements/SoElements.h, fake_headers/Inventor/elements/SoEmissiveColorElement.h, fake_headers/Inventor/elements/SoEnvironmentElement.h, fake_headers/Inventor/elements/SoFloatElement.h, fake_headers/Inventor/elements/SoFocalDistanceElement.h, fake_headers/Inventor/elements/SoFontNameElement.h, fake_headers/Inventor/elements/SoFontSizeElement.h, fake_headers/Inventor/elements/SoGLAmbientColorElement.h, fake_headers/Inventor/elements/SoGLCacheContextElement.h, fake_headers/Inventor/elements/SoGLClipPlaneElement.h, fake_headers/Inventor/elements/SoGLColorIndexElement.h, fake_headers/Inventor/elements/SoGLCoordinateElement.h, fake_headers/Inventor/elements/SoGLDiffuseColorElement.h, fake_headers/Inventor/elements/SoGLDrawStyleElement.h, fake_headers/Inventor/elements/SoGLEmissiveColorElement.h, fake_headers/Inventor/elements/SoGLEnvironmentElement.h, fake_headers/Inventor/elements/SoGLLazyElement.h, fake_headers/Inventor/elements/SoGLLightIdElement.h, fake_headers/Inventor/elements/SoGLLightModelElement.h, fake_headers/Inventor/elements/SoGLLinePatternElement.h, fake_headers/Inventor/elements/SoGLLineWidthElement.h, fake_headers/Inventor/elements/SoGLModelMatrixElement.h, fake_headers/Inventor/elements/SoGLNormalElement.h, fake_headers/Inventor/elements/SoGLNormalizeElement.h, fake_headers/Inventor/elements/SoGLPointSizeElement.h, fake_headers/Inventor/elements/SoGLPolygonOffsetElement.h, fake_headers/Inventor/elements/SoGLPolygonStippleElement.h, fake_headers/Inventor/elements/SoGLProjectionMatrixElement.h, fake_headers/Inventor/elements/SoGLRenderPassElement.h, fake_headers/Inventor/elements/SoGLShadeModelElement.h, fake_headers/Inventor/elements/SoGLShapeHintsElement.h, fake_headers/Inventor/elements/SoGLShininessElement.h, fake_headers/Inventor/elements/SoGLSpecularColorElement.h, fake_headers/Inventor/elements/SoGLTextureCoordinateElement.h, fake_headers/Inventor/elements/SoGLTextureEnabledElement.h, fake_headers/Inventor/elements/SoGLTextureImageElement.h, fake_headers/Inventor/elements/SoGLTextureMatrixElement.h, fake_headers/Inventor/elements/SoGLUpdateAreaElement.h, fake_headers/Inventor/elements/SoGLViewingMatrixElement.h, fake_headers/Inventor/elements/SoGLViewportRegionElement.h, fake_headers/Inventor/elements/SoInt32Element.h, fake_headers/Inventor/elements/SoLazyElement.h, fake_headers/Inventor/elements/SoLightAttenuationElement.h, fake_headers/Inventor/elements/SoLightElement.h, fake_headers/Inventor/elements/SoLightModelElement.h, fake_headers/Inventor/elements/SoLinePatternElement.h, fake_headers/Inventor/elements/SoLineWidthElement.h, fake_headers/Inventor/elements/SoLocalBBoxMatrixElement.h, fake_headers/Inventor/elements/SoLongElement.h, fake_headers/Inventor/elements/SoMaterialBindingElement.h, fake_headers/Inventor/elements/SoModelMatrixElement.h, fake_headers/Inventor/elements/SoNormalBindingElement.h, fake_headers/Inventor/elements/SoNormalElement.h, fake_headers/Inventor/elements/SoOverrideElement.h, fake_headers/Inventor/elements/SoPickRayElement.h, fake_headers/Inventor/elements/SoPickStyleElement.h, fake_headers/Inventor/elements/SoPointSizeElement.h, fake_headers/Inventor/elements/SoPolygonOffsetElement.h, fake_headers/Inventor/elements/SoProfileCoordinateElement.h, fake_headers/Inventor/elements/SoProfileElement.h, fake_headers/Inventor/elements/SoProjectionMatrixElement.h, fake_headers/Inventor/elements/SoReplacedElement.h, fake_headers/Inventor/elements/SoShapeHintsElement.h, fake_headers/Inventor/elements/SoShapeStyleElement.h, fake_headers/Inventor/elements/SoShininessElement.h, fake_headers/Inventor/elements/SoSpecularColorElement.h, fake_headers/Inventor/elements/SoSubElement.h, fake_headers/Inventor/elements/SoSwitchElement.h, fake_headers/Inventor/elements/SoTextOutlineEnabledElement.h, fake_headers/Inventor/elements/SoTextureCoordinateBindingElement.h, fake_headers/Inventor/elements/SoTextureCoordinateElement.h, fake_headers/Inventor/elements/SoTextureImageElement.h, fake_headers/Inventor/elements/SoTextureMatrixElement.h, fake_headers/Inventor/elements/SoTextureOverrideElement.h, fake_headers/Inventor/elements/SoTextureQualityElement.h, fake_headers/Inventor/elements/SoTransparencyElement.h, fake_headers/Inventor/elements/SoUnitsElement.h, fake_headers/Inventor/elements/SoViewVolumeElement.h, fake_headers/Inventor/elements/SoViewingMatrixElement.h, fake_headers/Inventor/elements/SoViewportRegionElement.h, fake_headers/Inventor/elements/SoWindowElement.h, fake_headers/Inventor/projectors/SbCylinderPlaneProjector.h, fake_headers/Inventor/projectors/SbCylinderProjector.h, fake_headers/Inventor/projectors/SbCylinderSectionProjector.h, fake_headers/Inventor/projectors/SbCylinderSheetProjector.h, fake_headers/Inventor/projectors/SbLineProjector.h, fake_headers/Inventor/projectors/SbPlaneProjector.h, fake_headers/Inventor/projectors/SbProjector.h, fake_headers/Inventor/projectors/SbProjectors.h, fake_headers/Inventor/projectors/SbSpherePlaneProjector.h, fake_headers/Inventor/projectors/SbSphereProjector.h, fake_headers/Inventor/projectors/SbSphereSectionProjector.h, fake_headers/Inventor/projectors/SbSphereSheetProjector.h, fake_headers/gtk/gtk.h, fake_headers/sys/time.h, fake_headers/sys/types.h: Initial revision 2002-03-12 23:15 tamer * AUTHORS, Makefile, pivy.i, Inventor/SbDict.h, Inventor/SbMatrix.h, Inventor/SbOctTree.h, Inventor/SbTesselator.h, Inventor/SbVec2f.h, Inventor/SbVec2s.h, Inventor/SbVec3f.h, Inventor/SbVec4f.h, Inventor/SoInput.h, Inventor/SoType.h, Inventor/Gtk/SoGtkCursor.h, Inventor/Gtk/SoGtkGraphEditor.h, Inventor/Gtk/SoGtkRoster.h, Inventor/engines/SoInterpolate.h, Inventor/lists/SbIntList.h, Inventor/lists/SbPList.h, Inventor/lists/SbStringList.h, Inventor/lists/SbVec3fList.h, Inventor/lists/SoAuditorList.h, Inventor/lists/SoDetailList.h, Inventor/lists/SoEngineOutputList.h, Inventor/lists/SoFieldList.h, Inventor/lists/SoPickedPointList.h, Inventor/lists/SoTypeList.h, Inventor/lists/SoVRMLInterpOutputList.h, Inventor/misc/SoNotification.h, fake_headers/assert.h, fake_headers/inttypes.h, fake_headers/math.h, fake_headers/stdarg.h, fake_headers/stddef.h, fake_headers/stdio.h, fake_headers/stdlib.h, fake_headers/time.h, fake_headers/Inventor/bundles/SoBundle.h, fake_headers/Inventor/bundles/SoMaterialBundle.h, fake_headers/Inventor/bundles/SoTextureCoordinateBundle.h, fake_headers/Inventor/caches/SoBoundingBoxCache.h, fake_headers/Inventor/caches/SoCache.h, fake_headers/Inventor/caches/SoConvexDataCache.h, fake_headers/Inventor/caches/SoGLCacheList.h, fake_headers/Inventor/caches/SoGLRenderCache.h, fake_headers/Inventor/caches/SoNormalCache.h, fake_headers/Inventor/caches/SoTextureCoordinateCache.h, fake_headers/Inventor/elements/SoAccumulatedElement.h, fake_headers/Inventor/elements/SoAmbientColorElement.h, fake_headers/Inventor/elements/SoAnnoText3CharOrientElement.h, fake_headers/Inventor/elements/SoAnnoText3FontSizeHintElement.h, fake_headers/Inventor/elements/SoAnnoText3RenderPrintElement.h, fake_headers/Inventor/elements/SoBBoxModelMatrixElement.h, fake_headers/Inventor/elements/SoCacheElement.h, fake_headers/Inventor/elements/SoClipPlaneElement.h, fake_headers/Inventor/elements/SoComplexityElement.h, fake_headers/Inventor/elements/SoComplexityTypeElement.h, fake_headers/Inventor/elements/SoCoordinateElement.h, fake_headers/Inventor/elements/SoCreaseAngleElement.h, fake_headers/Inventor/elements/SoCullElement.h, fake_headers/Inventor/elements/SoDecimationPercentageElement.h, fake_headers/Inventor/elements/SoDecimationTypeElement.h, fake_headers/Inventor/elements/SoDiffuseColorElement.h, fake_headers/Inventor/elements/SoDrawStyleElement.h, fake_headers/Inventor/elements/SoElement.h, fake_headers/Inventor/elements/SoElements.h, fake_headers/Inventor/elements/SoEmissiveColorElement.h, fake_headers/Inventor/elements/SoEnvironmentElement.h, fake_headers/Inventor/elements/SoFloatElement.h, fake_headers/Inventor/elements/SoFocalDistanceElement.h, fake_headers/Inventor/elements/SoFontNameElement.h, fake_headers/Inventor/elements/SoFontSizeElement.h, fake_headers/Inventor/elements/SoGLAmbientColorElement.h, fake_headers/Inventor/elements/SoGLCacheContextElement.h, fake_headers/Inventor/elements/SoGLClipPlaneElement.h, fake_headers/Inventor/elements/SoGLColorIndexElement.h, fake_headers/Inventor/elements/SoGLCoordinateElement.h, fake_headers/Inventor/elements/SoGLDiffuseColorElement.h, fake_headers/Inventor/elements/SoGLDrawStyleElement.h, fake_headers/Inventor/elements/SoGLEmissiveColorElement.h, fake_headers/Inventor/elements/SoGLEnvironmentElement.h, fake_headers/Inventor/elements/SoGLLazyElement.h, fake_headers/Inventor/elements/SoGLLightIdElement.h, fake_headers/Inventor/elements/SoGLLightModelElement.h, fake_headers/Inventor/elements/SoGLLinePatternElement.h, fake_headers/Inventor/elements/SoGLLineWidthElement.h, fake_headers/Inventor/elements/SoGLModelMatrixElement.h, fake_headers/Inventor/elements/SoGLNormalElement.h, fake_headers/Inventor/elements/SoGLNormalizeElement.h, fake_headers/Inventor/elements/SoGLPointSizeElement.h, fake_headers/Inventor/elements/SoGLPolygonOffsetElement.h, fake_headers/Inventor/elements/SoGLPolygonStippleElement.h, fake_headers/Inventor/elements/SoGLProjectionMatrixElement.h, fake_headers/Inventor/elements/SoGLRenderPassElement.h, fake_headers/Inventor/elements/SoGLShadeModelElement.h, fake_headers/Inventor/elements/SoGLShapeHintsElement.h, fake_headers/Inventor/elements/SoGLShininessElement.h, fake_headers/Inventor/elements/SoGLSpecularColorElement.h, fake_headers/Inventor/elements/SoGLTextureCoordinateElement.h, fake_headers/Inventor/elements/SoGLTextureEnabledElement.h, fake_headers/Inventor/elements/SoGLTextureImageElement.h, fake_headers/Inventor/elements/SoGLTextureMatrixElement.h, fake_headers/Inventor/elements/SoGLUpdateAreaElement.h, fake_headers/Inventor/elements/SoGLViewingMatrixElement.h, fake_headers/Inventor/elements/SoGLViewportRegionElement.h, fake_headers/Inventor/elements/SoInt32Element.h, fake_headers/Inventor/elements/SoLazyElement.h, fake_headers/Inventor/elements/SoLightAttenuationElement.h, fake_headers/Inventor/elements/SoLightElement.h, fake_headers/Inventor/elements/SoLightModelElement.h, fake_headers/Inventor/elements/SoLinePatternElement.h, fake_headers/Inventor/elements/SoLineWidthElement.h, fake_headers/Inventor/elements/SoLocalBBoxMatrixElement.h, fake_headers/Inventor/elements/SoLongElement.h, fake_headers/Inventor/elements/SoMaterialBindingElement.h, fake_headers/Inventor/elements/SoModelMatrixElement.h, fake_headers/Inventor/elements/SoNormalBindingElement.h, fake_headers/Inventor/elements/SoNormalElement.h, fake_headers/Inventor/elements/SoOverrideElement.h, fake_headers/Inventor/elements/SoPickRayElement.h, fake_headers/Inventor/elements/SoPickStyleElement.h, fake_headers/Inventor/elements/SoPointSizeElement.h, fake_headers/Inventor/elements/SoPolygonOffsetElement.h, fake_headers/Inventor/elements/SoProfileCoordinateElement.h, fake_headers/Inventor/elements/SoProfileElement.h, fake_headers/Inventor/elements/SoProjectionMatrixElement.h, fake_headers/Inventor/elements/SoReplacedElement.h, fake_headers/Inventor/elements/SoShapeHintsElement.h, fake_headers/Inventor/elements/SoShapeStyleElement.h, fake_headers/Inventor/elements/SoShininessElement.h, fake_headers/Inventor/elements/SoSpecularColorElement.h, fake_headers/Inventor/elements/SoSubElement.h, fake_headers/Inventor/elements/SoSwitchElement.h, fake_headers/Inventor/elements/SoTextOutlineEnabledElement.h, fake_headers/Inventor/elements/SoTextureCoordinateBindingElement.h, fake_headers/Inventor/elements/SoTextureCoordinateElement.h, fake_headers/Inventor/elements/SoTextureImageElement.h, fake_headers/Inventor/elements/SoTextureMatrixElement.h, fake_headers/Inventor/elements/SoTextureOverrideElement.h, fake_headers/Inventor/elements/SoTextureQualityElement.h, fake_headers/Inventor/elements/SoTransparencyElement.h, fake_headers/Inventor/elements/SoUnitsElement.h, fake_headers/Inventor/elements/SoViewVolumeElement.h, fake_headers/Inventor/elements/SoViewingMatrixElement.h, fake_headers/Inventor/elements/SoViewportRegionElement.h, fake_headers/Inventor/elements/SoWindowElement.h, fake_headers/Inventor/projectors/SbCylinderPlaneProjector.h, fake_headers/Inventor/projectors/SbCylinderProjector.h, fake_headers/Inventor/projectors/SbCylinderSectionProjector.h, fake_headers/Inventor/projectors/SbCylinderSheetProjector.h, fake_headers/Inventor/projectors/SbLineProjector.h, fake_headers/Inventor/projectors/SbPlaneProjector.h, fake_headers/Inventor/projectors/SbProjector.h, fake_headers/Inventor/projectors/SbProjectors.h, fake_headers/Inventor/projectors/SbSpherePlaneProjector.h, fake_headers/Inventor/projectors/SbSphereProjector.h, fake_headers/Inventor/projectors/SbSphereSectionProjector.h, fake_headers/Inventor/projectors/SbSphereSheetProjector.h, fake_headers/gtk/gtk.h, fake_headers/sys/time.h, fake_headers/sys/types.h: created CVS tree pivy-0.6.5/docs/license.template0000644000175000017500000000402413606712377015370 0ustar kurtkurtBelow are example licenses to be used for new code in Pivy, modeled after the OpenBSD license (which again is modeled after the ISC license). It is important to specify the year of the copyright. Additional years should be separated by a comma, e.g. Copyright (c) 2003, 2004 or given as an interval separated by a dash, e.g. Copyright (c) 2002-2006 If you add extra text to the body of the license, be careful not to add further restrictions. +++ C/C++ code +++ /* * Copyright (c) CCYY YOUR NAME HERE * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +++ Python code +++ ### # Copyright (c) CCYY YOUR NAME HERE # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # pivy-0.6.5/docs/ChangeLog.20050000644000175000017500000014010513606712377014351 0ustar kurtkurt2005-12-26 18:27:29 - r561 - tamer * examples/SoPyScript/SConstruct, SoPyScript/SConstruct, examples/extend/SConstruct: s/COIN3DDIR/COINDIR/ 2005-12-21 22:19:54 - r559 - tamer * NEWS: update on correct windows environment variable. 2005-12-21 22:16:03 - r558 - tamer * setup.py: s/COIN3DDIR/COINDIR/ after checking back with Lars. (reported by Michael Zimmermann) 2005-12-20 20:54:07 - r556 - tamer * setup.py, NEWS: added Windows SoQt build support. 2005-12-19 17:35:40 - r554 - tamer * THANKS: added Michael Zimmermann. 2005-11-16 21:18:59 - r552 - tamer * examples/extend/shapescale.i: added undef's needed for windows. reported by Frode ?ijord. 2005-11-16 21:15:18 - r551 - tamer * Inventor/sensors/SoSensorManager.i: added handling for SoSensorManager::setChangedCallback(). reported by Peder Blekken. 2005-11-14 09:56:50 - r549 - tamer * Inventor/SbImage.i: correct type in exception message. 2005-11-14 09:55:37 - r548 - tamer * fake_headers/sys/unistd.h, fake_headers/stdint.h: added fake headers for stdint.h and sys/unistd.h 2005-11-14 09:55:05 - r547 - tamer * THANKS: added Frode ?ijord. 2005-11-14 09:54:22 - r546 - tamer * Inventor/SoSceneManager.i: added handling for SoSceneManager::setRenderCallback(). reported by Frode ?ijord. 2005-10-19 03:29:40 - r544 - tamer * pivy/__init__.py, pivy/gui/__init__.py, examples/extend/shapescale.i: replaced old license header with new one. 2005-10-19 03:28:27 - r543 - tamer * pivy/sogui.py: cleanup: inject the proxy instances to the global module dict in one place instead of having to define them in 3 different places. reported by Terry Jones. 2005-10-07 03:28:58 - r541 - kyrah * packaging/macosx/Pivy.pkg/Contents/Resources/English.lproj/Installatio nCheck.strings, packaging/macosx/resources/InstallationCheck, packaging/macosx/Pivy.pkg/Contents/Resources/InstallationCheck: Speaking of the Lady... 2005-10-07 02:52:39 - r540 - kyrah * packaging/macosx/resources/InstallationCheck.strings, packaging/macosx/resources/InstallationCheck: All Hail Discordia. 2005-10-07 02:15:05 - r539 - kyrah * packaging/macosx/Pivy.pkg/Contents/Resources/Pivy.bom, packaging/macos x/Pivy.pkg/Contents/Resources/English.lproj/Welcome.rtf, packaging/m acosx/Pivy.pkg/Contents/Resources/English.lproj/background.pdf, pack aging/macosx/Pivy.pkg/Contents/Resources/English.lproj/InstallationC heck.strings, packaging/macosx/resources/README.txt, packaging/macosx/Welcome.rtf, packaging/macosx/Checklist.txt, packaging/macosx/Pivy.pkg/Contents/Info.plist, packaging/macosx/Pivy.pkg/Contents/Archive.pax.gz, packaging/macosx/Pivy.pkg/Contents/Resources/English.lproj, packaging/macosx/Pivy.pmproj, packaging/macosx, packaging/macosx/resources/InstallationCheck.strings, packaging/macosx/Pivy.pkg/Contents/Resources/Pivy.sizes, packaging/macosx/Pivy.pkg/Contents/Archive.bom, packaging/macosx/Pivy.pkg/Contents/PkgInfo, packaging/macosx/Pivy.pkg/Contents, packaging, packaging/macosx/install, packaging/macosx/Pivy.pkg, packaging/macos x/Pivy.pkg/Contents/Resources/English.lproj/Description.plist, packaging/macosx/resources/InstallationCheck, packaging/macosx/Pivy.pkg/Contents/Resources/BundleVersions.plist, packaging/macosx/resources, packaging/macosx/Pivy.pkg/Contents/Resources/Pivy.pax.gz, packaging/ macosx/Pivy.pkg/Contents/Resources/English.lproj/Pivy.info, packaging/macosx/Pivy.pkg/Contents/Resources/InstallationCheck, packaging/macosx/Pivy.pkg/Contents/Resources, packaging/macosx/Pivy.pkg/Contents/Resources/package_version: Installer for Mac OS 10.4. 2005-09-26 19:25:42 - r537 - tamer * tests/pivy_tests.py, examples/Mentor/03.3.Naming.py, examples/Mentor/17.3.GLFloor.py, examples/Mentor/09.3.Search.py, examples/Mentor/09.5.GenSph.py, examples/Mentor/12.2.NodeSensor.py: remove now obsolete SoDB.init() invocations. 2005-09-26 19:24:48 - r536 - tamer * pivy/__init__.py: let SoDB.init() be invoked automatically upon module import. 2005-09-26 09:49:23 - r535 - tamer * examples/Mentor/05.3.TriangleStripSet.py, examples/Mentor/14.1.FrolickingWords.py, examples/Mentor/02.4.Examiner.py, examples/Mentor/17.3.GLFloor.py, examples/Mentor/05.1.FaceSet.py, examples/Mentor/05.4.QuadMesh.py, examples/SoPyScript/example.iv, examples/Mentor/05.2.IndexedFaceSet.py, examples/Mentor/16.4.OneWindow.py, examples/Mentor/10.3and4.MotifList.py, examples/Mentor/03.2.Robot.py, examples/Mentor/12.3.AlarmSensor.py, examples/Mentor/06.2.Simple3DText.py, examples/Mentor/14.3.Balance.py, examples/Mentor/04.2.Lights.py, examples/Mentor/13.8.Blinker.py, examples/Mentor/15.1.ConeRadius.py, examples/Mentor/09.1.Print.py, examples/Mentor/03.1.Molecule.py, examples/Mentor/08.2.UniCurve.py, examples/Mentor/05.6.TransformOrdering.py, examples/Mentor/08.1.BSCurve.py, examples/Mentor/06.1.Text.py, examples/Mentor/15.4.Customize.py, examples/Mentor/10.1.addEventCB.py, examples/Mentor/09.5.GenSph.py, examples/SoPyScript/textscroll.py, examples/Mentor/13.3.TimeCounter.py, examples/Mentor/07.1.BasicTexture.py, examples/Mentor/09.2.Texture.py, examples/Mentor/13.1.GlobalFlds.py, examples/Mentor/14.2.Editors.py, examples/Mentor/13.7.Rotor.py, examples/Mentor/07.3.TextureFunction.py, examples/Mentor/12.4.TimerSensor.py, examples/Mentor/12.1.FieldSensor.py, examples/Mentor/12.2.NodeSensor.py, examples/Mentor/13.4.Gate.py, examples/Mentor/17.2.GLCallback.py, examples/Mentor/10.7.PickFilterManip.py, examples/Mentor/10.5.SelectionCB.py, examples/Mentor/09.4.PickAction.py, examples/Mentor/15.3.AttachManip.py, examples/Mentor/13.6.Calculator.py, examples/Mentor/02.2.EngineSpin.py, examples/Mentor/07.2.TextureCoordinates.py, examples/Mentor/11.2.ReadString.py, examples/SoPyScript/glow.py, examples/Mentor/06.3.Complex3DText.py, examples/Mentor/03.3.Naming.py, examples/Mentor/04.1.Cameras.py, examples/Mentor/09.3.Search.py, examples/Mentor/10.8.PickFilterNodeKit.py, examples/Mentor/05.5.Binding.py, examples/Mentor/16.3.AttachEditor.py, examples/Mentor/08.4.TrimSurf.py, examples/Mentor/13.5.Boolean.py, examples/Mentor/08.3.BezSurf.py, examples/extend/scale_test.py, examples/Mentor/13.2.ElapsedTime.py, examples/Mentor/15.2.SliderBox.py, examples/Mentor/02.3.Trackball.py, examples/Mentor/16.2.Callback.py, examples/Mentor/10.2.setEventCB.py: autoref'ing now fully works. remove ref/unref() invocations from examples. 2005-09-26 09:48:10 - r534 - tamer * examples/SIMVoleon/utility.py, examples/SIMVoleon/examine.py: cleanup and removal of manual ref's. 2005-09-26 09:46:04 - r533 - tamer * SoPyScript/SoPyScript.cpp, interfaces/coin.i: proper autoref'ing through a feature offered by SWIG. 2005-08-31 17:00:47 - r531 - tamer * examples/Sc21/Sc21Viewer/English.lproj/.cvsignore: removed ignores for cvs. 2005-08-31 16:59:49 - r530 - tamer * NEWS: updated NEWS. 2005-08-31 16:47:12 - r529 - tamer * docs/license.template, examples/contrib/iv2pov.py, examples/contrib/mirrorball.py: set svn:eol-style property to native. 2005-08-31 16:43:58 - r528 - tamer * examples/Mentor/05.3.TriangleStripSet.py, examples/Mentor/14.1.FrolickingWords.py, interfaces/coin.i, examples/Mentor/02.4.Examiner.py, examples/Mentor/17.3.GLFloor.py, examples/Mentor/05.4.QuadMesh.py, examples/Mentor/05.1.FaceSet.py, examples/Mentor/05.2.IndexedFaceSet.py, examples/Mentor/16.4.OneWindow.py, examples/Mentor/10.3and4.MotifList.py, examples/Mentor/03.2.Robot.py, examples/Mentor/12.3.AlarmSensor.py, examples/Mentor/06.2.Simple3DText.py, examples/Mentor/14.3.Balance.py, examples/Mentor/04.2.Lights.py, interfaces/simvoleon.i, SoPyScript/SConstruct, examples/Mentor/13.8.Blinker.py, examples/Mentor/15.1.ConeRadius.py, interfaces/pivy_common_typemaps.i, examples/Mentor/09.1.Print.py, examples/Mentor/03.1.Molecule.py, examples/Mentor/08.2.UniCurve.py, interfaces/soqt.i, examples/Mentor/02.1.HelloCone.py, tests/pivy_tests.py, examples/Mentor/10.6.PickFilterTopLevel.py, examples/Mentor/11.1.ReadFile.py, examples/SoPyScript/SConstruct, examples/Mentor/17.1.ColorIndex.py, examples/Mentor/05.6.TransformOrdering.py, examples/Mentor/08.1.BSCurve.py, examples/examiner_embed.py, examples/contrib/mirrorball.py, SoPyScript/SoPyScript.cpp, examples/Mentor/06.1.Text.py, examples/Mentor/15.4.Customize.py, LICENSE, docs/license.template, examples/Mentor/10.1.addEventCB.py, setup.py, examples/Mentor/09.5.GenSph.py, examples/Mentor/13.3.TimeCounter.py, examples/Mentor/07.1.BasicTexture.py, examples/Mentor/09.2.Texture.py, interfaces/sogtk.i, examples/Mentor/13.1.GlobalFlds.py, examples/Mentor/07.3.TextureFunction.py, examples/Mentor/13.7.Rotor.py, examples/Mentor/14.2.Editors.py, examples/Mentor/12.1.FieldSensor.py, examples/Mentor/12.4.TimerSensor.py, interfaces/soxt.i, examples/Mentor/12.2.NodeSensor.py, examples/extend/SConstruct, examples/Mentor/13.4.Gate.py, examples/Mentor/10.7.PickFilterManip.py, examples/Mentor/16.1.Overlay.py, examples/Mentor/17.2.GLCallback.py, SoPyScript/SoPyScript.h, examples/Mentor/10.5.SelectionCB.py, examples/Mentor/09.4.PickAction.py, examples/Mentor/15.3.AttachManip.py, examples/Mentor/02.2.EngineSpin.py, examples/Mentor/13.6.Calculator.py, examples/Mentor/07.2.TextureCoordinates.py, examples/contrib/iv2pov.py, examples/Mentor/11.2.ReadString.py, examples/Mentor/06.3.Complex3DText.py, examples/Mentor/03.3.Naming.py, examples/Mentor/04.1.Cameras.py, examples/Mentor/09.3.Search.py, examples/Mentor/10.8.PickFilterNodeKit.py, examples/Mentor/16.5.Examiner.py, examples/Mentor/05.5.Binding.py, interfaces/sowin.i, examples/Mentor/16.3.AttachEditor.py, examples/Mentor/08.4.TrimSurf.py, examples/Mentor/13.5.Boolean.py, examples/Mentor/08.3.BezSurf.py, examples/extend/scale_test.py, examples/Mentor/13.2.ElapsedTime.py, examples/Mentor/15.2.SliderBox.py, examples/Mentor/02.3.Trackball.py, examples/Mentor/10.2.setEventCB.py, examples/Mentor/16.2.Callback.py: purification and simplification of the license modeled after the OpenBSD license (which again is modeled after the ISC license). see docs/license.template for more information and license templates to be used for new code. 2005-08-31 16:32:20 - r527 - tamer * Inventor/SbImage.i: proper handling of size[2] == 0 in SbImage::setValue(SbVec3s size, ...) where the image is considered as a 2D image. indendation fixes. 2005-08-30 22:29:38 - r526 - kyrah * examples/Sc21/Sc21Viewer/English.lproj, examples/Sc21/Sc21Viewer/English.lproj/MainMenu.nib, examples/Sc21/Sc21Viewer, examples/Sc21/Sc21Viewer/English.lproj/MainMenu.nib/info.nib, exampl es/Sc21/Sc21Viewer/English.lproj/MainMenu.nib/keyedobjects.nib, examples/Sc21/Sc21Viewer/Sc21Viewer.py, examples/Sc21/Sc21Viewer/English.lproj/MainMenu.nib/classes.nib, examples/Sc21/Sc21Viewer/English.lproj/MainMenu.nib/data.dependency, examples/Sc21, examples/Sc21/Sc21Viewer/buildapp.py, examples/Sc21/Sc21Viewer/English.lproj/.cvsignore, examples/Sc21/Sc21Viewer/main.py: A first PyObjC Sc21 example. 2005-08-19 13:29:50 - r524 - oeystein * examples/contrib/iv2pov.py: Minor changes. 2005-08-19 11:06:51 - r523 - oeystein * examples/contrib/iv2pov.py: Minor fixes 2005-08-19 09:36:49 - r522 - oeystein * examples/contrib/iv2pov.py: A simple inventor-2-POV converter. 2005-08-17 15:33:16 - r519 - tamer * Inventor/actions/SoCallbackAction.i: add missing autocast invocation for SoNode param in SoCallbackActionPythonCB(). override getMaterial() to return a tuple for method's out parameters. reported by Oeystein Handegard. 2005-08-15 08:54:43 - r517 - oeystein * examples/contrib/mirrorball.py: Added encoding keyword. 2005-08-15 08:49:28 - r516 - oeystein * examples/contrib/mirrorball.py: A small script which generates a funky mirrorball. 2005-08-12 16:00:18 - r514 - tamer * examples/contrib: added contrib directory for script contributions. 2005-08-12 13:39:53 - r513 - tamer * THANKS: added Oeystein Handegard. 2005-08-12 06:07:20 - r512 - tamer * setup.py, interfaces/pivy_common_typemaps.i, examples/extend/SConstruct: removed PIVY_WIN32 define. new policy: all platforms must have exactly the same resulting wrapper and shouldn't differ in terms of features (also if it means sacrificing features on platforms where it would have worked fine otherwise). this will allow to bundle the swig generated wrappers with future releases and frees the user from having to install (the correct) SWIG version which further eases deployment. 2005-08-12 05:28:56 - r511 - tamer * MANIFEST.in: swigpyrun.h will now be picked up correctly by sdist through 'graft SoPyScript'. 2005-08-12 05:26:50 - r510 - tamer * SoPyScript/SoPyScript.cpp: fixup header include. 2005-08-12 05:26:07 - r509 - tamer * swigpyrun.h, SoPyScript/swigpyrun.h: moved the swig runtime header to its more apropriate SoPyScript location. 2005-08-11 09:02:08 - r507 - tamer * setup.py: add a more accurate description, increase the version number and fix the download url. remove the distutils classifier workaround for ancient python versions. 2005-08-11 01:17:47 - r504 - tamer * SoPyScript/SoPyScript.cpp: fixed scripting node regression by reverting to SoType::badType(). 2005-08-11 00:00:35 - r502 - tamer * examples/extend/README: remove obsolete notes for older swig versions. 2005-08-10 23:53:18 - r500 - tamer * NEWS: update to reflect current state. 2005-08-09 21:56:43 - r496 - tamer * interfaces/pivy_common_typemaps.i: proper handling for issue14. restructured code and generalized cast function. parent checking is node conducted through SWIG_TypeQuery() invocations done in the cast function. 2005-08-09 18:44:15 - r495 - tamer * interfaces/pivy_common_typemaps.i: as discussed on issue14: actually check with getIsBuiltIn(). plug a memory leak. this is just a temporarily fix until a better approach has been found as this solution doesn't work properly if the extension node is directly inherited from abstract classes such as SoNode or if an actually swigged extension node exists as a parent. 2005-08-09 05:28:33 - r494 - tamer * SoPyScript/SoPyScript.cpp: cleanup. 2005-08-09 05:14:59 - r493 - tamer * examples/SoPyScript/example_remote.iv: renamed scripts on webserver. 2005-08-09 04:27:59 - r492 - tamer * interfaces/pivy_common_typemaps.i: add a better comment. 2005-08-09 04:19:12 - r491 - tamer * interfaces/pivy_common_typemaps.i: fix for issue14. support autocasting for not builtin types. let extension nodes cast to the nearest parent builtin type. 2005-08-09 04:15:25 - r490 - tamer * Inventor/fields/SoMFVec4f.i, Inventor/fields/SoSFImage3.i, Inventor/fields/SoMFColor.i, Inventor/fields/SoMFName.i, Inventor/fields/SoMFUShort.i, Inventor/fields/SoMFUInt32.i, Inventor/fields/SoMFNode.i, Inventor/fields/SoSFImage.i, Inventor/fields/SoMFBool.i, Inventor/fields/SoMFPath.i, Inventor/fields/SoMFTime.i, Inventor/fields/SoMFInt32.i, Inventor/fields/SoMFPlane.i, Inventor/fields/SoMFRotation.i, Inventor/fields/SoMFShort.i, Inventor/fields/SoMFMatrix.i, Inventor/fields/SoMFEnum.i, Inventor/fields/SoMFFloat.i, Inventor/fields/SoMFEngine.i, Inventor/fields/SoMFVec2f.i, Inventor/fields/SoMFString.i, Inventor/fields/SoMFVec3f.i: minor comment fix. 2005-08-09 04:14:34 - r489 - tamer * setup.py: updated and sorted classifiers. 2005-08-08 21:30:39 - r487 - tamer * examples/Mentor/06.3.Complex3DText.py, examples/Mentor/02.4.Examiner.py, examples/Mentor/09.5.GenSph.py: cosmetics: strip empty lines at end. 2005-08-08 21:27:38 - r486 - tamer * examples/Mentor/08.2.UniCurve.py, examples/Mentor/08.3.BezSurf.py, examples/Mentor/08.1.BSCurve.py, examples/Mentor/08.4.TrimSurf.py: remove superfluous \n's. in python we have nice triple quotes for that purpose. 2005-08-08 04:44:45 - r485 - tamer * setup.py: cosmetics: less verbose output. 2005-08-07 19:28:20 - r483 - tamer * THANKS: added Terry Jones. 2005-08-07 19:27:08 - r482 - tamer * interfaces/soqt.i: removed not required Editor includes. further the build breaks on OSX because of a missing SoGuiMaterialEditor.h in the Framework installation. (reported by Terry Jones) 2005-08-07 08:59:02 - r481 - tamer * Inventor/sensors/SoSensor.i: minor code style fix. 2005-08-07 08:35:21 - r480 - tamer * interfaces/pivy_common_typemaps.i: small code style fix. 2005-08-07 08:34:17 - r479 - tamer * examples/extend/scale_test.py: removed now obsolete cast. 2005-08-07 08:33:22 - r478 - tamer * interfaces/pivy_common_typemaps.i: added autocasting for SoEvent classes. 2005-08-07 08:00:12 - r477 - tamer * Inventor/sensors/SoSensor.i: fix typo in typecheck. 2005-08-07 07:39:06 - r476 - tamer * Inventor/SbColor.i, Inventor/SoOffscreenRenderer.i, Inventor/nodes/SoGroup.i, Inventor/sensors/SoSensor.i, Inventor/SbImage.i, Inventor/SbVec2s.i, Inventor/SbDict.i, Inventor/SbDPRotation.i, Inventor/SbVec3s.i, Inventor/SbRotation.i, Inventor/SbVec2d.i, Inventor/SbMatrix.i, Inventor/SbVec3d.i, Inventor/actions/SoWriteAction.i, Inventor/SbVec2f.i, Inventor/SbVec4d.i, Inventor/SbVec3f.i, Inventor/SbString.i, Inventor/SbVec4f.i, Inventor/actions/SoCallbackAction.i, Inventor/SbColor4f.i, Inventor/SoPath.i, Inventor/nodes/SoSelection.i: removed shadowed constructor code as there is really no difference in ownership to the SWIG generated wrapper code. 2005-08-07 07:35:51 - r475 - tamer * Inventor/lists/SoEngineOutputList.i, Inventor/lists/SbStringList.i, Inventor/lists/SbVec3fList.i, Inventor/lists/SoPickedPointList.i, Inventor/lists/SbIntList.i, Inventor/lists/SoActionMethodList.i, Inventor/lists/SoTypeList.i, Inventor/lists/SoDetailList.i, Inventor/lists/SoEngineList.i: added operator[] and set/get support. 2005-08-07 06:19:16 - r474 - tamer * Inventor/lists/SoBaseList.i, Inventor/lists/SoPathList.i, Inventor/lists/SbPList.i, Inventor/lists/SoFieldList.i, Inventor/lists/SoNodeList.i: minor code style fixes. 2005-08-07 06:03:05 - r473 - tamer * Inventor/SoOffscreenRenderer.i: actually, we need the getBuffer() method... *getting some coffee* 2005-08-07 05:55:02 - r472 - tamer * Inventor/SbColor.i: added typemap for hsv[3]. 2005-08-07 05:36:11 - r471 - tamer * MANIFEST.in: include HACKING and NEWS. 2005-08-07 05:35:48 - r470 - tamer * NEWS: added NEWS file describing features and bugfixes between releases. 2005-08-07 05:27:42 - r469 - tamer * Inventor/actions/SoGLRenderAction.i, Inventor/fields/SoMFVec4f.i, Inventor/SoOffscreenRenderer.i, Inventor/Qt/SoQtRenderArea.i, Inventor/SbColor.i, Inventor/fields/SoSFVec2f.i, Inventor/nodes/SoGroup.i, Inventor/sensors/SoSensor.i, Inventor/SbVec3s.i, Inventor/Qt/SoQtCursor.i, Inventor/SbDict.i, Inventor/fields/SoMField.i, Inventor/fields/SoSFVec4f.i, Inventor/draggers/SoDragger.i, Inventor/actions/SoAction.i, Inventor/fields/SoMFUShort.i, Inventor/fields/SoMFNode.i, Inventor/SbBox3s.i, Inventor/SbRotation.i, Inventor/fields/SoMFPath.i, Inventor/SbVec2d.i, Inventor/SbMatrix.i, Inventor/fields/SoMFPlane.i, Inventor/SbVec2f.i, Inventor/SbVec4d.i, Inventor/Win/SoWinCursor.i, Inventor/actions/SoWriteAction.i, Inventor/fields/SoField.i, Inventor/SbVec4f.i, Inventor/actions/SoCallbackAction.i, Inventor/SbColor4f.i, Inventor/fields/SoFieldContainer.i, Inventor/nodes/SoSelection.i, Inventor/nodes/SoNode.i, Inventor/fields/SoMFEngine.i, Inventor/fields/SoMFString.i, Inventor/fields/SoMFVec3f.i, Inventor/nodes/SoCamera.i, Inventor/nodes/SoCallback.i, Inventor/SbImage.i, Inventor/SbVec2s.i, Inventor/fields/SoSFVec3f.i, Inventor/SbDPRotation.i, Inventor/nodes/SoEventCallback.i, Inventor/fields/SoMFColor.i, Inventor/fields/SoMFName.i, Inventor/SbDPMatrix.i, Inventor/lists/SbPList.i, Inventor/fields/SoSFColor.i, Inventor/SbVec3d.i, Inventor/fields/SoMFTime.i, Inventor/fields/SoMFRotation.i, Inventor/fields/SoMFShort.i, Inventor/SbVec3f.i, Inventor/SbString.i, Inventor/SoPath.i, Inventor/fields/SoMFMatrix.i, Inventor/collision/SoIntersectionDetectionAction.i, Inventor/fields/SoMFFloat.i, Inventor/fields/SoMFVec2f.i: fix for Issue16. remove all code obsoleted by SWIG's constructor and method overloading handling. however, need to keep shadowing constructor code dealing with ownership. 2005-08-07 05:23:42 - r468 - tamer * tests/pivy_tests.py: added So prefix in description before singled and multi field types. 2005-08-06 16:59:18 - r466 - tamer * Inventor/sensors/SoDelayQueueSensor.i: remove not needed typdef declaration. 2005-08-04 15:11:14 - r464 - tamer * Inventor/fields/SoSubField.h.fix, Inventor/engines/SoSubEngine.h.fix, Inventor/nodes/SoSubNode.h.fix: removed obsolete files. SWIG empty macro define "#define FOO()" doesn't hit anymore. 2005-08-04 14:56:51 - r463 - tamer * Inventor/system/inttypes.h.win32: type definition for COIN_UINT64_T looks like it could pass through SWIG now. 2005-08-04 14:43:53 - r462 - tamer * fake_headers/Inventor/C/base/string.h, interfaces/coin_header_includes.h, Inventor/fields/SoSFTrigger.i, Inventor/fields/SoSFMatrix.i, Inventor/fields/SoSFImage3.i, Inventor/elements/SoLazyElement.i, HACKING, examples/SoPyScript/example.iv, Inventor/elements/SoDiffuseColorElement.i, VolumeViz/nodes/SoVolumeRender.i, fake_headers/Inventor/C/glue/dl.h, fake_headers/Inventor/C/threads/mutex.h, Inventor/fields/SoMFUShort.i, Inventor/lists/SoFieldList.i, fake_headers/Inventor/C/base/hash.h, Inventor/fields/SoMFNode.i, fake_headers/Inventor/C/threads/thread.h, fake_headers/Inventor/C/threads/worker.h, Inventor/fields/SoMFPath.i, fake_headers/Inventor/C/base/time.h, Inventor/fields/SoMFPlane.i, interfaces/simvoleon.i, fake_headers/Inventor/C/threads/fifo.h, Inventor/fields/SoSFPlane.i, fake_headers/Inventor/C/threads/sched.h, Inventor/system/inttypes.h.win32, fake_headers/Inventor/C/threads/common.h, Inventor/fields/SoSFEngine.i, pivy/gui/__init__.py, fake_headers/Inventor/C/base/list.h, tests/pivy_tests.py, fake_headers/Inventor/C/threads/wpool.h, examples/examiner_embed.py, Inventor/fields/SoMFUInt32.i, fake_headers/Inventor/C/threads/storage.h, fake_headers/Inventor/C/glue/gl.h, pivy/__init__.py, fake_headers/Inventor/C/base/memalloc.h, fake_headers/Inventor/C/errors/error.h, Inventor/fields/SoSubField.h.fix, Inventor/fields/SoMFTime.i, Inventor/fields/SoMFShort.i, Inventor/nodes/SoSubNode.h.fix, Inventor/fields/SoMFMatrix.i, fake_headers/Inventor/C/base/rbptree.h, examples/Mentor/01.1.Windmill.iv, fake_headers/Inventor/C/threads/barrier.h, Inventor/nodekits/SoBaseKit.i, Inventor/fields/SoMField.i, docs/ChangeLog.2004, fake_headers/Inventor/C/threads/condvar.h, fake_headers/Inventor/C/threads/recmutex.h, fake_headers/Inventor/C/base/heap.h, fake_headers/Inventor/C/tidbits.h, examples/SoPyScript/example_local.iv, Inventor/fields/SoSFUShort.i, examples/SoPyScript/example_remote.iv, Inventor/fields/SoSFNode.i, fake_headers/Inventor/C/threads/rwmutex.h, fake_headers/Inventor/C/threads/sync.h, examples/SIMVoleon/utility.py, Inventor/fields/SoSFPath.i, Inventor/engines/SoSubEngine.h.fix, Inventor/fields/SoMFEnum.i, Inventor/fields/SoMFEngine.i, swigpyrun.h, Inventor/lists/SoBaseList.i, Inventor/misc/SoBase.i, examples/SIMVoleon/examine.py, Inventor/fields/SoMFName.i, Inventor/lists/SbPList.i, Inventor/fields/SoSFUInt32.i, Inventor/fields/SoMFBool.i, Inventor/fields/SoMFRotation.i, fake_headers/Inventor/C/errors/debugerror.h, Inventor/engines/SoEngine.i, Inventor/fields/SoSFTime.i: set svn:eol-style property to native. 2005-08-04 14:36:46 - r461 - tamer * setup.py: also clean SIMVoleon headers. 2005-08-04 14:36:06 - r460 - tamer * interfaces/simvoleon.i: added autorefing for SoBase derived nodes. 2005-08-04 14:31:19 - r459 - tamer * examples/SIMVoleon/examine.py: ref'ing now works correctly. 2005-08-04 14:30:01 - r458 - tamer * VolumeViz/nodes, VolumeViz/nodes/SoVolumeRender.i: added support for SoVolumeRender::setAbortCallback(). 2005-08-04 13:38:01 - r457 - tamer * setup.py: docstring fix. 2005-08-04 13:35:42 - r456 - tamer * VolumeViz, setup.py: cleanup of build system support for SIMVoleon. 2005-08-04 08:31:07 - r455 - reitmayr * examples/extend/SConstruct: correct specification of coin lib for windows 2005-08-04 04:33:06 - r454 - tamer * examples/SIMVoleon/utility.py, interfaces/simvoleon.i, examples/SIMVoleon/examine.py, setup.py, examples/SIMVoleon: added initial SIMVoleon support. needs a couple of proper void * typemaps (best would be an interface to numarray to handle the large volume data). otherwise just the ususal callback handling glue code and getBuffer() size parameter handling through typemap numinputs tweaks. it's a piece of cake by now as everything has already been done for the coin module. ;) 2005-08-04 00:46:51 - r453 - tamer * examples/extend/scale_test.py: (C) header update 2005-08-04 00:13:48 - r452 - tamer * examples/extend/scale_test.py: added FIXME note for the ref() problem. 2005-08-03 22:23:09 - r451 - tamer * examples/extend/scale_test.py: added kit.ref() to workaround a segfault and reordered imports to let it work with SoQt. 2005-08-03 21:29:16 - r449 - tamer * Inventor/nodekits/SoBaseKit.i: __getattribute__ -> __getattr__. fixes field access in nodekits as with SoTranslate1Dragger. fix by Gerhard. 2005-08-03 21:26:07 - r448 - tamer * interfaces/coin.i: small simplification. 2005-08-03 08:48:06 - r447 - tamer * examples/extend/ShapeScale.cpp, examples/extend/ShapeScale.h: (C) date update 2005-08-03 07:52:17 - r446 - tamer * examples/extend/shapescale.i: updated (C) 2005-08-03 07:47:54 - r445 - tamer * interfaces/pivy_common_typemaps.i: readded SbString include needed for extension as the extend example. 2005-08-03 07:47:19 - r444 - tamer * examples/extend/scale_test.py: adapted from the __call_() to the assignment interface. 2005-08-03 07:19:00 - r443 - tamer * examples/Mentor/07.1.BasicTexture.py, examples/Mentor/09.2.Texture.py, examples/Mentor/05.3.TriangleStripSet.py, examples/Mentor/14.1.FrolickingWords.py, examples/Mentor/02.4.Examiner.py, examples/Mentor/13.1.GlobalFlds.py, examples/Mentor/17.3.GLFloor.py, examples/Mentor/07.3.TextureFunction.py, examples/Mentor/05.1.FaceSet.py, examples/Mentor/05.4.QuadMesh.py, examples/Mentor/13.7.Rotor.py, examples/Mentor/05.2.IndexedFaceSet.py, examples/Mentor/12.2.NodeSensor.py, examples/Mentor/16.4.OneWindow.py, examples/Mentor/10.3and4.MotifList.py, examples/Mentor/13.4.Gate.py, examples/Mentor/17.2.GLCallback.py, examples/Mentor/10.7.PickFilterManip.py, examples/Mentor/03.2.Robot.py, examples/Mentor/12.3.AlarmSensor.py, examples/Mentor/14.3.Balance.py, examples/Mentor/06.2.Simple3DText.py, examples/Mentor/04.2.Lights.py, examples/Mentor/10.5.SelectionCB.py, examples/Mentor/09.4.PickAction.py, examples/Mentor/15.3.AttachManip.py, examples/Mentor/13.8.Blinker.py, examples/Mentor/15.1.ConeRadius.py, examples/Mentor/13.6.Calculator.py, examples/Mentor/02.2.EngineSpin.py, examples/Mentor/07.2.TextureCoordinates.py, examples/Mentor/09.1.Print.py, examples/Mentor/03.1.Molecule.py, examples/Mentor/08.2.UniCurve.py, examples/Mentor/02.1.HelloCone.py, examples/Mentor/06.3.Complex3DText.py, examples/Mentor/04.1.Cameras.py, examples/Mentor/05.6.TransformOrdering.py, examples/Mentor/08.1.BSCurve.py, examples/Mentor/10.8.PickFilterNodeKit.py, examples/Mentor/05.5.Binding.py, examples/Mentor/16.3.AttachEditor.py, examples/Mentor/08.4.TrimSurf.py, examples/Mentor/13.5.Boolean.py, examples/Mentor/08.3.BezSurf.py, examples/Mentor/06.1.Text.py, examples/Mentor/15.4.Customize.py, examples/Mentor/10.1.addEventCB.py, examples/Mentor/09.5.GenSph.py, examples/Mentor/13.2.ElapsedTime.py, examples/Mentor/15.2.SliderBox.py, examples/Mentor/02.3.Trackball.py, examples/Mentor/10.2.setEventCB.py, examples/Mentor/13.3.TimeCounter.py, examples/Mentor/16.2.Callback.py: the __call__() interface which allowed fields to be treated like methods has been deprecated. adapted examples to use the new assignment functionality through the = operator (which is a much better and more natural interface). 2005-08-03 07:16:20 - r442 - tamer * Inventor/SbName.i: code style fix 2005-08-03 07:15:13 - r441 - tamer * setup.py: shorten the description. 2005-08-03 07:13:22 - r440 - tamer * HACKING: reworded it a bit. 2005-08-03 07:10:36 - r439 - tamer * HACKING: added document describing which coding style guidelines Pivy should adhere to for consistency reasons. i.e. Coin HACKING for C/C++ code; PEP8 and PEP257 for Python code. 2005-08-03 06:49:56 - r438 - tamer * Inventor/fields/SoMFVec4f.i, Inventor/fields/SoSFTrigger.i, Inventor/fields/SoSFMatrix.i, Inventor/fields/SoSFImage3.i, Inventor/fields/SoSFFloat.i, Inventor/fields/SoSFVec2f.i, Inventor/fields/SoMField.i, Inventor/fields/SoSFVec4f.i, Inventor/fields/SoMFUShort.i, Inventor/fields/SoMFNode.i, Inventor/fields/SoSFImage.i, Inventor/fields/SoSFUShort.i, Inventor/fields/SoSFNode.i, Inventor/fields/SoMFPath.i, Inventor/fields/SoMFInt32.i, Inventor/fields/SoMFPlane.i, Inventor/fields/SoField.i, Inventor/fields/SoSFPath.i, Inventor/fields/SoMFEnum.i, Inventor/fields/SoSFPlane.i, Inventor/fields/SoMFEngine.i, Inventor/fields/SoSFInt32.i, Inventor/fields/SoMFString.i, Inventor/fields/SoMFVec3f.i, Inventor/fields/SoSFEnum.i, Inventor/fields/SoSFEngine.i, Inventor/fields/SoSFVec3f.i, Inventor/fields/SoSFString.i, Inventor/fields/SoMFColor.i, Inventor/fields/SoMFName.i, Inventor/fields/SoMFUInt32.i, Inventor/fields/SoSFColor.i, Inventor/fields/SoSFName.i, Inventor/fields/SoSFUInt32.i, Inventor/fields/SoMFBool.i, Inventor/fields/SoMFTime.i, Inventor/fields/SoMFRotation.i, Inventor/fields/SoMFShort.i, Inventor/fields/SoSFBool.i, Inventor/fields/SoMFMatrix.i, Inventor/fields/SoSFTime.i, Inventor/fields/SoMFVec2f.i, Inventor/fields/SoMFFloat.i, Inventor/fields/SoSFRotation.i, Inventor/fields/SoSFShort.i: coding style fixes. *sigh* 2005-08-03 06:17:06 - r437 - tamer * Inventor/fields/SoMFString.i: please, don't comment anything out without leaving a FIXME on why the code is commented. use the #if 0 #endif preprocessor directives to ease finding those parts. 2005-08-03 05:59:26 - r436 - tamer * interfaces/pivy_common_typemaps.i: add generic typemaps for int32_t, uint32_t. 2005-08-02 18:09:24 - r434 - tamer * Inventor/misc/SoBase.i, tests/pivy_tests.py: robustness fix. check if the other value isn't NULL. needed e.g. if return type from SoDB.readAll() is checked. added test case. needs to be fixed for all other __eq__/__nq__ occurences as well. 2005-07-31 23:17:05 - r432 - tamer * AUTHORS, THANKS: added Gerhard Reitmayr to the AUTHORS list. 2005-07-31 17:16:41 - r430 - reitmayr * tests/pivy_tests.py, interfaces/pivy_common_typemaps.i: rearranging declarations makes common type maps for SoFieldContainer output and SbName input work. 2005-07-31 10:54:13 - r429 - reitmayr * tests/pivy_tests.py: more tests for fields, SbTime simplification and len() on MFields 2005-07-31 10:53:27 - r428 - reitmayr * Inventor/fields/SoSFImage.i, Inventor/fields/SoSFTrigger.i, Inventor/fields/SoSFUInt32.i, Inventor/fields/SoSFUShort.i, Inventor/fields/SoSFImage3.i, Inventor/fields/SoMFPath.i, Inventor/fields/SoMFTime.i, Inventor/fields/SoMFPlane.i, Inventor/fields/SoSFPath.i, Inventor/fields/SoMFEnum.i, Inventor/fields/SoMFUInt32.i, Inventor/fields/SoMFUShort.i, Inventor/fields/SoSFColor.i, Inventor/fields/SoSFTime.i, Inventor/fields/SoSFPlane.i: finished getValue/setValue support for fields 2005-07-31 10:52:05 - r427 - reitmayr * Inventor/fields/SoMField.i: support for buildin len() function 2005-07-31 10:49:28 - r426 - reitmayr * Inventor/SbTime.i: simplified SbTime wrapper 2005-07-31 01:55:38 - r425 - tamer * tests/pivy_tests.py: added check for SoField.get(). 2005-07-31 01:35:51 - r424 - tamer * Inventor/fields/SoField.i: handle out parameter for SoField::get(SbString&). reported by Gerhard. 2005-07-30 23:11:40 - r423 - reitmayr * Inventor/fields/SoMFVec4f.i, Inventor/fields/SoSFMatrix.i, Inventor/fields/SoSFVec2f.i, Inventor/fields/SoSFFloat.i, Inventor/fields/SoSFVec4f.i, Inventor/fields/SoMField.i, Inventor/fields/SoMFUShort.i, Inventor/fields/SoMFNode.i, Inventor/fields/SoSFNode.i, Inventor/fields/SoMFInt32.i, Inventor/fields/SoSFInt32.i, Inventor/fields/SoMFEngine.i, Inventor/fields/SoMFString.i, Inventor/fields/SoMFVec3f.i, Inventor/fields/SoSFEnum.i, Inventor/fields/SoSFEngine.i, tests/pivy_tests.py, Inventor/fields/SoSFString.i, Inventor/fields/SoSFVec3f.i, Inventor/fields/SoMFColor.i, Inventor/fields/SoMFName.i, Inventor/fields/SoMFUInt32.i, Inventor/fields/SoSFColor.i, Inventor/fields/SoSFName.i, Inventor/fields/SoMFBool.i, Inventor/fields/SoMFShort.i, Inventor/fields/SoMFRotation.i, Inventor/fields/SoSFBool.i, Inventor/fields/SoMFMatrix.i, Inventor/fields/SoMFFloat.i, Inventor/fields/SoSFRotation.i, Inventor/fields/SoSFShort.i, Inventor/fields/SoMFVec2f.i: implemented setValue/s and getValues for most field types. also added tests for these methods. mostly, I used the swig overloading mechanism and just provided typemaps for correct conversion and type checking. A couple of fields are missing, we should go over them and add them sometime. 2005-07-30 23:06:51 - r422 - reitmayr * Inventor/SbName.i, Inventor/SbString.i: added comparisons with strings 2005-07-30 19:18:54 - r420 - reitmayr * Inventor/misc, Inventor/misc/SoBase.i: working comparisions for SoBase objects based on identity of underlying OIV objects (also, required for correct executions of test) 2005-07-30 16:25:56 - r419 - reitmayr * Inventor/SbName.i, Inventor/SbString.i: fixed various versions of the constructor by simply allowing swig to deal with the overloading. resolves all the tests for SbString and SbName constructors 2005-07-30 16:18:18 - r418 - reitmayr * Inventor/SoType.i, tests/pivy_tests.py: fixed typo in SoType.i plus tests for autocasting from SoType.createInstance 2005-07-30 15:38:52 - r417 - reitmayr * tests/pivy_tests.py: tests for list updates 2005-07-30 15:38:26 - r416 - reitmayr * Inventor/lists/SoBaseList.i, Inventor/lists/SoPathList.i, Inventor/lists/SbPList.i, Inventor/lists/SoFieldList.i, Inventor/lists/SoNodeList.i: updated lists with iterators, [] set and get methods. there is a difference between SoBaseList and SoFieldList in that set does not expand for the former, but does for the later. I have left this in, but it is annoying (see tests). we might want to fix that. 2005-07-30 11:12:25 - r415 - reitmayr * tests/pivy_tests.py: a lot of tests I added while working on field get/set stuff 2005-07-29 14:52:44 - r413 - reitmayr * interfaces/coin.i: moved property removal code to the end to work properly, also use locals now to resolve classes correctly 2005-07-28 16:27:29 - r411 - tamer * interfaces/coin.i: reverted removal of the field property removal code snippet (Gerhard explained in full details what and why it is needed for) needs to be tweaked a bit for some special cases. 2005-07-28 16:18:09 - r410 - tamer * examples/SoPyScript/example.iv, examples/SoPyScript/glow.py: fix for SbColor operator handling. 2005-07-28 16:15:08 - r409 - tamer * Inventor/SbColor.i, Inventor/SbMatrix.i, Inventor/SbDPMatrix.i: proper operator handling and cleanup. 2005-07-27 21:04:00 - r407 - tamer * MANIFEST.in: updated the manifesto for the package generation part of distutils. 2005-07-27 21:00:04 - r406 - tamer * SConstruct: removed obsolete scons build file which was needed for building the libpivy_runtime library. 2005-07-27 20:57:49 - r405 - tamer * setup.py: code cleanup and build system adaptions for new pivy package and SWIG runtime system. support for SWIG 1.3.25 and Coin 2.4. new swig runtime systems allowed to get rid of some dirty harry hacks and workarounds and drastically simplified the build script because of the dreaded(tm) libpivy_runtime library dependency has vanished. 2005-07-27 20:52:24 - r404 - tamer * tests/pivy_tests.py: fixed import for new pivy package. 2005-07-27 20:51:35 - r403 - tamer * SoPyScript/SConstruct: we don't need no dreaded libpivy_runtime library anymore... *tralala* 2005-07-27 20:50:57 - r402 - tamer * SoPyScript/SoPyScript.cpp: code cleanups. adaption to the swig 1.3.25 type system and package system. 2005-07-27 20:48:41 - r401 - tamer * SoPyScript/SoPyScript.h: fixed year in (C) header. 2005-07-27 20:47:31 - r400 - tamer * examples/Mentor/05.3.TriangleStripSet.py, examples/Mentor/14.1.FrolickingWords.py, examples/Mentor/02.4.Examiner.py, examples/Mentor/17.3.GLFloor.py, examples/Mentor/05.1.FaceSet.py, examples/Mentor/05.4.QuadMesh.py, examples/Mentor/05.2.IndexedFaceSet.py, examples/Mentor/16.4.OneWindow.py, examples/Mentor/10.3and4.MotifList.py, examples/Mentor/03.2.Robot.py, examples/Mentor/12.3.AlarmSensor.py, examples/Mentor/06.2.Simple3DText.py, examples/Mentor/14.3.Balance.py, examples/Mentor/04.2.Lights.py, examples/Mentor/13.8.Blinker.py, examples/Mentor/15.1.ConeRadius.py, examples/Mentor/09.1.Print.py, examples/Mentor/03.1.Molecule.py, examples/Mentor/08.2.UniCurve.py, examples/Mentor/02.1.HelloCone.py, examples/Mentor/11.1.ReadFile.py, examples/Mentor/10.6.PickFilterTopLevel.py, examples/Mentor/17.1.ColorIndex.py, examples/Mentor/05.6.TransformOrdering.py, examples/Mentor/08.1.BSCurve.py, examples/Mentor/06.1.Text.py, examples/Mentor/15.4.Customize.py, examples/Mentor/10.1.addEventCB.py, examples/Mentor/09.5.GenSph.py, examples/Mentor/13.3.TimeCounter.py, examples/Mentor/07.1.BasicTexture.py, examples/Mentor/09.2.Texture.py, examples/Mentor/13.1.GlobalFlds.py, examples/Mentor/07.3.TextureFunction.py, examples/Mentor/13.7.Rotor.py, examples/Mentor/14.2.Editors.py, examples/Mentor/12.1.FieldSensor.py, examples/Mentor/12.4.TimerSensor.py, examples/Mentor/12.2.NodeSensor.py, examples/Mentor/13.4.Gate.py, examples/Mentor/17.2.GLCallback.py, examples/Mentor/10.7.PickFilterManip.py, examples/Mentor/16.1.Overlay.py, examples/Mentor/10.5.SelectionCB.py, examples/Mentor/09.4.PickAction.py, examples/Mentor/15.3.AttachManip.py, examples/Mentor/02.2.EngineSpin.py, examples/Mentor/13.6.Calculator.py, examples/Mentor/07.2.TextureCoordinates.py, examples/Mentor/11.2.ReadString.py, examples/Mentor/06.3.Complex3DText.py, examples/Mentor/03.3.Naming.py, examples/Mentor/04.1.Cameras.py, examples/Mentor/09.3.Search.py, examples/Mentor/10.8.PickFilterNodeKit.py, examples/Mentor/05.5.Binding.py, examples/Mentor/16.5.Examiner.py, examples/Mentor/16.3.AttachEditor.py, examples/Mentor/08.4.TrimSurf.py, examples/Mentor/13.5.Boolean.py, examples/Mentor/08.3.BezSurf.py, examples/Mentor/13.2.ElapsedTime.py, examples/Mentor/15.2.SliderBox.py, examples/Mentor/02.3.Trackball.py, examples/Mentor/16.2.Callback.py, examples/Mentor/10.2.setEventCB.py: mega patch II: code cleanups and adaptions for the new package code; made all non working examples (mostly SoGuiMaterialEditor and very Xt, OpenGL toolkit specific code) exiting gracefully explaining why with a short message. (done in order to prevent wasting anybody's time in trying to figure out if his system or rather the code is broken *shrug*) 2005-07-27 20:39:21 - r399 - tamer * examples/SoPyScript/SConstruct: say goodbye to the dreaded pivy_runtime library. *taking a confetti shower* 2005-07-27 20:37:51 - r398 - tamer * examples/examiner_embed.py: added a _working_ example that shows how to embed a SoQtExaminerViewer in a PyQt windows in Pivy. 2005-07-27 20:36:33 - r397 - tamer * examples/extend/scale_test.py, examples/extend/shapescale.i, examples/extend/SConstruct: adaptions for the new type and package system. 2005-07-27 20:35:02 - r396 - tamer * Inventor/fields/SoMFVec4f.i, Inventor/SoOffscreenRenderer.i, Inventor/SbColor.i, Inventor/SbBox3f.i, Inventor/fields/SoSFFloat.i, Inventor/sensors/SoOneShotSensor.i, Inventor/sensors/SoTimerSensor.i, Inventor/SbViewportRegion.i, Inventor/SbVec3s.i, Inventor/SbDPPlane.i, Inventor/SbDict.i, Inventor/fields/SoSFVec4f.i, Inventor/SoNodeKitPath.i, Inventor/actions/SoAction.i, Inventor/fields/SoMFUShort.i, Inventor/SbTime.i, Inventor/SoType.i, Inventor/sensors/SoPathSensor.i, Inventor/SbMatrix.i, Inventor/actions/SoWriteAction.i, Inventor/SbVec4d.i, Inventor/SbVec4f.i, Inventor/SbColor4f.i, Inventor/fields/SoFieldContainer.i, Inventor/nodes/SoSelection.i, Inventor/fields/SoMFVec3f.i, Inventor/fields/SoMFString.i, Inventor/nodes/SoCamera.i, Inventor/SbBox2d.i, Inventor/fields/SoSFEnum.i, Inventor/SbBox2f.i, Inventor/sensors/SoIdleSensor.i, Inventor/SbVec2s.i, Inventor/fields/SoSFVec3f.i, Inventor/SbDPRotation.i, Inventor/fields/SoMFUInt32.i, Inventor/fields/SoSFName.i, Inventor/sensors/SoAlarmSensor.i, Inventor/SbPlane.i, Inventor/SbVec3d.i, Inventor/fields/SoMFShort.i, Inventor/SbVec3f.i, Inventor/fields/SoSFBool.i, Inventor/SoPath.i, Inventor/fields/SoMFVec2f.i, Inventor/fields/SoSFRotation.i, Inventor/fields/SoSFShort.i, Inventor/SbXfBox3f.i, Inventor/nodekits/SoBaseKit.i, Inventor/SbName.i, Inventor/nodes/SoGroup.i, Inventor/fields/SoSFVec2f.i, Inventor/sensors/SoSensor.i, Inventor/sensors/SoFieldSensor.i, Inventor/draggers/SoDragger.i, Inventor/sensors/SoNodeSensor.i, Inventor/SbBox3s.i, Inventor/fields/SoSFImage.i, Inventor/SbRotation.i, Inventor/SbVec2d.i, Inventor/SbVec2f.i, Inventor/fields/SoMFInt32.i, Inventor/sensors/SoDelayQueueSensor.i, Inventor/fields/SoField.i, Inventor/actions/SoCallbackAction.i, Inventor/nodes/SoNode.i, Inventor/fields/SoSFInt32.i, Inventor/fields/SoSFString.i, Inventor/SbImage.i, Inventor/fields/SoMFColor.i, Inventor/SbDPMatrix.i, Inventor/sensors/SoTimerQueueSensor.i, Inventor/fields/SoSFColor.i, Inventor/SbBox2s.i, Inventor/fields/SoMFBool.i, Inventor/SbString.i, Inventor/fields/SoMFFloat.i, Inventor/collision/SoIntersectionDetectionAction.i, Inventor/sensors/SoDataSensor.i: mega patch: code cleanups, various tweaks for swig 1.3.25, replace all occurences of _pivy with the new _coin module name. (no way i am ever going to rename anything like this in pivy again. torture me, scratch me, byte me, hurt me, tell me windows is great -> it's not gonna happen... *sigh*) 2005-07-27 20:26:41 - r395 - tamer * Inventor/Win/SoWinCursor.i: _sowin instead of the _pivy module needs to be consulted for SoWinCursor code if this should ever be touched... 2005-07-27 20:25:27 - r394 - tamer * Inventor/Qt/SoQtCursor.i: hmm, did i mention that we need more unit tests? *argh* 2005-07-27 20:23:58 - r393 - tamer * Inventor/Qt/SoQt.i: swig 1.3.25 has a parsing bug reg. methods with an explicit void parameter in their declaration. this results in swig treating them as 2 separate methods and generating a dispatch function for overloaded methods which then happily breaks of course. 2005-07-27 20:20:59 - r392 - tamer * Inventor/Qt/SoQtRenderArea.i: code cleanups. 2005-07-27 20:20:23 - r391 - tamer * interfaces/pivy.i, interfaces/coin.i: renamed pivy to coin as it now lives under the pivy package as pivy.coin. 2005-07-27 20:19:28 - r390 - tamer * Inventor/Qt/SoQtCursor.i: signing a petition for more unit tests. *cough* 2005-07-27 20:18:02 - r389 - tamer * Inventor/elements, Inventor/elements/SoLazyElement.i, Inventor/elements/SoDiffuseColorElement.i: needed to workaround faulty casts in the autogenerated swig wrapper code. 2005-07-27 20:16:47 - r388 - tamer * interfaces/pivy.i: renamed module to pivy.coin. outsourcing of the Coin header files. removal of the pythoncode snippet at the end which afaics is not needed. = assigments for fields work fine without it and it wouldn't have worked for the case where a user imported the pivy module properly through "import pivy" ;). 2005-07-27 20:12:38 - r387 - tamer * interfaces/sogtk.i, interfaces/soxt.i, interfaces/sowin.i: adaption for the pivy package and %import of the coin module. 2005-07-27 20:11:03 - r386 - tamer * interfaces/soqt.i: added %typechecks for QWidget and QEvent and class declarations for same to get entries for them in the generated SWIG type system code. adaption for the pivy package and %import for the coin module which reduces wrapper size and fixes the issues with the type system handling. 2005-07-27 20:08:24 - r385 - tamer * interfaces/pivy_common_typemaps.i: code cleanup, %typecheck additions needed for swig 1.3.25, %includes for SbString.h and SoField.h needed for the swig interface files code refactoring. 2005-07-27 20:03:29 - r384 - tamer * interfaces/pivy_runtime.i: removed obsolete file. 2005-07-27 20:02:08 - r383 - tamer * interfaces/coin_header_includes.h: outsourced all coin header files into its own file. 2005-07-27 20:00:28 - r382 - tamer * sogui.py, pivy/sogui.py: moved sogui proxy module to its new location in the package hierarchy. 2005-07-27 19:59:45 - r381 - tamer * sogui.py: package system adaptions. 2005-07-27 19:58:59 - r380 - tamer * pivy/__init__.py, pivy/gui/__init__.py, pivy, pivy/gui: added new pivy python package hierarchy and __init__.py code. 2005-07-27 19:57:45 - r379 - tamer * swigpyrun.h: added autogenerated header (see: http://www.swig.org/Doc1.3/Modules.html#external_run_time through 'swig -python -external-runtime swigpyrun.h' needed for the new runtime system mechanisms in 1.3.25. 2005-06-16 00:30:06 - r377 - tamer * MANIFEST.in: strip .txt suffix from README.txt. 2005-06-16 00:23:14 - r376 - tamer * README, README.txt: stripped off the unnecessary .txt suffix. 2005-06-15 15:35:10 - r374 - tamer * sogui.py, interfaces/soqt.i, interfaces/pivy.i, interfaces/sogtk.i, LICENSE, interfaces/soxt.i, interfaces/sowin.i, interfaces/pivy_common_typemaps.i: Copyright header date update. 2005-06-15 15:33:26 - r373 - tamer * MANIFEST.in: update for new directory structure. 2005-06-15 15:29:58 - r372 - tamer * setup.py: link the extensions against the python shared library in order to allow dynamically loading of the SoPyScript node without having to link the main application against the python shared library. (problem reported by Gerhard) 2005-06-15 03:22:56 - r371 - tamer * setup.py: added workaround for Linux systems (such as gentoo) where python gets compiled with a compiler named differently than gcc. this breaks hardcoded detection code (tagged as hackish) in distutils. 2005-05-24 08:24:09 - r369 - tamer * ChangeLog: strip the previous years. 2005-05-24 08:22:39 - r368 - tamer * docs/ChangeLog.2004: added ChangeLog.2004 for historical reference. 2005-05-24 08:15:37 - r366 - tamer * ChangeLog: tweaked the svn2cl.py script to produce a readable ChangeLog. 2005-04-14 23:23:10 - r364 - reitmayr * interfaces/pivy.i, Inventor/engines/SoEngine.i: fixed also access to SoEngineOutputs in a dynamic way. Fixed typo in the property removal code. should work fine now. now it becomes really important that all field types have proper setValue methods, because they are used by the attribute setting code to support n.f = x syntax. 2005-04-14 22:59:45 - r363 - reitmayr * Inventor/nodekits/SoBaseKit.i, interfaces/pivy.i, Inventor/fields/SoFieldContainer.i: solved the field access problem: now it is possible to write material.diffuseColor = [0,1,1] for example. The trick is first to delete all properties of classes derived from SoFieldContainer (see pivy.i) and then implement dynamic access in SoFieldContainer. Also required some additional cleanup in the dynamic access for parts. 2005-04-14 18:35:42 - r361 - reitmayr * Inventor/fields/SoMFBool.i, Inventor/fields/SoMField.i, Inventor/fields/SoMFInt32.i, Inventor/fields/SoMFShort.i, Inventor/fields/SoMFUInt32.i, Inventor/fields/SoMFUShort.i, Inventor/fields/SoMFFloat.i, Inventor/fields/SoMFString.i: much cleaner iterator for MFields. works now for all MFields generically and is based on flashy generators. 2005-04-14 18:34:04 - r360 - reitmayr * interfaces/pivy.i, interfaces/sowin.i: fixes for Coin 2.4: removed deprecated fields and added required #include. also removed iterator stuff which is handled now much nicer. 2005-01-13 16:46:12 - r358 - kyrah * README.txt: Removed Mac OS X workaround, since it is no longer necessary 2005-01-13 16:42:37 - r357 - kyrah * README, README.txt: Renamed for easy double-click-ability. pivy-0.6.5/docs/ChangeLog.20030000644000175000017500000003777213606712377014366 0ustar kurtkurt2003-12-18 16:05 tamer * sogtk.i, soqt.i, soxt.i: added interface files for the separate SoGui modules. 2003-12-18 15:56 tamer * Inventor/SbMatrix.h: fix for the getTransform() method which takes in a bunch of references. reported by Joe Newman. 2003-12-18 15:42 tamer * THANKS: added Christian Sandor. 2003-10-08 23:11 tamer * Inventor/collision/SoIntersectionDetectionAction.h: code style fix and fix for cut and paste error in callback handling. 2003-10-07 19:31 tamer * Inventor/Qt/SoQtRenderArea.h, Inventor/actions/SoCallbackAction.h, Inventor/collision/SoIntersectionDetectionAction.h, Inventor/draggers/SoDragger.h, Inventor/nodes/SoCallback.h, Inventor/nodes/SoEventCallback.h, Inventor/nodes/SoSelection.h, examples/Mentor/python/09.1.Print.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/python/09.5.GenSph.py, examples/Mentor/python/10.1.addEventCB.py, examples/Mentor/python/10.2.setEventCB.py, examples/Mentor/python/10.5.SelectionCB.py, examples/Mentor/python/10.6.PickFilterTopLevel.py, examples/Mentor/python/10.7.PickFilterManip.py, examples/Mentor/python/10.8.PickFilterNodeKit.py, examples/Mentor/python/13.4.Gate.py, examples/Mentor/python/13.5.Boolean.py, examples/Mentor/python/14.3.Balance.py, examples/Mentor/python/15.3.AttachManip.py, examples/Mentor/python/16.2.Callback.py, examples/Mentor/python/17.2.GLCallback.py: removed the Python prefix from the callback methods. e.g. addPythonIntersectionCallback() -> addIntersectionCallback() so that there is no difference anymore between C++ callback method names and the one's in Python. (thx to Joe Newman for notifying me) fixed examples to reflect the changes... 2003-10-07 10:22 tamer * fake_headers/OpenGL/: gl.h, glext.h, glu.h: fake headers needed for MacOSX OpenGL framework. 2003-10-07 10:13 tamer * build_pivy.py: fixes for darwin. (compiler output file needs to be specified with -ofoo) 2003-09-02 20:04 tamer * Inventor/collision/SoIntersectionDetectionAction.h: consistency fix. 2003-09-02 19:10 tamer * THANKS: added joe. 2003-09-02 19:09 tamer * Inventor/collision/SoIntersectionDetectionAction.h: handling for SoIntersectionDetectionAction.h added (callbacks and apply overloads). reported by Joseph Newman. 2003-08-23 15:30 tamer * THANKS: added Peder Blekken. 2003-08-23 15:29 tamer * pivy.i: removed now obsolete ignores as unimplemented methods got fixed in Coin-2 cvs by Peder Blekken. added ignores for SoGuiColorEditor (reported by Roland Schulz) removed typemaps for unsigned char *. those are arrays and python string functions obviously only read until a '\0' is encountered like any other C function, too. this renders SoSFImage.h useless until array handling for unsigned char * is properly fixed in pivy. will very likely map them to lists. 2003-08-23 15:19 tamer * THANKS: added Roland Schulz. 2003-08-23 15:18 tamer * Inventor/: SbDPMatrix.h, SbMatrix.h: gcc 3.3 doesn't work with the former workaround for the swig cast. refined it and made it less ugly. reported by Roland Schulz. 2003-08-22 19:32 tamer * build_pivy.py: -w flag added that allows switching off the suppression of SWIG warnings. 2003-07-28 02:33 tamer * pivy.i: added handling for unsigned char* -> PyString and vice versa. 2003-07-28 02:31 tamer * build_pivy.py: moved -Ifake_headers before -I%s. As seen during my visit at TU Muenchen (many greets to Christian Sandor btw. :)) there are people who really do install Coin into /usr/ instead of /usr/local. 2003-07-28 02:28 tamer * examples/Mentor/python/: 02.1.HelloCone.py, 02.2.EngineSpin.py, 02.3.Trackball.py, 02.4.Examiner.py, 03.1.Molecule.py, 03.2.Robot.py, 03.3.Naming.py, 04.1.Cameras.py, 04.2.Lights.py, 05.1.FaceSet.py, 05.2.IndexedFaceSet.py, 05.3.TriangleStripSet.py, 05.4.QuadMesh.py, 05.5.Binding.py, 05.6.TransformOrdering.py, 06.1.Text.py, 06.2.Simple3DText.py, 06.3.Complex3DText.py, 07.1.BasicTexture.py, 07.2.TextureCoordinates.py, 07.3.TextureFunction.py, 08.1.BSCurve.py, 09.1.Print.py, 09.2.Texture.py, 09.3.Search.py, 09.4.PickAction.py, 09.5.GenSph.py, 10.1.addEventCB.py, 10.3and4.MotifList.py, 10.5.SelectionCB.py, 10.6.PickFilterTopLevel.py, 10.7.PickFilterManip.py, 10.8.PickFilterNodeKit.py, 11.1.ReadFile.py, 11.2.ReadString.py, 12.1.FieldSensor.py, 12.2.NodeSensor.py, 12.3.AlarmSensor.py, 12.4.TimerSensor.py, 13.1.GlobalFlds.py, 13.2.ElapsedTime.py, 13.3.TimeCounter.py, 13.4.Gate.py, 13.5.Boolean.py, 13.6.Calculator.py, 13.7.Rotor.py, 13.8.Blinker.py, 14.1.FrolickingWords.py, 14.2.Editors.py, 14.3.Balance.py, 15.1.ConeRadius.py, 15.2.SliderBox.py, 15.3.AttachManip.py, 15.4.Customize.py, 16.1.Overlay.py, 16.2.Callback.py, 16.3.AttachEditor.py, 16.4.OneWindow.py, 16.5.Examiner.py, 17.1.ColorIndex.py, 17.2.GLCallback.py, 17.3.GLFloor.py: untabified examples. 2003-07-28 02:27 tamer * Inventor/fields/SoSFImage.h: fixed handling for SoSFImage::getValue(), SoSFImage::startEditing(). 2003-07-28 02:24 tamer * Inventor/actions/SoAction.h: handling for new overloaded method added. 2003-07-27 16:37 tamer * build_pivy.py: updated build script for Coin-2.1 and swig 1.3.19. added options to specify SoGui binding it should build Pivy with. (call with --help to see what's available.) fixed typos and general improvements. 2003-07-27 16:34 tamer * pivy.i: Coin-2.1 support. 2003-07-27 16:28 tamer * Inventor/: SbMatrix.h, SbRotation.h, SbTime.h, SoInput.h, Qt/SoQt.h, Qt/SoQtCursor.h, Qt/SoQtRenderArea.h, actions/SoAction.h, fields/SoFieldContainer.h: fixed headers for Coin-2.1. 2003-07-10 01:44 tamer * Inventor/SoOffscreenRenderer.h: fixed writeToRGB() typo. 2003-07-05 03:10 tamer * Inventor/Qt/SoQtRenderArea.h: the QEvent bridge is complete. chose not to depend on and link against libsip and libqtcmodule. used a switch statement for autocasting. by this 10.2.setEventCB.py and native event handling with PyQt now works... 2003-07-05 01:38 tamer * examples/Mentor/python/10.2.setEventCB.py: removed now obsolete FIXME comment. 2003-07-05 01:37 tamer * examples/Mentor/python/10.2.setEventCB.py: code cleanup. 2003-07-05 01:31 tamer * examples/Mentor/python/10.2.setEventCB.py: final version of the now fully working 10.2.setEventCB example. SoQtRenderArea patches to be checked in... 2003-07-05 01:21 tamer * Inventor/SbViewVolume.h: typemaps for projectPointToLine() and projectToScreen(). only projectPointToLine(const SbVec2f& pt, SbVec3f& line0, SbVec3f& line1) const; gets applied. to be used as e.g.: p0, p1 = myViewVolume.projectPointToLine(SbVec2f(x,y)) 2003-07-03 06:38 tamer * examples/Mentor/python/10.2.setEventCB.py: updated example to reflect the changes in SoQtRenderArea which allows now to get QEvent's in the way PyQt expects them. open question: how does one cast a QEvent to a QMouseEvent in PyQt? 2003-07-03 06:27 tamer * Inventor/Qt/SoQtRenderArea.h: the first brick for the pyqt bridge is deployed. from the comments: the next stunt here deserves documentation as otherwise i would not know what is going on here by tomorrow morning! What are we doing here? hacking in extremo! i had to find a way to pass the QEvent instance we get to PyQt! the approach i chose is to create a QEvent instance in Python from PyQt (obviously to let this work the user had to import PyQt beforehand. he has to otherwise he has no reason to create this callback). this gives us a fully and properly instantiated structure as PyQt expects it without digging into sip or depending on the sip library. then i pass the instantiated structure over here and grab the sipThis entry from the instance which holds a u.cppPtr which turns out to be the real Qt Object in memory. *har, we are in business now* now i delete the current pointer and let u.cppPtr point to our very own QEvent Object. amazingly enough this really works... 2003-07-03 01:45 tamer * Inventor/Qt/SoQt.h: Py_BEGIN_ALLOW_THREADS, Py_END_ALLOW_THREADS macros around SoQt::mainLoop() were causing segfaults in examples where e.g. mouse events were processed. the non multithreadsafety feature in Qt and Python said hello and took revenge. therefore i removed them and am starting to rethink a proper solution to handle the dilemma where one would like to start his program in a thread. (i heard sedatives and heavy drugs might help... :() on to plan b, aka. operation 'mr. workaround strikes back'! 2003-07-01 01:09 tamer * Inventor/Qt/SoQt.h: Py_Exit() instead of exit() to allow python call PyFinalize() on exit. 2003-06-30 23:39 tamer * Inventor/Qt/SoQt.h: Pivy_PythonInteractiveLoop has void * as return type and not void. so we really are supposed to return something... 2003-06-28 03:46 tamer * Inventor/Qt/SoQt.h: if SoQt::mainLoop() gets called from within an interactive python session PyRun_InteractiveLoop() is getting called in a separate thread. therefore SoQt::mainLoop() isn't a blocking call anymore allowing further manipulation of the scene graph directly within the python interpreter without the need to go through a thread.start_new_thread() workaround. FIXME note attached as Qt and Python are not mt-safe and nasty problems could result out of this. The non-blocking SoQt::mainLoop() feature is dedicated to Morten Eriksen! ;) 2003-06-26 02:43 tamer * Inventor/Qt/SoQt.h: made SoQt::mainLoop() release the global interpreter lock so that pivy can be used interactively from within the python interpreter without the need to use PyQt and qApp.exec_loop() as a workaround... 2003-03-23 22:24 tamer * Inventor/fields/SoFieldContainer.h: consistency: let types be determined by SWIG descriptor or basename variables. 2003-03-23 22:23 tamer * Inventor/SbVec3d.h: added handling for operator* with methods like SbVec3f_mul(). 2003-03-23 22:22 tamer * Inventor/SbVec3f.h: added handling for operator* etc. with methods like SbVec3f_mul(). 2003-03-23 22:21 tamer * Inventor/SbMatrix.h: added handling for methods like multMatrixVec() that return their value in the 2nd parameter dst. 2003-03-23 22:20 tamer * Inventor/nodes/SoSelection.h: fixed typo with deselect(). 2003-03-17 07:50 tamer * Inventor/fields/: SoMFString.h, SoSFImage.h: fixed typo in SoSFImage error message and added glue code for SoMFString.setValues(). added preliminary currently segfaulting version of a SoSFImage.getValues() method. 2003-03-12 04:42 tamer * Inventor/: SbVec3d.h, fields/SoSFImage.h: added pivy versions for SbVec3d.h SoSFImage.h. FIXME notes in SoSFImage.h as the way unsigned char * pixels for setValue() is very breakable and not a very clean solution. unsigned char * gets mapped to a sequence in Python. e.g.: texture = (0xff,0x00,0x00,0xff) mapTex.image.setValue(SbVec2s(2,2),1,texture) FIXME for SoSFImage getValue(). 2003-03-12 04:37 tamer * Inventor/SbVec3f.h: added __setitem__ method to allow assigning from SoMFVec3f. keep in mind that double indexing like foo[i][2] = bar does not work. the way it works is to calculate the offset and add the coordinate you want to assign. e.g. foo[i*3+2] = 0.15 2003-03-10 00:31 tamer * Inventor/SbRotation.h: added SbRotation_eq(), SbRotation_neq(), SbRotation_mul() methods to support operator==, operator!=, operator*. 2003-03-08 03:13 tamer * Inventor/SbTime.h: added methods SbTime_add, SbTime_sub, SbTime_d_mult, SbTime_mult, SbTime_div to make operators operator+, operator-, operator*, and operator/ accessible through pivy for efficient usage. otherwise one would have to call methods like SbTime.getValue() twice for operation and create a new instance. e.g. subtraction would have been done like so: s = SbTime(); s.setToTimeOfDay() t = SbTime(); t.setToTimeOfDay() r = SbTime(s.getValue() - t.getValue()) now can be achieved through: SbTime_sub(s,t) which removes 2 namespace lookups and one instatiation and calls the more efficient code below. 2003-03-05 04:01 tamer * MANIFEST.in, THANKS, build_pivy.py: distutils is currently not up to the task, so i created a build_pivy.py script that should take care of the build process. 2003-03-05 03:29 tamer * Inventor/fields/SoFieldContainer.h: %typemap(ignore) has been replaced by %typemap(in,numinputs=0) 2003-03-04 23:30 tamer * Inventor/fields/: SoMFColor.h, SoMFVec2f.h, SoMFVec3f.h, SoMFVec4f.h: cosmetics... 2003-03-04 21:12 tamer * Inventor/actions/SoCallbackAction.h: beautified return statement. 2003-03-03 05:22 tamer * fake_headers/: string.h, GL/gl.h, GL/glext.h, GL/glu.h, GL/glx.h, X11/Intrinsic.h, X11/Xresource.h, Xm/Xm.h: added missing fake header files. 2003-03-03 05:21 tamer * Makefile: updated to make it easy to build it under MacOS X. 2003-03-03 03:07 tamer * Makefile, pivy.i, examples/Mentor/python/10.2.setEventCB.py: fixed up pivy.i to support the new classes in coin-2 (mostly untested). changed the C module name to _pivy.so as newer swig versions do it and this is the more usual name for such things in the python community. fixed already all headers in this regard. made 10.2.setEventCB.py example more reasonable with SoQt and added notification about it being not fully operational due to a missing PyQt bridge. 2003-03-03 03:03 tamer * Inventor/: SbColor.h, SbColor4f.h, SbDict.h, SbMatrix.h, SbName.h, SbRotation.h, SbString.h, SbTime.h, SbVec2f.h, SbVec2s.h, SbVec3f.h, SbVec4f.h, SbViewVolume.h, SbViewportRegion.h, SoInput.h, SoOffscreenRenderer.h, SoPath.h, SoType.h, Qt/SoQtCursor.h, Qt/SoQtRenderArea.h, actions/SoAction.h, actions/SoCallbackAction.h, actions/SoWriteAction.h, draggers/SoDragger.h, events/SoEvent.h, fields/SoField.h, fields/SoFieldContainer.h, fields/SoMFColor.h, fields/SoMFFloat.h, fields/SoMFInt32.h, fields/SoMFString.h, fields/SoMFVec2f.h, fields/SoMFVec3f.h, fields/SoMFVec4f.h, fields/SoSFBool.h, fields/SoSFColor.h, fields/SoSFEnum.h, fields/SoSFFloat.h, fields/SoSFInt32.h, fields/SoSFName.h, fields/SoSFRotation.h, fields/SoSFShort.h, fields/SoSFString.h, fields/SoSFVec2f.h, fields/SoSFVec3f.h, fields/SoSFVec4f.h, nodes/SoCallback.h, nodes/SoCamera.h, nodes/SoEventCallback.h, nodes/SoGroup.h, nodes/SoNode.h, nodes/SoSelection.h, sensors/SoAlarmSensor.h, sensors/SoDataSensor.h, sensors/SoDelayQueueSensor.h, sensors/SoFieldSensor.h, sensors/SoIdleSensor.h, sensors/SoNodeSensor.h, sensors/SoOneShotSensor.h, sensors/SoPathSensor.h, sensors/SoSensor.h, sensors/SoTimerQueueSensor.h, sensors/SoTimerSensor.h: fixes and updates for coin-2 support. updated header files to reflect api changes and the new header string containing the new license at the beginning. works with most recent swig-1.3.17 and swig-1.3.18 (currently the bleeding edge from cvs). coin-2 has been configured with --enable-vrml97 --enable-sound --enable-threads. the upcoming pivy distutils setup will take care of the different compile options and setups. 2003-03-03 02:51 tamer * Inventor/: SbOctTree.h, Qt/SoQt.h, lists/SbIntList.h, lists/SbPList.h, lists/SbStringList.h, lists/SbVec3fList.h, lists/SoAuditorList.h, lists/SoDetailList.h, lists/SoEngineOutputList.h, lists/SoFieldList.h, lists/SoPickedPointList.h, lists/SoTypeList.h: removed obsolete files for Coin-2. 2003-03-02 02:00 tamer * Inventor/lists/SoVRMLInterpOutputList.h: removed now obsolete SoVRMLInterpOutputList.h. 2003-03-02 00:14 tamer * THANKS: added Michael Kalkusch, whom I owe a lot to the THANKS file. 2003-03-01 03:03 tamer * AUTHORS: added AUTHORS file. 2003-03-01 02:41 tamer * docs/ruby-inventor.txt: John K. Grytten reported that it is possible to use Coin3d with Ruby by using pivy. Pretty cool! :) thx, John! 2003-03-01 02:30 tamer * THANKS: never forget to be grateful. 2003-03-01 02:11 tamer * docs/ChangeLog.2002: added ChangeLog.2002 for historical reference. pivy-0.6.5/docs/ChangeLog.20040000644000175000017500000022017613606712377014357 0ustar kurtkurt2004-12-30 06:43:44 - r355 - tamer * tests/pivy.py, tests/pivy_tests.py: renamed pivy.py to pivy_tests.py. guess why... (getting some coffee *grmbl*) 2004-12-30 06:41:45 - r354 - tamer * tests/pivy.py, tests/unittests.py: renamed unittests.py to pivy.py (as sogui* tests should be added into separate files and in order to prevent name clashes with existing python modules) 2004-12-30 06:37:43 - r353 - tamer * tests, tests/unittests.py: added initial PyUnit based pivy unit test suite. 2004-12-29 07:35:50 - r351 - tamer * fake_headers/Inventor/C/threads/barrier.h, fake_headers/Inventor/C/base/string.h, fake_headers/Inventor/C/base, fake_headers/Inventor/C/threads/recmutex.h, fake_headers/Inventor/C/threads/condvar.h, fake_headers/Inventor/C/errors, fake_headers/Inventor/C/base/heap.h, fake_headers/Inventor, fake_headers/Inventor/C/glue/dl.h, fake_headers/Inventor/C/threads/mutex.h, fake_headers/Inventor/C/base/hash.h, fake_headers/Inventor/C/threads/thread.h, fake_headers/Inventor/C/tidbits.h, fake_headers/Inventor/C/threads/worker.h, fake_headers/Inventor/C/threads/rwmutex.h, fake_headers/Inventor/C/threads/sync.h, fake_headers/Inventor/C/base/time.h, fake_headers/Inventor/C, fake_headers/Inventor/C/threads/fifo.h, interfaces/pivy_common_typemaps.i, fake_headers/Inventor/C/threads/sched.h, fake_headers/Inventor/C/threads/common.h, interfaces/pivy.i, fake_headers/Inventor/C/base/list.h, fake_headers/Inventor/C/threads/wpool.h, fake_headers/Inventor/C/glue/gl.h, fake_headers/Inventor/C/threads/storage.h, fake_headers/Inventor/C/base/memalloc.h, fake_headers/Inventor/C/threads, fake_headers/Inventor/C/errors/error.h, fake_headers/Inventor/C/glue, fake_headers/Inventor/C/errors/debugerror.h, fake_headers/Inventor/C/base/rbptree.h: do not wrap the Coin internal C functions. 2004-12-29 07:30:28 - r350 - tamer * Inventor/lists/SoBaseList.i, Inventor/lists/SoFieldList.i: added for autocasting to take effect on inherited classes. 2004-12-29 06:34:27 - r349 - tamer * interfaces/pivy_common_typemaps.i: removed fluff. 2004-12-29 05:30:34 - r348 - tamer * examples/Mentor/13.4.Gate.py, Inventor/SoType.i, examples/Mentor/16.2.Callback.py, interfaces/pivy_common_typemaps.i, Inventor/lists/SoNodeList.i: autocasting for all SoFieldContainer, SoPath, SoField derived classes. according typemap for createInstance that allows extensions classe to be hooked in without creating a wrapper through the Inventor type system. 2004-12-19 17:28:03 - r345 - reitmayr * Inventor/nodekits/SoBaseKit.i, Inventor/nodekits: interface file for SoBaseKit to provide generic access to parts! Parts were not wrapped at all and only accessible via OIV framework API. the solution here is dynamic and works automatically for all nodekits. it allows code like the following: s.transform = some node print s.transform.translation.getValue() etc. this is what we have been looking for to implement attribute like field access! 2004-12-19 16:06:22 - r344 - reitmayr * Inventor/fields/SoMFBool.i, interfaces/pivy.i, Inventor/fields/SoMFInt32.i, Inventor/fields/SoMFShort.i, Inventor/fields/SoMFUInt32.i, Inventor/fields/SoMFUShort.i, Inventor/fields/SoMFFloat.i, Inventor/fields/SoMFString.i: for a the simpler MFFields: * added getValues wrapper outputing a list * extended setValues to accept various parameter combinations * added iterator interface to be able to write code like this: t = SoMFString() for x in t: ... do something 2004-12-16 08:53:02 - r342 - reitmayr * Inventor/fields/SoMFVec4f.i, Inventor/fields/SoMFColor.i, Inventor/fields/SoMFInt32.i, Inventor/fields/SoMFFloat.i, Inventor/fields/SoMFVec2f.i, Inventor/fields/SoMFString.i, Inventor/fields/SoMFVec3f.i: added [] operators to the MFields with existing interface files. problem reported by VRLU student. is there an easy way to add this for all the other MFields ? 2004-12-15 11:26:03 - r340 - reitmayr * SoPyScript/SoPyScript.cpp: implemented a dedicated field list to store changed fields until the next execution of script code. this solves a number of problems described in issue 11. 2004-12-13 18:24:42 - r338 - reitmayr * SoPyScript/SoPyScript.cpp: fixed swallowing of '}', if no fields where found 2004-12-13 18:13:20 - r337 - reitmayr * SoPyScript/SoPyScript.cpp: added filename lookup to read script files relative to current file and all other directories on the Open Inventor dir stack. 2004-12-13 17:40:06 - r336 - tamer * examples/Mentor/10.2.setEventCB.py: updated to accomodate the recent operator overload additions. 2004-12-13 17:24:30 - r335 - tamer * README: set native eol-style property. 2004-12-13 17:00:42 - r334 - kyrah * README: Basic build instructions. 2004-12-11 15:37:36 - r332 - reitmayr * Inventor/SbRotation.i, Inventor/SbDPRotation.i, Inventor/SbMatrix.i: more API warts removed. setValue and copy constructors. more getXXX methods to get axis, angle and matrix representations. some copy & paste errors fixed 2004-12-09 23:08:20 - r330 - reitmayr * Inventor/SbVec2s.i, Inventor/SbVec2d.i, Inventor/SbVec3s.i, Inventor/SbVec3d.i, Inventor/SbVec2f.i, Inventor/SbVec4d.i, Inventor/SbVec3f.i, Inventor/SbVec4f.i: added copy constructors and setValue overload to all vector types. also all support setitem now. 2004-12-09 19:49:19 - r328 - reitmayr * Inventor/SbBox2d.i, Inventor/SbVec2d.i: some test work on copy constructors and setValue() overloads 2004-12-09 19:44:52 - r327 - reitmayr * Inventor/SbVec2d.i: fixed a typo 2004-12-09 19:42:36 - r326 - reitmayr * SoPyScript/SoPyScript.cpp: creating python objects after the test for an action function passes. triples performance in the fail case which is the common one. actually it would be better to not call any Python API functions, if not necessary. That require more book-keeping in the node itself. 2004-12-08 18:49:53 - r324 - reitmayr * setup.py: I think the changes warrant a bump up in the version number. It will help me not to confuse the VRLU students :) 2004-12-06 16:54:23 - r322 - reitmayr * SoPyScript/SoPyScript.cpp: another refactoring of the locale dictionary code. reading in a new script should also clear the locale dictionary. now there is only one code location to do that. 2004-12-06 16:41:48 - r321 - tamer * SoPyScript/SoPyScript.cpp: untabified sources... 2004-12-06 16:39:09 - r320 - tamer * SoPyScript/SoPyScript.cpp: more code cleanup. i am a pedantic pita, time to either consult a psychatrist or to do some more python only coding. free form C++ indentation and negative logic is killing me... *help* 2004-12-06 16:15:53 - r319 - tamer * SoPyScript/SoPyScript.cpp: no need to have the state protected. rather enforce it to private as nobody should have a good reason to muck around with it... *shrug* 2004-12-06 16:12:14 - r318 - tamer * SoPyScript/SoPyScript.cpp: further cleanup and gcc3 compile fix. 2004-12-06 15:58:21 - r317 - tamer * SoPyScript/SoPyScript.cpp: code style fixes and cleanup. 2004-12-06 15:48:00 - r316 - tamer * examples/extend/README, scons/scons-README, scons/scons-LICENSE: set native eol-style property. 2004-12-06 15:44:59 - r315 - tamer * examples/extend/ShapeScale.cpp, examples/Mentor/05.3.TriangleStripSet.py, examples/Mentor/14.1.FrolickingWords.py, Inventor/SbViewportRegion.i, examples/Mentor/17.3.GLFloor.py, examples/Mentor/05.2.IndexedFaceSet.py, scons/scons- local-0.96.1/SCons/Tool/default.py, examples/Mentor/10.3and4.MotifList.py, scons/scons- local-0.96.1/SCons/Tool/javah.py, Inventor/SoType.i, examples/Mentor/03.2.Robot.py, Inventor/sensors/SoPathSensor.i, examples/Mentor/14.3.Balance.py, SoPyScript/SConstruct, scons/scons- local-0.96.1/SCons/Tool/as.py, Inventor/fields/SoFieldContainer.i, scons/scons-local-0.96.1/SCons/Tool/sgiar.py, Inventor/nodes/SoSelection.i, scons/scons- local-0.96.1/SCons/Platform/cygwin.py, Inventor/fields/SoMFVec3f.i, scons/scons-local-0.96.1/SCons/Platform/win32.py, Inventor/SbBox2d.i, scons/scons- local-0.96.1/SCons/Scanner/__init__.py, examples/Mentor/08.2.UniCurve.py, Inventor/sensors/SoIdleSensor.i, Inventor/SbVec2s.i, Inventor/fields/SoSFVec3f.i, examples/Mentor/10.6.PickFilterTopLevel.py, scons/scons- local-0.96.1/SCons/Tool/javac.py, scons/scons- local-0.96.1/SCons/Tool/dvips.py, scons/scons- local-0.96.1/SCons/Defaults.py, Inventor/SbPlane.i, examples/Mentor/06.1.Text.py, setup.py, examples/SoPyScript/textscroll.py, scons/scons- local-0.96.1/SCons/Tool/f77.py, examples/Mentor/13.3.TimeCounter.py, Inventor/fields/SoSFRotation.i, Inventor/actions/SoGLRenderAction.i, examples/Mentor/07.1.BasicTexture.py, scons/scons- local-0.96.1/SCons/Options/EnumOption.py, scons/scons- local-0.96.1/SCons/Tool/jar.py, examples/Mentor/09.2.Texture.py, scons/scons-local-0.96.1/SCons/Tool/g++.py, docs/ChangeLog.2002, Inventor/nodes/SoGroup.i, docs/ChangeLog.2003, scons/scons- local-0.96.1/SCons/Tool/m4.py, examples/Mentor/14.2.Editors.py, Inventor/sensors/SoFieldSensor.i, interfaces/soxt.i, examples/Mentor/12.2.NodeSensor.py, scons/scons- local-0.96.1/SCons/Tool/RCS.py, scons/scons- local-0.96.1/SCons/Tool/rmic.py, Inventor/SbBox3s.i, examples/Mentor/10.7.PickFilterManip.py, examples/Mentor/16.1.Overlay.py, scons/scons- local-0.96.1/SCons/Tool/JavaCommon.py, scons/scons- local-0.96.1/SCons/Platform/darwin.py, Inventor/lists/SoPathList.i, Inventor/SbVec2d.i, Inventor/sensors/SoDelayQueueSensor.i, Inventor/fields/SoField.i, examples/Mentor/15.3.AttachManip.py, examples/Mentor/13.6.Calculator.py, examples/Mentor/07.2.TextureCoordinates.py, scons/scons- local-0.96.1/SCons/Tool/icl.py, Inventor/fields/SoSFString.i, Inventor/fields/SoMFColor.i, scons/scons- local-0.96.1/SCons/Tool/mingw.py, scons/scons- local-0.96.1/SCons/Tool/sunlink.py, examples/Mentor/10.8.PickFilterNodeKit.py, Inventor/SbDPMatrix.i, scons/scons-local-0.96.1/SCons/Script/__init__.py, Inventor/fields/SoSFColor.i, scons/scons- local-0.96.1/SCons/Platform/aix.py, scons/scons- local-0.96.1/SCons/Tool/CVS.py, scons/scons- local-0.96.1/SCons/Tool/PharLapCommon.py, scons/scons- local-0.96.1/SCons/Options/BoolOption.py, scons/scons- local-0.96.1/SCons/Tool/f95.py, Inventor/collision/SoIntersectionDetectionAction.i, Inventor/sensors/SoDataSensor.i, Inventor/fields/SoMFVec4f.i, scons /scons-local-0.96.1/SCons/Tool/sgic++.py, scons/scons- local-0.96.1/SCons/Platform/sunos.py, Inventor/sensors/SoOneShotSensor.i, Inventor/SbVec3s.i, Inventor/fields/SoSFVec4f.i, scons/scons- local-0.96.1/SCons/Tool/386asm.py, scons/scons- local-0.96.1/SCons/Optik/option.py, examples/Mentor/05.1.FaceSet.py, scons/scons-local-0.96.1/SCons/Tool/qt.py, Inventor/actions/SoAction.i, scons/scons- local-0.96.1/SCons/Tool/tar.py, scons/scons- local-0.96.1/SCons/Tool/aixcc.py, scons/scons- local-0.96.1/SCons/Node/Python.py, scons/scons- local-0.96.1/SCons/exitfuncs.py, scons/scons- local-0.96.1/SCons/Tool/f90.py, examples/Mentor/06.2.Simple3DText.py, scons/scons- local-0.96.1/SCons/Tool/nasm.py, scons/scons- local-0.96.1/SCons/Tool/sunc++.py, Inventor/SbMatrix.i, examples/Mentor/04.2.Lights.py, scons/scons- local-0.96.1/SCons/Warnings.py, Inventor/fields/SoSFEnum.i, Inventor/SbBox2f.i, scons/scons-local-0.96.1/SCons/Tool/latex.py, scons/scons-local-0.96.1/SCons/Node/FS.py, scons/scons- local-0.96.1/SCons/Scanner/Fortran.py, MANIFEST.in, Inventor/fields/SoSFName.i, scons/scons- local-0.96.1/SCons/Sig/MD5.py, scons/scons- local-0.96.1/SCons/Optik/option_parser.py, Inventor/SbVec3d.i, Inventor/fields/SoSFBool.i, scons/scons- local-0.96.1/SCons/Tool/gas.py, Inventor/Qt/SoQtRenderArea.i, Inventor/sensors/SoSensor.i, examples/Mentor/13.1.GlobalFlds.py, examples/Mentor/12.1.FieldSensor.py, examples/Mentor/13.4.Gate.py, scons/scons-local-0.96.1/SCons/Tool/tlib.py, Inventor/SbRotation.i, scons/scons-local-0.96.1/SCons/Tool/link.py, scons/scons- local-0.96.1/SCons/Tool/aixlink.py, scons/scons- local-0.96.1/SCons/Tool/Subversion.py, scons/scons- local-0.96.1/SCons/Errors.py, scons/scons- local-0.96.1/SCons/Tool/tex.py, Inventor/SbVec2f.i, AUTHORS, examples/Mentor/10.5.SelectionCB.py, examples/Mentor/09.4.PickAction.py, Inventor/actions/SoCallbackAction.i, scons/scons- local-0.96.1/SCons/Sig/__init__.py, scons/scons- local-0.96.1/SCons/Tool/g77.py, scons/scons- local-0.96.1/SCons/Tool/Perforce.py, Inventor/nodes/SoNode.i, examples/Mentor/11.2.ReadString.py, scons/scons- local-0.96.1/SCons/Tool/msvc.py, examples/SoPyScript/glow.py, scons /scons-local-0.96.1/SCons/Tool/swig.py, scons/scons.py, examples/Mentor/06.3.Complex3DText.py, Inventor/nodes/SoCallback.i, Inventor/SbImage.i, scons/scons- local-0.96.1/SCons/Script/SConscript.py, examples/Mentor/03.3.Naming.py, SConstruct, scons/scons- local-0.96.1/SCons/Tool/midl.py, scons/scons- local-0.96.1/SCons/Tool/msvs.py, sogui.py, examples/Mentor/13.5.Boolean.py, examples/Mentor/08.3.BezSurf.py, scons/scons-local-0.96.1/SCons/Tool/bcc32.py, scons/scons- local-0.96.1/SCons/Tool/icc.py, examples/extend/scale_test.py, scons /scons-local-0.96.1/SCons/Util.py, examples/Mentor/02.3.Trackball.py, scons/scons- local-0.96.1/SCons/Tool/ilink.py, Inventor/SbBox3f.i, scons/scons- local-0.96.1/SCons/Tool/yacc.py, Inventor/SbDict.i, examples/Mentor/05.4.QuadMesh.py, scons/scons- local-0.96.1/SCons/Platform/irix.py, scons/scons- local-0.96.1/SCons/Tool/cc.py, Inventor/SbTime.i, scons/scons- local-0.96.1/SCons/Tool/linkloc.py, scons/scons- local-0.96.1/SCons/Platform/hpux.py, scons/scons- local-0.96.1/SCons/Tool/mslink.py, examples/Mentor/12.3.AlarmSensor.py, Inventor/SbVec4d.i, Inventor/Win/SoWinCursor.i, scons/scons- local-0.96.1/SCons/Taskmaster.py, Inventor/Win/SoWin.i, THANKS, scons/scons-local-0.96.1/SCons/Tool/gs.py, examples/Mentor/03.1.Molecule.py, scons/scons- local-0.96.1/SCons/Tool/BitKeeper.py, scons/scons- local-0.96.1/SCons/Tool/suncc.py, scons/scons- local-0.96.1/SCons/Tool/ilink32.py, Inventor/nodes/SoEventCallback.i, examples/Mentor/11.1.ReadFile.py, examples/extend/shapescale.i, interfaces/pivy_runtime.i, examples/Mentor/05.6.TransformOrdering.py, examples/SoPyScript/soqtexamin.cpp, examples/Mentor/08.1.BSCurve.py, scons/scons-local-0.96.1/SCons/Scanner/Prog.py, SoPyScript/SoPyScript.cpp, examples/Mentor/15.4.Customize.py, examples/Mentor/10.1.addEventCB.py, Inventor/SbVec3f.i, examples/Mentor/09.5.GenSph.py, scons/scons- local-0.96.1/SCons/Tool/dmd.py, scons/scons- local-0.96.1/SCons/Platform/__init__.py, scons/scons- local-0.96.1/SCons/SConsign.py, Inventor/fields/SoSFShort.i, Inventor/SbName.i, interfaces/sogtk.i, Inventor/Qt/SoQt.i, Inventor/draggers/SoDragger.i, examples/Mentor/12.4.TimerSensor.py, scons/scons-local-0.96.1/SCons/Options/ListOption.py, scons/scons- local-0.96.1/SCons/dblite.py, examples/extend/SConstruct, scons /scons-local-0.96.1/SCons/Tool/SCCS.py, scons/scons- local-0.96.1/SCons/Tool/__init__.py, scons/scons- local-0.96.1/SCons/Tool/hpc++.py, Inventor/fields/SoMFInt32.i, Inventor/fields/SoSFInt32.i, scons/scons- local-0.96.1/SCons/Conftest.py, scons/scons- local-0.96.1/SCons/Platform/posix.py, scons/sconsign.py, scons /scons-local-0.96.1/SCons/Options/__init__.py, examples/Mentor/04.1.Cameras.py, scons/scons- local-0.96.1/SCons/Tool/hplink.py, examples/Mentor/16.3.AttachEditor.py, scons/scons- local-0.96.1/SCons/Tool/sgicc.py, scons/scons- local-0.96.1/SCons/Job.py, Inventor/SbViewVolume.i, scons/scons- local-0.96.1/SCons/Scanner/C.py, scons/scons- local-0.96.1/SCons/Options/PackageOption.py, examples/Mentor/13.2.ElapsedTime.py, examples/Mentor/15.2.SliderBox.py, examples/Mentor/10.2.setEventCB.py, Inventor/fields/SoMFFloat.i, scons/scons-local-0.96.1/SCons/Builder.py, Inventor/SbColor.i, Inventor/SoOffscreenRenderer.i, scons/scons- local-0.96.1/SCons/Tool/aixc++.py, scons/scons- local-0.96.1/SCons/Tool/fortran.py, Inventor/fields/SoSFFloat.i, examples/Mentor/02.4.Examiner.py, Inventor/sensors/SoTimerSensor.i, Inventor/SbDPPlane.i, scons/scons-local-0.96.1/SCons/__init__.py, Inventor/SoNodeKitPath.i, examples/Mentor/16.4.OneWindow.py, Inventor/actions/SoWriteAction.i, scons/scons- local-0.96.1/SCons/Node/Alias.py, scons/scons- local-0.96.1/SCons/Tool/zip.py, Inventor/SbVec4f.i, examples/Mentor/13.8.Blinker.py, Inventor/SbColor4f.i, examples/Mentor/15.1.ConeRadius.py, docs/ruby-inventor.txt, examples/Mentor/09.1.Print.py, interfaces/pivy_common_typemaps.i, scons/scons-local-0.96.1/SCons/Node/__init__.py, Inventor/SoInput.i, Inventor/fields/SoMFString.i, scons/scons- local-0.96.1/SCons/Sig/TimeStamp.py, Inventor/nodes/SoCamera.i, examples/Mentor/02.1.HelloCone.py, interfaces/soqt.i, scons/scons- local-0.96.1/SCons/Tool/hpcc.py, Inventor/SbDPRotation.i, examples/SoPyScript/SConstruct, examples/Mentor/17.1.ColorIndex.py, scons/scons-local-0.96.1/SCons/Tool/ifort.py, scons/scons- local-0.96.1/SCons/Tool/pdftex.py, scons/scons- local-0.96.1/SCons/SConf.py, examples/SoPyScript/sowinexamin.cpp, Inventor/sensors/SoAlarmSensor.i, scons/scons- local-0.96.1/SCons/Tool/gcc.py, LICENSE, scons/scons- local-0.96.1/SCons/Tool/ar.py, Inventor/SoPath.i, scons/scons- local-0.96.1/SCons/Tool/mslib.py, Inventor/fields/SoMFVec2f.i, scons /scons-local-0.96.1/SCons/Tool/c++.py, scons/scons- local-0.96.1/SCons/Platform/os2.py, Inventor/SbXfBox3f.i, Inventor/fields/SoSFVec2f.i, Inventor/Qt/SoQtCursor.i, scons/scons- local-0.96.1/SCons/Executor.py, examples/Mentor/13.7.Rotor.py, examples/Mentor/07.3.TextureFunction.py, scons/scons- local-0.96.1/SCons/Scanner/IDL.py, Inventor/sensors/SoNodeSensor.i, Inventor/lists/SoNodeList.i, scons/scons- local-0.96.1/SCons/Tool/lex.py, scons/scons- local-0.96.1/SCons/Tool/sunar.py, examples/Mentor/17.2.GLCallback.py, Inventor/fields/SoSFImage.i, scons/scons-local-0.96.1/SCons/Tool/masm.py, scons/scons- local-0.96.1/SCons/Scanner/D.py, examples/Mentor/02.2.EngineSpin.py, scons/scons-local-0.96.1/SCons/Debug.py, scons/scons- local-0.96.1/SCons/Tool/ifl.py, scons/scons- local-0.96.1/SCons/Tool/dvipdf.py, interfaces/pivy.i, scons/scons- local-0.96.1/SCons/Tool/cvf.py, examples/Mentor/09.3.Search.py, Inventor/sensors/SoTimerQueueSensor.i, scons/scons- local-0.96.1/SCons/Optik/errors.py, interfaces/sowin.i, examples/Mentor/16.5.Examiner.py, examples/Mentor/05.5.Binding.py, scons/scons-local-0.96.1/SCons/Environment.py, examples/Mentor/08.4.TrimSurf.py, Inventor/SbBox2s.i, scons/scons- local-0.96.1/SCons/Action.py, scons/scons- local-0.96.1/SCons/Tool/sgilink.py, Inventor/SbString.i, scons /scons-local-0.96.1/SCons/Options/PathOption.py, scons/scons- local-0.96.1/SCons/Tool/aixf77.py, examples/Mentor/16.2.Callback.py, scons/scons-local-0.96.1/SCons/Tool/gnulink.py, scons/scons- local-0.96.1/SCons/Tool/pdflatex.py, scons/scons- local-0.96.1/SCons/Optik/__init__.py: set native eol-style property. 2004-12-06 15:42:29 - r314 - tamer * fake_headers/string.h, fake_headers/OpenGL/glext.h, fake_headers/Xm/Xm.h, fake_headers/stddef.h, fake_headers/gtk/gtk.h, fake_headers/OpenGL/glu.h, fake_headers/X11/Intrinsic.h, fake_headers/sys/time.h, examples/extend/ShapeScale.h, fake_headers/inttypes.h, fake_headers/stdlib.h, fake_headers/sys/types.h, fake_headers/stdio.h, fake_headers/stdarg.h, fake_headers/GL/glext.h, fake_headers/OpenGL/gl.h, fake_headers/qobject.h, fake_headers/X11/Xresource.h, fake_headers/GL/glu.h, fake_headers/math.h, fake_headers/qwindowdefs.h, fake_headers/windows.h, fake_headers/GL/glx.h, SoPyScript/SoPyScript.h, fake_headers/time.h, ChangeLog, fake_headers/assert.h, fake_headers/qevent.h, fake_headers/GL/gl.h, fake_headers/wchar.h: set native eol-style property. 2004-12-06 15:41:59 - r313 - tamer * SoPyScript/SoPyScript.cpp, Inventor/SoNodeKitPath.i: converted to unix line endings. 2004-12-06 10:38:21 - r312 - reitmayr * SoPyScript/SoPyScript.cpp: copyContents was missing code to reset the python dictionaries representing scope and handlers. refactored necessary code into initFieldData to have it accessible from every location necessary. 2004-12-06 09:03:57 - r311 - reitmayr * SoPyScript/SoPyScript.cpp: fixed multiple scripts issue and probably threading. should resolve issue 7. 2004-12-05 17:10:33 - r309 - reitmayr * Inventor/SbBox2d.i, Inventor/SbPlane.i, Inventor/SbXfBox3f.i, Inventor/SbDPPlane.i, Inventor/SbDPRotation.i, Inventor/SoNodeKitPath.i, Inventor/SbColor4f.i: more operators and some cleanup 2004-12-05 16:26:16 - r308 - reitmayr * Inventor/SbTime.i: added operators and improved getValue to also accept another SbTime instance 2004-12-05 12:33:12 - r307 - reitmayr * Inventor/SbBox2s.i, Inventor/SbBox2d.i, Inventor/SbBox3s.i, Inventor/SbBox2f.i, Inventor/SbBox3f.i, Inventor/SbDPMatrix.i: more operator overloads 2004-12-05 11:37:39 - r306 - reitmayr * Inventor/SoOffscreenRenderer.i, Inventor/SbColor.i, Inventor/SbName.i, Inventor/nodes/SoGroup.i, Inventor/sensors/SoOneShotSensor.i, Inventor/sensors/SoSensor.i, Inventor/SbViewportRegion.i, Inventor/SbVec3s.i, Inventor/Qt/SoQtCursor.i, Inventor/SbDict.i, Inventor/sensors/SoTimerSensor.i, Inventor/sensors/SoFieldSensor.i, Inventor/sensors/SoNodeSensor.i, Inventor/SbTime.i, Inventor/SbRotation.i, Inventor/sensors/SoPathSensor.i, Inventor/SbVec2d.i, Inventor/SbMatrix.i, Inventor/SbVec2f.i, Inventor/SbVec4d.i, Inventor/Win/SoWinCursor.i, Inventor/actions/SoWriteAction.i, Inventor/sensors/SoDelayQueueSensor.i, Inventor/SbVec4f.i, Inventor/actions/SoCallbackAction.i, Inventor/SbColor4f.i, Inventor/nodes/SoSelection.i, Inventor/sensors/SoIdleSensor.i, Inventor/SbVec2s.i, Inventor/SbImage.i, Inventor/SbDPRotation.i, Inventor/sensors/SoTimerQueueSensor.i, Inventor/sensors/SoAlarmSensor.i, Inventor/SbVec3d.i, Inventor/SbString.i, Inventor/SbVec3f.i, Inventor/SoPath.i, Inventor/sensors/SoDataSensor.i: fixed constructors for modern. the C objects were deleted at the end of the constructors ! 2004-12-03 10:46:56 - r304 - reitmayr * Inventor/SoOffscreenRenderer.i, Inventor/SbColor.i, Inventor/SbName.i, Inventor/nodes/SoGroup.i, Inventor/sensors/SoOneShotSensor.i, Inventor/sensors/SoSensor.i, Inventor/SbViewportRegion.i, Inventor/SbVec3s.i, Inventor/Qt/SoQtCursor.i, Inventor/SbDict.i, Inventor/sensors/SoTimerSensor.i, Inventor/sensors/SoFieldSensor.i, Inventor/sensors/SoNodeSensor.i, Inventor/SbTime.i, Inventor/SbRotation.i, Inventor/sensors/SoPathSensor.i, Inventor/SbVec2d.i, Inventor/SbMatrix.i, Inventor/SbVec2f.i, Inventor/SbVec4d.i, Inventor/Win/SoWinCursor.i, Inventor/actions/SoWriteAction.i, Inventor/sensors/SoDelayQueueSensor.i, Inventor/SbVec4f.i, Inventor/actions/SoCallbackAction.i, Inventor/SbColor4f.i, Inventor/nodes/SoSelection.i, Inventor/sensors/SoIdleSensor.i, Inventor/SbVec2s.i, Inventor/SbImage.i, Inventor/SbDPRotation.i, SConstruct, Inventor/sensors/SoTimerQueueSensor.i, Inventor/sensors/SoAlarmSensor.i, Inventor/SbVec3d.i, Inventor/SbString.i, Inventor/SbVec3f.i, setup.py, Inventor/SoPath.i, Inventor/sensors/SoDataSensor.i: build system switched to -modern. all constructors fixed to work with -modern. should resolve issue 7 and 8. 2004-12-02 17:19:20 - r302 - reitmayr * SoPyScript/SoPyScript.cpp: a fix for issue 6 ? 2004-11-21 14:36:19 - r300 - reitmayr * setup.py: fixed a typo 2004-11-21 14:35:22 - r299 - reitmayr * interfaces/pivy.i: added reference counting for SoBase derived types to eliminate a whole range of error cases. 2004-11-21 14:33:53 - r298 - reitmayr * Inventor/SbRotation.i, Inventor/SbVec2s.i, Inventor/SbVec2d.i, Inventor/SbVec3s.i, Inventor/SbViewportRegion.i, Inventor/SbMatrix.i, Inventor/SbVec3d.i, Inventor/SbVec2f.i, Inventor/SbVec4d.i, Inventor/SbVec3f.i, Inventor/SbVec4f.i: a couple of operator overloads for algebraic types for simplified use. 2004-11-21 14:26:31 - r297 - reitmayr * SoPyScript/SoPyScript.h: used correct define which is set automatically 2004-10-25 23:33:28 - r295 - tamer * examples/Mentor/09.1.Print.py: get rid of Python's deprecation warning. 2004-10-25 23:09:25 - r294 - tamer * examples/SoPyScript/SConstruct, SoPyScript/SConstruct, examples/extend/SConstruct: allow builds even though pivy has not been installed yet. 2004-10-25 00:46:36 - r292 - tamer * interfaces/soxt.i: updates for SoXt binding. 2004-10-24 23:20:35 - r291 - tamer * examples/extend/scale_test.py: remove unnecessary explicit cast. 2004-10-24 23:14:29 - r290 - tamer * examples/extend/scale_test.py, examples/extend/SConstruct: windows build fix. remove explicit cast. 2004-10-24 22:18:14 - r289 - tamer * examples/extend/SConstruct: added missing read() for popen. 2004-10-24 22:03:53 - r288 - tamer * examples/SoPyScript/SConstruct, SoPyScript/SConstruct, SConstruct, setup.py, examples/extend/SConstruct: help wincrap in building. 2004-10-24 22:01:56 - r287 - tamer * SoPyScript/SoPyScript.cpp, SoPyScript/SoPyScript.h: wincrap DLL stuff... 2004-10-24 22:00:41 - r286 - tamer * examples/SoPyScript/sowinexamin.cpp, examples/SoPyScript/soqtexamin.cpp: added toolkit specific examiner viewers. 2004-10-24 22:00:07 - r285 - tamer * examples/SoPyScript/examin.cpp: removed obsolete file. 2004-10-24 17:40:11 - r283 - tamer * examples/SoPyScript/SConstruct, SoPyScript/SConstruct, examples/extend/SConstruct: scons' RPATH environment variable instead of platform check and -Wl,-R for the runtime library path. 2004-10-24 05:02:34 - r282 - tamer * examples/SoPyScript/SConstruct, SoPyScript/SConstruct, SConstruct, examples/extend/SConstruct: consistency fixes. 2004-10-24 04:24:04 - r281 - tamer * SConstruct: link with -install_name on darwin so no DYLD_LIBRARY_PATH has to be specified for the runtime library. 2004-10-24 02:36:18 - r280 - tamer * examples/SoPyScript/SConstruct: added LINKFORSHARED distutils config var. 2004-10-24 02:34:19 - r279 - tamer * examples/extend/SConstruct: added LINKFORSHARED distutils config var and removed swig verbose flag. 2004-10-24 02:30:37 - r278 - tamer * SoPyScript/SConstruct: indentation fix. 2004-10-24 02:24:27 - r277 - tamer * SoPyScript/SConstruct: added LINKSFORSHARED distutils config var. 2004-10-24 02:13:48 - r276 - tamer * examples/SoPyScript/SConstruct, SoPyScript/SConstruct, SConstruct, examples/extend/SConstruct: consistency fixes. 2004-10-24 02:09:47 - r275 - tamer * SConstruct, MANIFEST.in: add LINKER flags. 2004-10-24 01:23:30 - r274 - tamer * SConstruct, setup.py: create and handle the shared pivy_runtime library through scons. 2004-10-24 01:21:32 - r273 - tamer * interfaces/soqt.i: cleanup. 2004-10-23 20:35:46 - r271 - tamer * examples/extend/SConstruct: no need to link against Python library as an extension. 2004-10-23 17:34:35 - r270 - tamer * examples/extend/SConstruct: remove debuging fluff... 2004-10-23 17:33:50 - r269 - tamer * examples/extend/SConstruct: be more explicit about the shared library suffix. this is necessary for platforms such as darwin. 2004-10-23 17:28:51 - r268 - tamer * examples/extend/Makefile: removed obsolete file. 2004-10-23 17:28:30 - r267 - tamer * examples/extend/README, examples/extend/SConstruct: added scons SConstruct file. 2004-10-23 15:56:47 - r266 - tamer * examples/SoPyScript/SConstruct: SConstruct simplification. 2004-10-23 02:24:47 - r265 - tamer * SoPyScript/glow.py, SoPyScript/examin.cpp, SoPyScript/example_local.iv, SoPyScript/example_remote.iv, SoPyScript/SConstruct, SoPyScript/example.iv, SoPyScript/textscroll.py, SoPyScript/Makefile: removed obsolete files. build a shared scripting node library. 2004-10-23 02:22:56 - r264 - tamer * examples/SoPyScript, examples/SoPyScript/examin.cpp, examples/SoPyScript/example_local.iv, examples/SoPyScript/example_remote.iv, examples/SoPyScript/SConstruct, examples/SoPyScript/example.iv, examples/SoPyScript/textscroll.py, examples/SoPyScript/glow.py: added SoPyScript examples. 2004-10-22 18:53:55 - r262 - tamer * SoPyScript/examin.cpp: removed fluff... 2004-10-22 03:06:08 - r261 - tamer * SoPyScript/SConstruct: add scons SConstruct file for the scripting node. 2004-10-22 02:54:44 - r260 - tamer * scons/scons-local-0.96.1/SCons/Tool/yacc.py, scons/scons- local-0.96.1/SCons/Platform/irix.py, scons/scons- local-0.96.1/SCons/Tool/default.py, scons/scons- local-0.96.1/SCons/Tool/cc.py, scons/scons- local-0.96.1/SCons/Tool/javah.py, scons/scons- local-0.96.1/SCons/Tool/linkloc.py, scons/scons- local-0.96.1/SCons/Platform/hpux.py, scons/scons- local-0.96.1/SCons/Tool/mslink.py, scons/scons- local-0.96.1/SCons/Script, scons/scons- local-0.96.1/SCons/Taskmaster.py, scons/scons- local-0.96.1/SCons/Tool/as.py, scons/scons- local-0.96.1/SCons/Tool/sgiar.py, scons/scons-local-0.96.1, scons /scons-local-0.96.1/SCons/Platform/cygwin.py, scons/scons- local-0.96.1/SCons/Tool/gs.py, scons/scons- local-0.96.1/SCons/Platform/win32.py, scons/scons- local-0.96.1/SCons/Tool/BitKeeper.py, scons/scons- local-0.96.1/SCons/Tool/suncc.py, scons/scons- local-0.96.1/SCons/Scanner/__init__.py, scons/scons- local-0.96.1/SCons/Tool/ilink32.py, scons/scons-README, scons/scons- local-0.96.1/SCons/Scanner/Prog.py, scons/scons- local-0.96.1/SCons/Tool/javac.py, scons/scons- local-0.96.1/SCons/Tool/dvips.py, scons/scons- local-0.96.1/SCons/Defaults.py, scons/scons-local-0.96.1/SCons, scons/scons-local-0.96.1/SCons/Tool/f77.py, scons/scons- local-0.96.1/SCons/Tool/dmd.py, scons/scons- local-0.96.1/SCons/SConsign.py, scons/scons- local-0.96.1/SCons/Platform/__init__.py, scons/scons- local-0.96.1/SCons/Options/EnumOption.py, scons/scons- local-0.96.1/SCons/Tool/jar.py, scons/scons- local-0.96.1/SCons/Tool/g++.py, scons/scons- local-0.96.1/SCons/Tool/m4.py, scons/scons- local-0.96.1/SCons/Options/ListOption.py, scons/scons- local-0.96.1/SCons/Scanner, scons/scons- local-0.96.1/SCons/dblite.py, scons/scons- local-0.96.1/SCons/Tool/RCS.py, scons/scons- local-0.96.1/SCons/Tool/rmic.py, scons/scons- local-0.96.1/SCons/Tool/JavaCommon.py, scons/scons- local-0.96.1/SCons/Tool/SCCS.py, scons/scons- local-0.96.1/SCons/Platform/darwin.py, scons/scons- local-0.96.1/SCons/Tool/__init__.py, scons/scons- local-0.96.1/SCons/Tool/hpc++.py, scons/scons- local-0.96.1/SCons/Tool/icl.py, scons/scons- local-0.96.1/SCons/Conftest.py, scons/scons- local-0.96.1/SCons/Platform/posix.py, scons/sconsign.py, scons /scons-local-0.96.1/SCons/Options/__init__.py, scons/scons- local-0.96.1/SCons/Tool/mingw.py, scons/scons- local-0.96.1/SCons/Tool/sunlink.py, scons/scons- local-0.96.1/SCons/Tool/hplink.py, scons/scons- local-0.96.1/SCons/Script/__init__.py, scons/scons- local-0.96.1/SCons/Tool/sgicc.py, scons/scons- local-0.96.1/SCons/Platform/aix.py, scons/scons- local-0.96.1/SCons/Tool/CVS.py, scons/scons- local-0.96.1/SCons/Job.py, scons/scons- local-0.96.1/SCons/Scanner/C.py, scons/scons- local-0.96.1/SCons/Tool/PharLapCommon.py, scons/scons- local-0.96.1/SCons/Options/PackageOption.py, scons/scons- local-0.96.1/SCons/Options/BoolOption.py, scons/scons- local-0.96.1/SCons/Tool/f95.py, scons/scons- local-0.96.1/SCons/Builder.py, scons/scons-local-0.96.1/SCons/Tool, scons/scons-local-0.96.1/SCons/Tool/aixc++.py, scons/scons- local-0.96.1/SCons/Tool/fortran.py, scons/scons- local-0.96.1/SCons/Tool/sgic++.py, scons/scons- local-0.96.1/SCons/Sig, scons/scons- local-0.96.1/SCons/Platform/sunos.py, scons/scons- local-0.96.1/SCons/Tool/386asm.py, scons/scons- local-0.96.1/SCons/Optik/option.py, scons/scons- local-0.96.1/SCons/__init__.py, scons/scons- local-0.96.1/SCons/Tool/qt.py, scons/scons- local-0.96.1/SCons/Tool/tar.py, scons/scons- local-0.96.1/SCons/Options, scons/scons- local-0.96.1/SCons/Tool/aixcc.py, scons/scons- local-0.96.1/SCons/Node/Python.py, scons/scons- local-0.96.1/SCons/exitfuncs.py, scons/scons- local-0.96.1/SCons/Tool/sunc++.py, scons/scons- local-0.96.1/SCons/Tool/f90.py, scons/scons- local-0.96.1/SCons/Tool/nasm.py, scons/scons- local-0.96.1/SCons/Node/Alias.py, scons, scons/scons- local-0.96.1/SCons/Tool/zip.py, scons/scons- local-0.96.1/SCons/Node/__init__.py, scons/scons- local-0.96.1/SCons/Sig/TimeStamp.py, scons/scons- local-0.96.1/SCons/Warnings.py, scons/scons- local-0.96.1/SCons/Tool/hpcc.py, scons/scons- local-0.96.1/SCons/Tool/latex.py, scons/scons- local-0.96.1/SCons/Node/FS.py, scons/scons-local-0.96.1/SCons/Optik, scons/scons-local-0.96.1/SCons/Tool/ifort.py, scons/scons- local-0.96.1/SCons/Scanner/Fortran.py, scons/scons- local-0.96.1/SCons/Sig/MD5.py, scons/scons- local-0.96.1/SCons/Tool/pdftex.py, scons/scons- local-0.96.1/SCons/SConf.py, scons/scons- local-0.96.1/SCons/Tool/gcc.py, scons/scons- local-0.96.1/SCons/Optik/option_parser.py, scons/scons- local-0.96.1/SCons/Tool/ar.py, scons/scons- local-0.96.1/SCons/Tool/mslib.py, scons/scons- local-0.96.1/SCons/Tool/c++.py, scons/scons- local-0.96.1/SCons/Platform/os2.py, scons/scons- local-0.96.1/SCons/Tool/gas.py, scons/scons-local-0.96.1/SCons/Node, scons/scons-local-0.96.1/SCons/Executor.py, scons/scons- local-0.96.1/SCons/Scanner/IDL.py, scons/scons- local-0.96.1/SCons/Tool/lex.py, scons/scons- local-0.96.1/SCons/Tool/sunar.py, scons/scons- local-0.96.1/SCons/Tool/tlib.py, scons/scons- local-0.96.1/SCons/Tool/link.py, scons/scons- local-0.96.1/SCons/Tool/masm.py, scons/scons- local-0.96.1/SCons/Scanner/D.py, scons/scons- local-0.96.1/SCons/Errors.py, scons/scons- local-0.96.1/SCons/Tool/Subversion.py, scons/scons- local-0.96.1/SCons/Tool/aixlink.py, scons/scons- local-0.96.1/SCons/Tool/tex.py, scons/scons- local-0.96.1/SCons/Sig/__init__.py, scons/scons- local-0.96.1/SCons/Tool/g77.py, scons/scons- local-0.96.1/SCons/Tool/Perforce.py, scons/scons-LICENSE, scons /scons-local-0.96.1/SCons/Tool/msvc.py, scons/scons- local-0.96.1/SCons/Tool/swig.py, scons/scons- local-0.96.1/SCons/Debug.py, scons/scons- local-0.96.1/SCons/Tool/ifl.py, scons/scons- local-0.96.1/SCons/Tool/dvipdf.py, scons/scons.py, scons/scons- local-0.96.1/SCons/Script/SConscript.py, scons/scons- local-0.96.1/SCons/Tool/cvf.py, scons/scons- local-0.96.1/SCons/Platform, scons/scons- local-0.96.1/SCons/Tool/midl.py, scons/scons- local-0.96.1/SCons/Optik/errors.py, scons/scons- local-0.96.1/SCons/Environment.py, scons/scons- local-0.96.1/SCons/Tool/msvs.py, scons/scons- local-0.96.1/SCons/Tool/bcc32.py, scons/scons- local-0.96.1/SCons/Tool/icc.py, scons/scons- local-0.96.1/SCons/Tool/sgilink.py, scons/scons- local-0.96.1/SCons/Action.py, scons/scons- local-0.96.1/SCons/Util.py, scons/scons- local-0.96.1/SCons/Options/PathOption.py, scons/scons- local-0.96.1/SCons/Tool/aixf77.py, scons/scons- local-0.96.1/SCons/Tool/ilink.py, scons/scons- local-0.96.1/SCons/Tool/pdflatex.py, scons/scons- local-0.96.1/SCons/Tool/gnulink.py, scons/scons- local-0.96.1/SCons/Optik/__init__.py: added scons local package. 2004-10-21 00:40:34 - r258 - tamer * SoPyScript/SoPyScript.cpp: FIXME reg. error handling. 2004-10-21 00:31:40 - r257 - tamer * SoPyScript/glow.py, SoPyScript/example_local.iv, SoPyScript/example_remote.iv, SoPyScript/textscroll.py: add examples to show usage of remote and local file handling. 2004-10-21 00:31:00 - r256 - tamer * SoPyScript/SoPyScript.cpp, SoPyScript/SoPyScript.h: added url and file loading through Python's urllib module. allows to execute scripts located on a web, ftp or gopher server (are there any left yet?) or simply in a file. read the documenation of the urllib module for further information. *** !!! WARNING !!! *** _.--"""""--._ .' '. / \ ; ; | | | | ; ; \ (`'--, ,--'`) / \ \ _ ) ( _ / / ) )(')/ \(')( ( (_ `""` /\ `""` _) \`"-, / \ ,-"`/ `\ / `""` \ /` |/\/\/\/\/\| |\ /| ; |/\/\/\| ; \`-`--`-`/ \ / ',__,' q__p q__p q__p *** !!! WARNING !!! *** Do not run scripts from untrusted sources before inspecting the script itself first! Pivy has the same security model as Microsoft's Internet Exploder -> namely _NONE_! No sandbox, no wizards, no dialog box to warn you, no nothing! Ya have been warned! *** !!! WARNING !!! *** this makes the scripting node feature complete. happy hacking! 2004-10-20 12:13:13 - r254 - tamer * SoPyScript/SoPyScript.h: header cleanup and #ifdef obfuscation for brokenbydesign(tm) we_are_the_m$_and_refusing_to_adhere_to_any_standards_except_for_our_very_own and therefore_do_whatever_we_like_and_pleases_us win32 "platforms"... 2004-10-20 02:28:28 - r253 - tamer * Inventor/events: removed obsolete SoEvent.i. 2004-10-20 02:02:09 - r252 - tamer * setup.py: win32 build fixes. (thx to Gerhard Reitmayr) 2004-10-20 02:01:05 - r251 - tamer * SoPyScript/examin.cpp: removed fluff... 2004-10-20 01:52:29 - r250 - tamer * SoPyScript/SoPyScript.cpp: consistency fix. 2004-10-20 01:50:22 - r249 - tamer * SoPyScript/SoPyScript.cpp: multiple initClass() calling safety belt and SoAudioRenderAction fix. (thx to Gerhard Reitmayr) 2004-10-20 01:31:13 - r248 - tamer * interfaces/soqt.i: reverting changes. PyErr_Clear() returns void... (note to brain: test before you check in!) 2004-10-20 01:24:41 - r247 - tamer * interfaces/soqt.i: academic correctness aka. pedantic mode... 2004-10-20 00:11:20 - r246 - tamer * interfaces/soqt.i: fix for the case where sip/PyQt is not installed. 2004-10-20 00:10:18 - r245 - tamer * interfaces/pivy_common_typemaps.i: cleanup. 2004-10-18 23:31:40 - r243 - tamer * examples/extend/Makefile, examples/extend/shapescale.i: updated example to deal with the new interfaces directory. 2004-10-18 23:29:41 - r242 - tamer * interfaces/soqt.i, interfaces/pivy.i, interfaces/sogtk.i, interfaces/pivy_runtime.i, interfaces/soxt.i, pivy_common_typemaps.i, interfaces/sowin.i, soqt.i, pivy.i, sogtk.i, pivy_runtime.i, interfaces, soxt.i, sowin.i, setup.py, interfaces/pivy_common_typemaps.i: cleanup. moved interface files to their own interfaces directory. 2004-10-18 23:26:56 - r241 - tamer * fake_headers/wchar.h: added fakeheader for wchar.h. 2004-10-18 21:53:13 - r239 - tamer * examples/extend/ShapeScale.cpp, examples/extend/Makefile, examples/extend/README, examples/extend/scale_test.py, examples/extend/ShapeScale.h: updated example. 2004-10-18 20:53:56 - r238 - tamer * examples/extend/python: removed obsolete directory. 2004-10-18 20:53:37 - r237 - tamer * examples/extend/ShapeScale.cpp, examples/extend/python/ShapeScale.cpp, examples/extend/Makefile, examples/extend/README, examples/extend/scale_test.py, examples/extend/ShapeScale.h, examples/extend/python/Makefile, examples/extend/python/README, examples/extend/python/scale_test.py, examples/extend/python/ShapeScale.h, examples/extend/shapescale.i, examples/extend/python/shapescale.i: moved extend example up one hierarchy. 2004-10-18 20:52:16 - r236 - tamer * examples/Mentor/python: removed obsolete directory. 2004-10-18 20:51:31 - r235 - tamer * examples/Mentor/flower.iv, examples/Mentor/05.3.TriangleStripSet.py, examples/Mentor/14.1.FrolickingWords.py, examples/Mentor/17.3.GLFloor.py, examples/Mentor/oak.rgb, examples/Mentor/05.4.QuadMesh.py, examples/Mentor/05.2.IndexedFaceSet.py, examples/Mentor/python/13.6.Calculator.py, examples/Mentor/python/15.2.SliderBox.py, examples/Mentor/python/07.2.TextureCoordinates.py, examples/Mentor/10.3and4.MotifList.py, examples/Mentor/python/13.3.TimeCounter.py, examples/Mentor/03.2.Robot.py, examples/Mentor/python/windmillTower.iv, examples/Mentor/dogDish.iv, examples/Mentor/12.3.AlarmSensor.py, examples/Mentor/14.3.Balance.py, examples/Mentor/diamondRug.rgb, examples/Mentor/python/03.3.Naming.py, examples/Mentor/python/07.3.TextureFunction.py, examples/Mentor/python/12.4.TimerSensor.py, examples/Mentor/python/09.3.Search.py, examples/Mentor/python/star.iv, examples/Mentor/python/16.4.OneWindow.py, examples/Mentor/python/10.3and4.MotifList.py, examples/Mentor/03.1.Molecule.py, examples/Mentor/08.2.UniCurve.py, examples/Mentor/jumpyMan.iv, examples/Mentor/python/03.2.Robot.py, examples/Mentor/python/06.1.Text.py, examples/Mentor/11.1.ReadFile.py, examples/Mentor/10.6.PickFilterTopLevel.py, examples/Mentor/05.6.TransformOrdering.py, examples/Mentor/python/temple.iv, examples/Mentor/08.1.BSCurve.py, examples/Mentor/python/15.3.AttachManip.py, examples/Mentor/python/10.2.setEventCB.py, examples/Mentor/python/07.1.BasicTexture.py, examples/Mentor/06.1.Text.py, examples/Mentor/15.4.Customize.py, examples/Mentor/python/02.1.HelloCone.py, examples/Mentor/10.1.addEventCB.py, examples/Mentor/09.5.GenSph.py, examples/Mentor/python/05.2.IndexedFaceSet.py, examples/Mentor/python/05.5.Binding.py, examples/Mentor/13.3.TimeCounter.py, examples/Mentor/01.1.Windmill.iv, examples/Mentor/python/13.5.Boolean.py, examples/Mentor/07.1.BasicTexture.py, examples/Mentor/09.2.Texture.py, examples/Mentor/python/08.3.BezSurf.py, examples/Mentor/14.2.Editors.py, examples/Mentor/python/diamondRug.rgb, examples/Mentor/12.4.TimerSensor.py, examples/Mentor/python/13.2.ElapsedTime.py, examples/Mentor/12.2.NodeSensor.py, examples/Mentor/python/15.1.ConeRadius.py, examples/Mentor/10.7.PickFilterManip.py, examples/Mentor/16.1.Overlay.py, examples/Mentor/bird.iv, examples/Mentor/python/14.1.FrolickingWords.py, examples/Mentor/python/17.3.GLFloor.py, examples/Mentor/python/17.1.ColorIndex.py, examples/Mentor/python/oak.rgb, examples/Mentor/15.3.AttachManip.py, examples/Mentor/13.6.Calculator.py, examples/Mentor/07.2.TextureCoordinates.py, examples/Mentor/python/16.5.Examiner.py, examples/Mentor/python/16.3.AttachEditor.py, examples/Mentor/python/08.4.TrimSurf.py, examples/Mentor/python/14.3.Balance.py, examples/Mentor/04.1.Cameras.py, examples/Mentor/10.8.PickFilterNodeKit.py, examples/Mentor/python/09.5.GenSph.py, examples/Mentor/16.3.AttachEditor.py, examples/Mentor/eatAtJosies.iv, examples/Mentor/python/16.2.Callback.py, examples/Mentor/python/parkbench.iv, examples/Mentor/python/05.3.TriangleStripSet.py, examples/Mentor/python/13.1.GlobalFlds.py, examples/Mentor/desk.iv, examples/Mentor/duck.iv, examples/Mentor/python/05.4.QuadMesh.py, examples/Mentor/13.2.ElapsedTime.py, examples/Mentor/python/08.1.BSCurve.py, examples/Mentor/15.2.SliderBox.py, examples/Mentor/10.2.setEventCB.py, examples/Mentor/parkbench.iv, examples/Mentor/python/17.2.GLCallback.py, examples/Mentor/python/06.2.Simple3DText.py, examples/Mentor/02.4.Examiner.py, examples/Mentor/python/globe.rgb, examples/Mentor/python/brick.1.rgb, examples/Mentor/05.1.FaceSet.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/16.4.OneWindow.py, examples/Mentor/python/02.2.EngineSpin.py, examples/Mentor/python/02.3.Trackball.py, examples/Mentor/windmillVanes.iv, examples/Mentor/python/11.2.ReadString.py, examples/Mentor/python/flower.iv, examples/Mentor/python/03.1.Molecule.py, examples/Mentor/python/08.2.UniCurve.py, examples/Mentor/python/09.2.Texture.py, examples/Mentor/06.2.Simple3DText.py, examples/Mentor/python/11.1.ReadFile.py, examples/Mentor/temple.iv, examples/Mentor/04.2.Lights.py, examples/Mentor/python/14.2.Editors.py, examples/Mentor/luxo.iv, examples/Mentor/python/12.1.FieldSensor.py, examples/Mentor/13.8.Blinker.py, examples/Mentor/15.1.ConeRadius.py, examples/Mentor/python/eatAtJosies.iv, examples/Mentor/09.1.Print.py, examples/Mentor/python/bookshelf.iv, examples/Mentor/windmillTower.iv, examples/Mentor/python/10.7.PickFilterManip.py, examples/Mentor/python/16.1.Overlay.py, examples/Mentor/python/bird.iv, examples/Mentor/02.1.HelloCone.py, examples/Mentor/17.1.ColorIndex.py, examples/Mentor/python/10.5.SelectionCB.py, examples/Mentor/flowerPath.iv, examples/Mentor/bookshelf.iv, examples/Mentor/python/09.1.Print.py, examples/Mentor/python/01.1.Windmill.iv, examples/Mentor/brick.1.rgb, examples/Mentor/python/04.1.Cameras.py, examples/Mentor/python/05.6.TransformOrdering.py, examples/Mentor/python/flowerPath.iv, examples/Mentor/python/13.4.Gate.py, examples/Mentor/python/dogDish.iv, examples/Mentor/python/15.4.Customize.py, examples/Mentor/13.1.GlobalFlds.py, examples/Mentor/07.3.TextureFunction.py, examples/Mentor/13.7.Rotor.py, examples/Mentor/python/duck.iv, examples/Mentor/python/desk.iv, examples/Mentor/12.1.FieldSensor.py, examples/Mentor/python/04.2.Lights.py, examples/Mentor/sillyFace.rgb, examples/Mentor/star.iv, examples/Mentor/13.4.Gate.py, examples/Mentor/17.2.GLCallback.py, examples/Mentor/python/10.6.PickFilterTopLevel.py, examples/Mentor/10.5.SelectionCB.py, examples/Mentor/python/05.1.FaceSet.py, examples/Mentor/09.4.PickAction.py, examples/Mentor/python/13.7.Rotor.py, examples/Mentor/python/sillyFace.rgb, examples/Mentor/02.2.EngineSpin.py, examples/Mentor/11.2.ReadString.py, examples/Mentor/06.3.Complex3DText.py, examples/Mentor/python/12.3.AlarmSensor.py, examples/Mentor/03.3.Naming.py, examples/Mentor/09.3.Search.py, examples/Mentor/python/luxo.iv, examples/Mentor/python/10.1.addEventCB.py, examples/Mentor/python/13.8.Blinker.py, examples/Mentor/05.5.Binding.py, examples/Mentor/16.5.Examiner.py, examples/Mentor/08.4.TrimSurf.py, examples/Mentor/13.5.Boolean.py, examples/Mentor/08.3.BezSurf.py, examples/Mentor/python/jumpyMan.iv, examples/Mentor/python/06.3.Complex3DText.py, examples/Mentor/globe.rgb, examples/Mentor/python/02.4.Examiner.py, examples/Mentor/python/10.8.PickFilterNodeKit.py, examples/Mentor/02.3.Trackball.py, examples/Mentor/python/12.2.NodeSensor.py, examples/Mentor/16.2.Callback.py, examples/Mentor/python/windmillVanes.iv: moved examples up one hierarchy. 2004-10-18 19:52:22 - r234 - tamer * SoPyScript/Makefile: remove examin binary as well. 2004-10-18 17:58:23 - r233 - tamer * SoPyScript/Makefile: removed fluff... 2004-10-18 16:13:42 - r232 - tamer * SoPyScript/Makefile: cleaned up Makefile. 2004-10-17 23:05:23 - r231 - tamer * soqt.i: check for Py_None. user might want to assign NULL for the toplevel widget in SoQt.init(). 2004-10-17 21:55:03 - r229 - tamer * soqt.i, Inventor/Qt/SoQtRenderArea.i: general in/out typemaps over sip for QEvent and QWidget. completes the PyQt bridge. depends on sip 4.x and a recent PyQt. 2004-10-17 13:14:38 - r228 - tamer * examples/Mentor/python/10.2.setEventCB.py: example just works with SoQt, so do not use SoGui. 2004-10-17 13:13:39 - r227 - tamer * Inventor/Qt/SoQtRenderArea.i: PyQt bridge. approach: check if the sip and qt module are available and use sip's python wrapinstance() call to get hold of a wrapped PyQt QEvent. 2004-10-16 20:22:02 - r225 - tamer * SoPyScript/SoPyScript.cpp, SoPyScript/example.iv: added handler_registry, where the field handlers can be set to call other functions instead of the implictly set default handler_fieldname() function. updated example to show how to use it. 2004-10-15 16:23:41 - r223 - tamer * SoPyScript/example.iv: ref() self object before applying action... 2004-10-15 15:55:26 - r222 - tamer * SoPyScript/SoPyScript.cpp: code style fix. 2004-10-15 15:31:07 - r221 - tamer * SoPyScript/SoPyScript.cpp: remove \r from strings with windows line endings so that PySimple_RunString() is able to fulfill its task. reported by Gerhard Reitmayr. 2004-10-15 14:56:47 - r220 - tamer * SoPyScript/glow.iv, SoPyScript/example.iv: renamed glow.iv to example.iv. 2004-10-15 14:56:03 - r219 - tamer * SoPyScript/glow.iv: issue write action earlier to get a clean output. 2004-10-15 14:48:33 - r218 - tamer * SoPyScript/glow.iv: a more interesting example. 2004-10-15 13:32:07 - r217 - tamer * SoPyScript/SoPyScript.cpp: plugged memory leak. 2004-10-14 15:53:16 - r215 - tamer * SoPyScript/SoPyScript.cpp, SoPyScript/SoPyScript.h, SoPyScript/glow.iv: cleanup, refactoring, robustification, handle_fieldname function handling. 2004-10-14 11:33:18 - r214 - tamer * SoPyScript/SoPyScript.cpp: cosmetics... 2004-10-14 10:36:59 - r213 - tamer * SoPyScript/SoPyScript.cpp, SoPyScript/SoPyScript.h, SoPyScript/glow.iv, SoPyScript/Makefile: removed swig wrapper of SoPyScript == not needed unmaintainable cruft. added SWIG runtime definitions. 2004-10-14 10:35:44 - r212 - tamer * SoPyScript/SoPyScript.i: removed now obsolete file. 2004-10-14 09:25:16 - r211 - tamer * SoPyScript/SoPyScript.cpp, SoPyScript/SoPyScript.h: added copyright stuff. 2004-10-13 13:20:58 - r209 - tamer * SoPyScript/examin.cpp, SoPyScript/glow.iv, SoPyScript/SoPyScript.i, SoPyScript/Makefile: added SWIG interface file for the SoPyScript node and an example. 2004-10-12 23:03:22 - r208 - tamer * SoPyScript, SoPyScript/SoPyScript.cpp, SoPyScript/SoPyScript.h: added preliminary implementation of the scripting node. 2004-10-12 22:20:58 - r207 - tamer * pivy_common_typemaps.i: added swig cpointer.i which defines a class to help in dealing with pointers and references. see http://www.swig.org/Doc1.3/Library.html#Library_nn4 for information in how to use it. specified handling for int, long, float and double datatypes. 2004-10-12 20:16:14 - r205 - tamer * pivy_swigpy.c: removed obsolete file. 2004-10-12 20:15:55 - r204 - tamer * pivy_runtime.i: added pivy_runtime interface file for SWIG runtime library generation. 2004-10-12 20:14:52 - r203 - tamer * setup.py: handling for SWIG 1.3.22 and the SWIG runtime library. SWIG doesn't build a runtime library anymore so a libpivy_runtime.so is created and installed into site-packages as if it's a regular python extension module (in fact, one can import it). the pivy modules are then linked against it by having the runtime_library_path set to python's site-packages directory. possible win32 breakage (did not test and verify; removed old swig_py.dll workaround). macosx definitely will break as it will need a .dylib instead of an .so for that to work (untested and unverified). (there is a distinction made on this platform for shared libraries and runtime extensions). 2004-10-12 20:05:53 - r202 - tamer * soqt.i: SoQt fixes for CVS version. 2004-10-12 20:04:30 - r201 - tamer * Inventor/SbColor.i: added methods SbColor_add, SbColor_sub, SbColor_d_mul, SbColor_mul, SbColor_div, SbColor_eq and SbColor_neq to make operators operator+, operator-, operator*, operator/, operator== and operator!= accessible through pivy for efficiency reasons. 2004-08-10 21:55:48 - r199 - tamer * Inventor/actions/SoGLRenderAction.i, Inventor/Qt/SoQtRenderArea.i, Inventor/nodes/SoCallback.i, Inventor/sensors/SoSensor.i, Inventor/nodes/SoEventCallback.i, Inventor/draggers/SoDragger.i, Inventor/actions/SoCallbackAction.i, Inventor/nodes/SoSelection.i, Inventor/collision/SoIntersectionDetectionAction.i: indentation fixes and output the stack trace if a callback fails. this frees the developer from having to provide try except blocks around the code in callback functions in order to pinpoint the problem. 2004-07-24 03:12:53 - r197 - tamer * Inventor/system/inttypes.h.win32, Inventor/system/inttypes.h.fix, Inventor/fields/SoSubField.h.fix, setup.py, Inventor/engines/SoSubEngine.h.fix, Inventor/nodes/SoSubNode.h.fix, Inventor/engines: added fixes to workaround a bug in SWIG 1.3.21. 2004-07-16 09:26:10 - r195 - tamer * setup.py: windows build fixes: - compile with multithreaded runtime lib (/MT instead of /MD) this removes the dependencies on the vc dlls. Coin therefore needs to be build with /MT, too! - coin2.dll and sowin1.dll will be bundled with the package thx to and fixes by Gerhard Reitmayr. 2004-07-16 01:59:10 - r188 - tamer * Inventor/Win/SoWinCursor.i, sowin.i, Inventor/Win/SoWin.i: removed executable property. 2004-07-16 01:45:22 - r186 - tamer * LICENSE: updated year. 2004-07-16 00:31:20 - r184 - tamer * THANKS: added Eduardo Kortright. 2004-07-09 02:00:07 - r183 - tamer * ChangeLog: Automatic ChangeLog generation 2004-07-08 18:21:55 - r182 - tamer * setup.py: untabified source and added platform specific check for win32 for the pivy_swigpy.c extension. 2004-07-08 04:10:14 - r181 - tamer * setup.py: added sanity check for COIN3DDIR environment variable. 2004-07-08 03:50:12 - r180 - tamer * ChangeLog: Automatic ChangeLog generation 2004-07-08 03:49:38 - r179 - tamer * sowin.i: code style fix. 2004-07-08 03:47:17 - r178 - tamer * Inventor/SbBox3s.i, Inventor/Win, fake_headers/windows.h, Inventor/system/inttypes.h.fix, Inventor/Win/SoWinCursor.i, sowin.i, Inventor/Win/SoWin.i, setup.py, Inventor/system, pivy_common_typemaps.i, pivy_swigpy.c: build system "fixes" for windows... strategy: --------- we need the runtime swig library built as a dll. unfortunately the precompiled SWIG windows distribution does not come with one. so in order to avoid in having to figure out how to build and deploy on the crap called windows myself (and in order to save from a myriad of other braindead windows issues which will cost me even more time and health) i simply let distutils believe the swig runtime sources are just another python extension (i therefore hacked in void init_swigpy() {} into pivy_swigpy.c). additionally in order to not clash with a probably already installed swigpy.pyd i renamed it to pivy_swigpy. i define a PIVY_WIN32 macro in order to fix certain issues such as not provided DLL export macros in the Coin headers and other windows specific braindeadness. another problem: ---------------- regarding the "Python was built with version 6 of Visual Studio and extensions need to be built with the same version of the compiler, but it isn't installed." error that distutils correctly issues, you have 2 options to choose from: 1. easy going: uncomment the check in distutils/msvccompiler.py. pivy works but then avoid or test thoroughly any usage of methods or functions that involve 'FILE *' references. for whatever reason but microstupid figured that they need to change the FILE structure between the 2 releases. 2. the hard but safe way: recompile python with VC7 and use this freshly generated interpreter for pivy. i am not aware of a precompiled python distribution that was created with VC7. in any case you should play safe and recompile Coin with VC7 which works out of the box without any glitch just by using the provided project files. 2004-03-20 03:00:07 - r177 - tamer * ChangeLog: Automatic ChangeLog generation 2004-03-19 18:08:02 - r176 - tamer * fake_headers/qwindowdefs.h: added fake header for native Qt on MacOSX. 2004-03-19 18:07:02 - r175 - tamer * setup.py: fixed file open mode (rw+->r+) 2004-03-19 15:52:25 - r174 - tamer * setup.py: fixes to let it work with Python version < 2.3 2004-03-18 03:00:08 - r173 - tamer * ChangeLog: Automatic ChangeLog generation 2004-03-17 18:17:05 - r172 - tamer * setup.py: fix to include pivy.py, soqt.py etc. modules on installation. 2004-03-17 04:09:08 - r171 - tamer * setup.py: added classifiers and made it PyPI ready. 2004-03-17 03:17:24 - r170 - tamer * ChangeLog: Automatic ChangeLog generation 2004-03-17 03:15:58 - r169 - tamer * docs/ChangeLog.2003: added ChangeLog.2003 for historical reference. 2004-03-17 03:08:52 - r168 - tamer * sogui.py: added sowin support. 2004-03-17 03:08:08 - r167 - tamer * examples/Mentor/python/13.5.Boolean.py, examples/Mentor/python/17.2.GLCallback.py, examples/Mentor/python/10.7.PickFilterManip.py, examples/Mentor/python/15.4.Customize.py, examples/Mentor/python/14.3.Balance.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/python/10.1.addEventCB.py, examples/Mentor/python/13.8.Blinker.py, examples/Mentor/python/15.3.AttachManip.py, examples/Mentor/python/15.2.SliderBox.py, examples/Mentor/python/10.2.setEventCB.py, examples/Mentor/python/14.1.FrolickingWords.py, examples/Mentor/python/17.3.GLFloor.py, examples/Mentor/python/17.1.ColorIndex.py, examples/Mentor/python/03.3.Naming.py, examples/Mentor/python/13.7.Rotor.py, examples/Mentor/python/12.1.FieldSensor.py, examples/Mentor/python/10.8.PickFilterNodeKit.py, examples/Mentor/python/05.5.Binding.py, examples/Mentor/python/10.3and4.MotifList.py: fixes to reflect the new changes regarding autocasting. 2004-03-17 03:00:10 - r166 - tamer * ChangeLog: Automatic ChangeLog generation 2004-03-17 02:59:52 - r165 - tamer * Makefile: removed now obsolete file. 2004-03-17 02:58:47 - r164 - tamer * soqt.i, pivy.i, pivy_common_typemaps.i: - updated to interface against most recent Coin-2 release. tested against CVS version - updated soqt interface file - fixes for windows builds (SWIGEXPORT'ed cast function and added undef's to allow building) - autocasting for methods returning SoNode*. means no direct casts more necessary for callbacks and the like - restructured common reusable parts into pivy_common_typemaps 2004-03-17 02:53:44 - r163 - tamer * build_pivy.py: removed now obsolete file. 2004-03-17 02:53:14 - r162 - tamer * setup.py: added distutils conformant setup.py build tool. 2004-03-17 02:52:42 - r161 - tamer * sowin.i: added swig interface file for SoWin. 2004-03-17 02:51:20 - r160 - tamer * MANIFEST.in: updated to reflect changes. 2004-03-17 02:49:43 - r159 - tamer * Inventor/Qt/SoQtRenderArea.h, Inventor/SbColor.h, Inventor/SoOffscreenRenderer.h, Inventor/SbName.h, Inventor/Xt, Inventor/fields/SoSFFloat.h, Inventor/Qt/SoQtCursor.h, Inventor/SbDict.h, Inventor/SbViewportRegion.h, Inventor/Qt/SoQt.h, Inventor/draggers/SoDragger.h, Inventor/actions/SoAction.h, Inventor/SoType.h, Inventor/SbTime.h, Inventor/fields/SoSFImage.h, Inventor/SbRotation.h, Inventor/events/SoEvent.h, Inventor/SbMatrix.h, Inventor/SbVec2f.h, Inventor/fields/SoMFInt32.h, Inventor/actions/SoWriteAction.h, Inventor/fields/SoField.h, Inventor/SbVec4f.h, Inventor/actions/SoCallbackAction.h, Inventor/SbColor4f.h, Inventor/fields/SoFieldContainer.h, Inventor/Gtk, Inventor/fields/SoSFInt32.h, Inventor/SoInput.h, Inventor/fields/SoMFVec3f.h, Inventor/fields/SoMFString.h, Inventor/fields/SoSFEnum.h, Inventor/SbVec2s.h, Inventor/fields/SoMFColor.h, Inventor/SbDPMatrix.h, Inventor/fields/SoSFColor.h, Inventor/fields/SoSFName.h, Inventor/elements, Inventor/SbViewVolume.h, Inventor/SbVec3d.h, Inventor/SbVec3f.h, Inventor/SbString.h, Inventor/fields/SoSFBool.h, Inventor/SoPath.h, Inventor/fields/SoMFFloat.h, Inventor/collision/SoIntersectionDetectionAction.h, Inventor/fields/SoMFVec2f.h, Inventor/fields/SoMFVec4f.h: removed now obsolete header files. 2004-03-17 02:44:49 - r158 - tamer * Inventor/lists/SoNodeList.i: added swig interface file for SoNodeList to let autocasting work. 2004-03-17 02:43:31 - r157 - tamer * Inventor/sensors/SoIdleSensor.h, Inventor/fields/SoSFVec2f.h, Inventor/nodes/SoCallback.h, Inventor/nodes/SoGroup.h, Inventor/sensors/SoSensor.h, Inventor/fields/SoSFString.h, Inventor/fields/SoSFVec3f.h, Inventor/sensors/SoOneShotSensor.h, Inventor/sensors/SoTimerSensor.h, Inventor/fields/SoSFVec4f.h, Inventor/nodes/SoEventCallback.h, Inventor/sensors/SoFieldSensor.h, Inventor/sensors/SoTimerQueueSensor.h, Inventor/sensors/SoNodeSensor.h, Inventor/sensors/SoAlarmSensor.h, Inventor/sensors/SoPathSensor.h, Inventor/sensors/SoDelayQueueSensor.h, Inventor/nodes/SoSelection.h, Inventor/nodes/SoNode.h, Inventor/fields/SoSFShort.h, Inventor/fields/SoSFRotation.h, Inventor/sensors/SoDataSensor.h, Inventor/nodes/SoCamera.h: removed now obsolete header files. 2004-03-17 02:40:17 - r156 - tamer * Inventor/nodes/SoNode.i: added handling for getByname(SbName, SoNodeList) 2004-02-26 03:00:12 - r155 - tamer * ChangeLog: Automatic ChangeLog generation 2004-02-26 00:18:11 - r154 - tamer * Inventor/SbImage.i: fixed up SbImage class to be consistent with unsigned char * being treated as a string in Python. extended getValue() which based on the z value of the image size automatically determines if it should return an SbVec2s or SbVec3s instance in the result list. 2004-02-25 23:16:50 - r153 - tamer * THANKS: the abc has been invented for a reason... 2004-02-25 23:16:09 - r152 - tamer * THANKS: added Franz Strasser 2004-02-25 23:15:31 - r151 - tamer * Inventor/SoOffscreenRenderer.i: extended getBuffer() method to correct the handling and to allow direct access to the image from the OffscreenRenderer. reported by Franz Strasser. 2004-02-25 23:12:27 - r150 - tamer * Inventor/fields/SoSFImage.i: removed obsolete and commented code. 2004-02-24 03:00:06 - r149 - tamer * ChangeLog: Automatic ChangeLog generation 2004-02-24 00:52:30 - r148 - tamer * Inventor/SbTime.i, Inventor/SbName.i, Inventor/SbVec2s.i, Inventor/SbVec3s.i, Inventor/SbViewportRegion.i, Inventor/SbMatrix.i, Inventor/SbVec3d.i, Inventor/SbVec2f.i, Inventor/SbString.i, Inventor/SbVec4f.i, Inventor/SbColor4f.i, Inventor/SbDPMatrix.i, Inventor/SoPath.i: handling for operator overloading and some fixes. 2004-02-24 00:51:36 - r147 - tamer * Inventor/SbBox2s.i, Inventor/SbBox2d.i, Inventor/SbBox3s.i, Inventor/SbPlane.i, Inventor/SbXfBox3f.i, Inventor/SbBox2f.i, Inventor/SbBox3f.i, Inventor/SbDPPlane.i, Inventor/SbDPRotation.i, Inventor/SbVec2d.i, Inventor/SbVec4d.i: added new classes to be wrapped and handling for operator overloading. 2004-02-24 00:49:38 - r146 - tamer * Inventor/SoNodeKitPath.i: handling for operator overloading. 2004-02-19 03:00:08 - r145 - tamer * ChangeLog: Automatic ChangeLog generation 2004-02-18 07:31:55 - r144 - tamer * Inventor/actions/SoGLRenderAction.i: added support for callbacks in SoGLRenderAction 2004-02-18 04:18:18 - r143 - tamer * Inventor/fields/SoMFVec4f.i, Inventor/SoOffscreenRenderer.i, Inventor/SbColor.i, Inventor/fields/SoSFFloat.i, Inventor/sensors/SoOneShotSensor.i, Inventor/sensors/SoTimerSensor.i, Inventor/SbViewportRegion.i, Inventor/SbVec3s.i, Inventor/SbDict.i, Inventor/fields/SoSFVec4f.i, Inventor/actions/SoAction.i, Inventor/SoType.i, Inventor/SbTime.i, Inventor/sensors/SoPathSensor.i, Inventor/events/SoEvent.i, Inventor/SbMatrix.i, Inventor/actions/SoWriteAction.i, Inventor/SbVec4f.i, Inventor/SbColor4f.i, Inventor/fields/SoFieldContainer.i, Inventor/nodes/SoSelection.i, Inventor/fields/SoMFVec3f.i, Inventor/fields/SoMFString.i, Inventor/SoInput.i, Inventor/nodes/SoCamera.i, Inventor/fields/SoSFEnum.i, Inventor/sensors/SoIdleSensor.i, Inventor/fields/SoSFVec3f.i, Inventor/SbVec2s.i, Inventor/nodes/SoEventCallback.i, Inventor/fields/SoSFName.i, Inventor/sensors/SoAlarmSensor.i, Inventor/SbVec3d.i, Inventor/SbVec3f.i, Inventor/fields/SoSFBool.i, Inventor/SoPath.i, Inventor/fields/SoMFVec2f.i, Inventor/fields/SoSFRotation.i, Inventor/fields/SoSFShort.i, Inventor/Qt/SoQtRenderArea.i, Inventor/SbName.i, Inventor/fields/SoSFVec2f.i, Inventor/nodes/SoGroup.i, Inventor/sensors/SoSensor.i, Inventor/lists, Inventor/Qt/SoQtCursor.i, Inventor/Qt/SoQt.i, Inventor/sensors/SoFieldSensor.i, Inventor/draggers/SoDragger.i, Inventor/sensors/SoNodeSensor.i, Inventor/fields/SoSFImage.i, Inventor/SbRotation.i, Inventor/lists/SoPathList.i, Inventor/SbVec2f.i, Inventor/fields/SoMFInt32.i, Inventor/fields/SoField.i, Inventor/sensors/SoDelayQueueSensor.i, Inventor/actions/SoCallbackAction.i, Inventor/nodes/SoNode.i, Inventor/fields/SoSFInt32.i, Inventor/nodes/SoCallback.i, Inventor/SbImage.i, Inventor/fields/SoSFString.i, Inventor/fields/SoMFColor.i, Inventor/SbDPMatrix.i, Inventor/sensors/SoTimerQueueSensor.i, Inventor/fields/SoSFColor.i, Inventor/SbViewVolume.i, Inventor/SbString.i, Inventor/fields/SoMFFloat.i, Inventor/collision/SoIntersectionDetectionAction.i, Inventor/sensors/SoDataSensor.i: separated SWIG declarations from the Coin headers into their own interface files. this makes it easier to maintain and cope with the changing Coin header files and to possibly integrate Pivy with the Coin main brainch at a later time. improved Sb handling and __call__ methods of fields. bug fixes and cleanup for Coin-2.2. not used by the build system yet which needs to be adapted. 2004-02-17 03:00:06 - r142 - tamer * ChangeLog: Automatic ChangeLog generation 2004-02-16 23:43:46 - r141 - tamer * THANKS: added Martin Wagner. 2004-01-16 03:00:07 - r140 - tamer * ChangeLog: Automatic ChangeLog generation 2004-01-15 08:53:03 - r139 - tamer * MANIFEST.in: updated to reflect the new changes. 2004-01-15 08:50:03 - r138 - tamer * examples/extend/python/README, examples/extend/python/shapescale.i: updated interface file and README to reflect the changes regarding the new pivy_common_typemaps.i. to add new nodekits should now be a lot simpler and less errorprone. 2004-01-15 08:47:59 - r137 - tamer * soqt.i, pivy.i, sogtk.i, soxt.i, pivy_common_typemaps.i: added an interface file that contains the typemaps that are common to all pivy modules. fixed existing interface files to use it. 2004-01-15 03:00:06 - r136 - tamer * ChangeLog: Automatic ChangeLog generation 2004-01-14 16:13:52 - r135 - tamer * examples/extend/python/scale_test.py: removed the unnecessary traceback module import. 2004-01-14 16:01:42 - r134 - tamer * examples/extend/python/scale_test.py: added the missing example file that uses the nodekit. 2004-01-14 15:50:48 - r133 - tamer * THANKS: added Doug Epps 2004-01-14 15:49:57 - r132 - tamer * examples/extend/python/ShapeScale.cpp, examples/extend/python/Makefile, examples/extend/python/README, examples/extend/python/ShapeScale.h, examples/extend, examples/extend/python/shapescale.i, examples/extend/python: added an example that shows how to use swig in order to add a simple NodeKit and build it as an additional module. 2004-01-09 03:00:06 - r131 - tamer * ChangeLog: Automatic ChangeLog generation 2004-01-08 11:59:00 - r130 - tamer * examples/Mentor/python/13.5.Boolean.py, examples/Mentor/python/13.4.Gate.py, examples/Mentor/python/17.2.GLCallback.py, examples/Mentor/python/08.3.BezSurf.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/python/13.2.ElapsedTime.py, examples/Mentor/python/13.6.Calculator.py, examples/Mentor/python/13.3.TimeCounter.py, examples/Mentor/python/11.2.ReadString.py, examples/Mentor/python/08.2.UniCurve.py, examples/Mentor/python/09.2.Texture.py, examples/Mentor/python/11.1.ReadFile.py, examples/Mentor/python/10.6.PickFilterTopLevel.py, examples/Mentor/python/03.3.Naming.py, examples/Mentor/python/17.1.ColorIndex.py, examples/Mentor/python/17.3.GLFloor.py, examples/Mentor/python/14.2.Editors.py, examples/Mentor/python/13.7.Rotor.py, examples/Mentor/python/09.3.Search.py, examples/Mentor/python/12.1.FieldSensor.py, examples/Mentor/python/12.4.TimerSensor.py, examples/Mentor/python/16.5.Examiner.py, examples/Mentor/python/16.4.OneWindow.py, examples/Mentor/python/16.3.AttachEditor.py, examples/Mentor/python/10.3and4.MotifList.py, examples/Mentor/python/08.4.TrimSurf.py, examples/Mentor/python/16.1.Overlay.py, examples/Mentor/python/10.7.PickFilterManip.py, examples/Mentor/python/14.3.Balance.py, examples/Mentor/python/10.5.SelectionCB.py, examples/Mentor/python/10.1.addEventCB.py, examples/Mentor/python/13.8.Blinker.py, examples/Mentor/python/09.5.GenSph.py, examples/Mentor/python/15.3.AttachManip.py, examples/Mentor/python/10.2.setEventCB.py, examples/Mentor/python/16.2.Callback.py, examples/Mentor/python/09.1.Print.py, examples/Mentor/python/13.1.GlobalFlds.py, examples/Mentor/python/04.1.Cameras.py, examples/Mentor/python/05.6.TransformOrdering.py, examples/Mentor/python/08.1.BSCurve.py, examples/Mentor/python/10.8.PickFilterNodeKit.py, examples/Mentor/python/12.2.NodeSensor.py: replaced every occurence of underscore with dot for static method calls. 2004-01-08 03:00:06 - r129 - tamer * ChangeLog: Automatic ChangeLog generation 2004-01-07 21:51:53 - r128 - tamer * examples/Mentor/python/13.4.Gate.py, examples/Mentor/python/13.5.Boolean.py, examples/Mentor/python/17.2.GLCallback.py, examples/Mentor/python/08.3.BezSurf.py, examples/Mentor/python/15.4.Customize.py, examples/Mentor/python/06.2.Simple3DText.py, examples/Mentor/python/04.2.Lights.py, examples/Mentor/python/09.4.PickAction.py, examples/Mentor/python/13.2.ElapsedTime.py, examples/Mentor/python/02.2.EngineSpin.py, examples/Mentor/python/13.6.Calculator.py, examples/Mentor/python/15.1.ConeRadius.py, examples/Mentor/python/15.2.SliderBox.py, examples/Mentor/python/07.2.TextureCoordinates.py, examples/Mentor/python/02.3.Trackball.py, examples/Mentor/python/13.3.TimeCounter.py, examples/Mentor/python/11.2.ReadString.py, examples/Mentor/python/03.1.Molecule.py, examples/Mentor/python/08.2.UniCurve.py, examples/Mentor/python/09.2.Texture.py, examples/Mentor/python/14.1.FrolickingWords.py, examples/Mentor/python/11.1.ReadFile.py, examples/Mentor/python/10.6.PickFilterTopLevel.py, examples/Mentor/python/17.3.GLFloor.py, examples/Mentor/python/17.1.ColorIndex.py, examples/Mentor/python/14.2.Editors.py, examples/Mentor/python/13.7.Rotor.py, examples/Mentor/python/05.1.FaceSet.py, examples/Mentor/python/07.3.TextureFunction.py, examples/Mentor/python/12.4.TimerSensor.py, examples/Mentor/python/12.1.FieldSensor.py, examples/Mentor/python/16.4.OneWindow.py, examples/Mentor/python/16.5.Examiner.py, examples/Mentor/python/10.3and4.MotifList.py, examples/Mentor/python/16.3.AttachEditor.py, examples/Mentor/python/08.4.TrimSurf.py, examples/Mentor/python/10.7.PickFilterManip.py, examples/Mentor/python/16.1.Overlay.py, examples/Mentor/python/03.2.Robot.py, examples/Mentor/python/06.1.Text.py, examples/Mentor/python/12.3.AlarmSensor.py, examples/Mentor/python/14.3.Balance.py, examples/Mentor/python/10.5.SelectionCB.py, examples/Mentor/python/10.1.addEventCB.py, examples/Mentor/python/13.8.Blinker.py, examples/Mentor/python/15.3.AttachManip.py, examples/Mentor/python/10.2.setEventCB.py, examples/Mentor/python/16.2.Callback.py, examples/Mentor/python/09.1.Print.py, examples/Mentor/python/07.1.BasicTexture.py, examples/Mentor/python/02.1.HelloCone.py, examples/Mentor/python/05.3.TriangleStripSet.py, examples/Mentor/python/06.3.Complex3DText.py, examples/Mentor/python/02.4.Examiner.py, examples/Mentor/python/13.1.GlobalFlds.py, examples/Mentor/python/04.1.Cameras.py, examples/Mentor/python/05.4.QuadMesh.py, examples/Mentor/python/05.6.TransformOrdering.py, examples/Mentor/python/08.1.BSCurve.py, examples/Mentor/python/05.2.IndexedFaceSet.py, examples/Mentor/python/10.8.PickFilterNodeKit.py, examples/Mentor/python/05.5.Binding.py: updated the examples to make use of the new SoGui proxy. 2004-01-07 21:50:43 - r127 - tamer * pivy.i: desoguinated pivy.i. 2004-01-07 21:50:11 - r126 - tamer * build_pivy.py: support for building the different sogui bindings if available. if pivy should not build any gui bindings the --without-sogui option can be specified. 2004-01-07 19:47:28 - r125 - tamer * sogui.py: removed the fishyness of the previous solution... 2004-01-04 03:00:06 - r124 - tamer * ChangeLog: Automatic ChangeLog generation 2004-01-03 14:31:14 - r123 - tamer * soqt.i, sogtk.i, soxt.i: 2004 is the new year for the (c) header. small fix for soxt.i 2004-01-03 14:30:05 - r122 - tamer * sogui.py: finally, the missing link and the last step for the deSoGUInation process. created an SoGui proxy that routes the calls through to the real underlying binding. i.e. from now on it is possible to write gui agnostic programs by solely referring to an SoGui... naming scheme and programs not depending on any toolkit dependent behaviour will just run with any binding installed. there are 2 variables with a special meaning which have to be specified before the actual import of the gui: - SOGUI_DEBUG = 1 # set this to get debug output - SOGUI_BINDING = "SoQt" # set this 2 override the binding to your liking # default behaviour is autodetect in this order: # SoQt -> SoXt -> SoGtk # Could be used for any other binding not currently # known ootb if it contains the same class hierarchy. pivy-0.6.5/docs/ruby-inventor.txt0000644000175000017500000000463113606712377015601 0ustar kurtkurtJohn K. Grytten reported that it is possible to use Coin3d with Ruby by using pivy. Pretty cool! :) thx, John! Here are his instructions: RubyInventor using Pivy ----------------------- Yes, you can use Coin with Ruby. And no, you can't just yet install a nicely wrapped up package with InstallShield for Windows with everything needed! But if you don't mind using an highly experimental and creative setup you may get a glimpse of tomorrows' defacto standard scientific visualization and simulation environment today(!) Surely it has great potential for prototyping stuff that can later be implemented as NodeKits etc.. Ok, that's the vision anyway.. now to reality: Hopefully it will be possible to get rid of the python dependency, but that'll probably require some substantial work as one would like to use the latest SWIG versions - but then new low-level details concerning the Coin include files will probably have to be sorted out again (a lot can be learned from pivy of course) and also Ruby specific conversions must be worked out. The following setup have only been tested on Debian GNU/Linux so far, but it works ok (try it in irb - Interactive Ruby!). Now, let's hack it all together in 1-2-3... First step: install pivy module for Python: ------------------------------------------- You need this: pivy from cvs coin1 soqt cvs http://prdownloads.sourceforge.net/swig/swig-1.3.13.tar.gz Install pivy.py, pivy.pyc and pivycmodule.so manually to /usr/lib/python2.1 Second step: install Ruby/Python extension for Ruby: ---------------------------------------------------- http://www.goto.info.waseda.ac.jp/~fukusima/ruby/python/doc/ Please check that extconf.rb detects the correct python module directory (you may have more than one python installation) Third step: ExaminerViewer in Ruby: ----------------------------------- #!/usr/bin/env ruby require 'python' require 'python/pivy' py = Py.pivy myWindow = py.SoQt_init(ARGV[0].to_s) if myWindow == nil raise "could not open window" end root = py.SoSeparator.new root.ref myMaterial = py.SoMaterial.new mf = py.SoMFColor.new mf.setValue(1.0,0.0,1.0) myMaterial.getField('diffuseColor').copyFrom mf mf.setValue(1.0,0.0,1.0) root.addChild(myMaterial) root.addChild(py.SoCube.new) myViewer = py.SoQtExaminerViewer.new(myWindow) myViewer.setSceneGraph(root) myViewer.setTitle("Examiner Viewer") myViewer.show py.SoQt_show(myWindow) py.SoQt_mainLoop pivy-0.6.5/docs/ChangeLog.20060000644000175000017500000002254713606712377014363 0ustar kurtkurt2006-08-21 13:43:53 Rev 602 reitmayr * Inventor/SbVec2s.i, tests/pivy_tests.py, Inventor/SbVec2d.i, Inventor/SbVec3s.i, Inventor/SbVec3d.i, Inventor/SbVec2f.i, Inventor/SbVec4d.i, Inventor/SbVec3f.i, Inventor/SbVec4f.i, Inventor/SbDPMatrix.i: added iterators two vector types and fixed vec * matrix multiplication (where possible :) 2006-08-18 09:01:33 Rev 600 reitmayr * pivy/__init__.py: specify Python dynamic library loading flags to enable Coin dynamic node loading from within Pivy 2006-08-14 10:27:03 Rev 598 reitmayr * Inventor/nodes/SoGroup.i, tests/pivy_tests.py: some more operators for SoGroup plus unit tests 2006-08-10 13:46:19 Rev 596 reitmayr * tests/pivy_tests.py: added unit test for new SoGroup operators 2006-08-10 13:17:30 Rev 595 reitmayr * Inventor/nodes/SoGroup.i: added iterator interface for group to simplify use in list comprehensions etc 2006-07-28 17:06:32 Rev 593 tamer * Inventor/sensors/SoSensorManager.i: added support for SoSensorManager.isTimerSensorPending(). (reported by Frode ?ijord) 2006-07-05 16:30:57 Rev 591 tamer * tests/pivy_tests.py: small consistency fix for -v invocation. 2006-04-14 11:40:32 Rev 589 tamer * setup.py: usage of os.path.join() for win32 case to remedy path problems. 2006-03-17 09:51:48 Rev 587 reitmayr * pivy/__init__.py, Inventor/nodekits/SoBaseKit.i, tests/pivy_tests.py: * added initialization for nodekits and interaction nodes at module load time. * reordered tests in SoBaseKit.__getattr__ to make useage of nodekits simpler. now it will actually return the node not the SoSFNode field underlying a part. This allows the following syntax to work: shape.appearance.material.diffuseColor = (1,0,0) * added test cases for all these things 2006-03-05 14:19:01 Rev 585 tamer * examples/Mentor/12.3.AlarmSensor.py, examples/SoPyScript/example.iv, examples/Mentor/12.4.TimerSensor.py, examples/SoPyScript/textscroll.py, examples/Mentor/12.2.NodeSensor.py, examples/Mentor/10.3and4.MotifList.py: update examples: remove manual cast() invocations due to Sensor autocasting in place. 2006-03-05 14:17:26 Rev 584 tamer * Inventor/sensors/SoAlarmSensor.i, Inventor/sensors/SoPathSensor.i, Inventor/sensors/SoIdleSensor.i, Inventor/sensors/SoOneShotSensor.i, Inventor/sensors/SoSensor.i, Inventor/sensors/SoTimerSensor.i, Inventor/sensors/SoDelayQueueSensor.i, Inventor/sensors/SoFieldSensor.i, Inventor/sensors/SoNodeSensor.i, Inventor/sensors/SoTimerQueueSensor.i, Inventor/sensors/SoDataSensor.i, NEWS: autocasting for SoSensor derived nodes through providing a 3rd item in the data tuple added in the corresponding constructors of each SoSensor derived node. using this information our own sensor callback handler can then now lookup and construct the right SWIG type. 2006-03-05 14:13:20 Rev 583 tamer * Inventor/fields/SoFieldContainer.i: small codestyle fixes. 2006-03-03 13:36:00 Rev 581 tamer * docs/ChangeLog.2005: added ChangeLog.2005 for historical reference. 2006-03-02 02:29:14 Rev 579 tamer * THANKS: added Bill Hart. 2006-03-02 02:28:50 Rev 578 tamer * Inventor/SbString.i: ignore SbString::vsprintf() as it causes C++ compile error on Ubuntu 64 bit with gcc-3.4 and gcc-4.0.2. very likely to affect other systems as well. reported by Bill Hart. 2006-03-01 10:53:16 Rev 576 tamer * setup.py: win32 build fix for build pathes that contain spaces such as "c:\Documents and Settings\...". reported and fix provided by Alessandro Iob. 2006-03-01 09:17:52 Rev 575 tamer * interfaces/soqt.i, interfaces/sogtk.i, interfaces/coin.i, interfaces/simvoleon.i, interfaces/soxt.i: activate autodoc'ing SWIG feature and add module parameter to the %import pivy directive to let pivy work as a package with SWIG 1.3.28. 2006-03-01 09:15:07 Rev 574 tamer * Inventor/fields/SoFieldContainer.i: small code style fix and removal of SbName(). should be rewritten in plain C for a possible performance improvement as this code section get invoked on every field access... 2006-03-01 09:12:00 Rev 573 tamer * Inventor/SbViewVolume.i: do not depend on SWIG internals as they tend to change... 2006-02-21 04:44:00 Rev 571 tamer * NEWS: update NEWS items. 2006-02-21 04:30:18 Rev 570 tamer * examples/Mentor/05.3.TriangleStripSet.py, examples/Mentor/14.1.FrolickingWords.py, interfaces/coin.i, examples/Mentor/02.4.Examiner.py, examples/Mentor/17.3.GLFloor.py, examples/Mentor/05.4.QuadMesh.py, examples/Mentor/05.1.FaceSet.py, examples/Mentor/05.2.IndexedFaceSet.py, examples/Mentor/16.4.OneWindow.py, examples/Mentor/10.3and4.MotifList.py, examples/Mentor/03.2.Robot.py, examples/Mentor/12.3.AlarmSensor.py, examples/Mentor/06.2.Simple3DText.py, examples/Mentor/14.3.Balance.py, interfaces/simvoleon.i, examples/Mentor/04.2.Lights.py, SoPyScript/SConstruct, examples/Mentor/13.8.Blinker.py, examples/Mentor/15.1.ConeRadius.py, examples/Mentor/09.1.Print.py, interfaces/pivy_common_typemaps.i, examples/Mentor/03.1.Molecule.py, examples/Mentor/08.2.UniCurve.py, p ackaging/macosx/Pivy.pkg/Contents/Resources/English.lproj/Welcome.rtf , examples/Mentor/02.1.HelloCone.py, interfaces/soqt.i, pivy/gui/__init__.py, tests/pivy_tests.py, examples/Mentor/11.1.ReadFile.py, examples/Mentor/10.6.PickFilterTopLevel.py, examples/extend/shapescale.i, pivy/sogui.py, examples/SoPyScript/SConstruct, examples/Mentor/17.1.ColorIndex.py, examples/Mentor/05.6.TransformOrdering.py, examples/Mentor/08.1.BSCurve.py, examples/examiner_embed.py, pivy/__init__.py, SoPyScript/SoPyScript.cpp, examples/Mentor/06.1.Text.py, examples/Mentor/15.4.Customize.py, LICENSE, docs/license.template, examples/Mentor/10.1.addEventCB.py, setup.py, examples/Mentor/09.5.GenSph.py, examples/Mentor/13.3.TimeCounter.py, examples/Mentor/07.1.BasicTexture.py, examples/Mentor/09.2.Texture.py, interfaces/sogtk.i, packaging/macosx/Welcome.rtf, examples/Mentor/13.1.GlobalFlds.py, examples/Mentor/07.3.TextureFunction.py, examples/Mentor/13.7.Rotor.py, examples/Mentor/14.2.Editors.py, examples/Mentor/12.1.FieldSensor.py, examples/Mentor/12.4.TimerSensor.py, interfaces/soxt.i, examples/Mentor/12.2.NodeSensor.py, examples/extend/SConstruct, examples/Mentor/13.4.Gate.py, examples/Mentor/17.2.GLCallback.py, examples/Mentor/10.7.PickFilterManip.py, examples/Mentor/16.1.Overlay.py, SoPyScript/SoPyScript.h, examples/Mentor/10.5.SelectionCB.py, examples/Mentor/09.4.PickAction.py, examples/Mentor/15.3.AttachManip.py, examples/Mentor/13.6.Calculator.py, examples/Mentor/02.2.EngineSpin.py, examples/Mentor/07.2.TextureCoordinates.py, examples/Mentor/11.2.ReadString.py, examples/Mentor/06.3.Complex3DText.py, examples/Mentor/03.3.Naming.py, examples/Mentor/04.1.Cameras.py, examples/Mentor/09.3.Search.py, examples/Mentor/10.8.PickFilterNodeKit.py, examples/Mentor/05.5.Binding.py, examples/Mentor/16.5.Examiner.py, interfaces/sowin.i, examples/Mentor/16.3.AttachEditor.py, examples/Mentor/08.4.TrimSurf.py, examples/Mentor/13.5.Boolean.py, examples/Mentor/08.3.BezSurf.py, examples/extend/scale_test.py, examples/Mentor/13.2.ElapsedTime.py, examples/Mentor/15.2.SliderBox.py, examples/Mentor/02.3.Trackball.py, examples/Mentor/10.2.setEventCB.py, examples/Mentor/16.2.Callback.py: update copyright header. 2006-02-21 04:15:44 Rev 569 tamer * Inventor/collision/SoIntersectionDetectionAction.i: cut & paste error fix. 2006-02-21 03:55:54 Rev 568 tamer * Inventor/fields/SoMFVec4f.i, Inventor/actions/SoGLRenderAction.i, Inventor/Qt/SoQtRenderArea.i, Inventor/fields/SoSFImage3.i, Inventor/sensors/SoSensor.i, Inventor/SbVec3s.i, Inventor/draggers/SoDragger.i, Inventor/fields/SoMFUShort.i, Inventor/fields/SoSFImage.i, Inventor/SbRotation.i, Inventor/fields/SoMFInt32.i, Inventor/SbVec4d.i, Inventor/SoSceneManager.i, Inventor/SbVec4f.i, Inventor/actions/SoCallbackAction.i, Inventor/nodes/SoSelection.i, Inventor/fields/SoMFEnum.i, Inventor/fields/SoMFString.i, Inventor/fields/SoMFVec3f.i, Inventor/sensors/SoSensorManager.i, Inventor/nodes/SoCallback.i, Inventor/SbImage.i, Inventor/misc/SoBase.i, Inventor/SbDPRotation.i, Inventor/nodes/SoEventCallback.i, Inventor/fields/SoMFName.i, Inventor/fields/SoMFUInt32.i, Inventor/fields/SoMFBool.i, Inventor/SbViewVolume.i, Inventor/SbVec3d.i, Inventor/fields/SoMFShort.i, Inventor/SbVec3f.i, Inventor/fields/SoMFVec2f.i, Inventor/fields/SoMFFloat.i, Inventor/collision/SoIntersectionDetectionAction.i: memleak audit and robustifcation effort. replace usage of PyTuple_SetItem with Py_BuildValue. fixes issue19. 2006-02-21 03:54:11 Rev 567 tamer * Inventor/SbMatrix.i, Inventor/SbDPMatrix.i: memleak audit and robustifcation effort. replace usage of PyTuple_SetItem with Py_BuildValue. PySequence_GetItem() returns a new reference! result if not Py_DECREF'ed appropriately: memory outbursts... fixes issue19. 2006-02-21 03:51:12 Rev 566 tamer * interfaces/pivy_common_typemaps.i: memleak audit and robustifcation effort. replace usage of PyTuple_SetItem with Py_BuildValue. fixes issue19. 2006-02-21 03:47:06 Rev 565 tamer * THANKS: added Alessandro Iob. 2006-02-21 03:44:46 Rev 564 tamer * examples/Mentor/12.2.NodeSensor.py: updated example to reflect getFieldName change. 2006-02-21 03:44:12 Rev 563 tamer * Inventor/fields/SoFieldContainer.i: fix memleak and make getFieldName more pythonic through returning either a PySring or None. pivy-0.6.5/setup_old.py0000644000175000017500000005743613606712377013650 0ustar kurtkurt#!/usr/bin/env python ### # Copyright (c) 2002-2009 Systems in Motion # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ### # Pivy distutils setup script. # """Pivy is a Coin binding for Python. Coin is a high-level 3D graphics library with a C++ Application Programming Interface. Coin uses scene-graph data structures to render real-time graphics suitable for mostly all kinds of scientific and engineering visualization applications. """ from __future__ import print_function ### # Setup file for the Pivy distribution. # import glob, os, shutil, subprocess, sys from distutils.command.build import build from distutils.command.clean import clean from distutils.command.install import install from distutils.core import setup from distutils.extension import Extension from distutils import sysconfig # if we are on a Gentoo box salute the chap and output stuff in nice colors # Gentoo is Python friendly, so be especially friendly to them! ;) try: from portage.output import green, blue, turquoise, red, yellow print(red("Oooh, it's a Gentoo! Nice nice! tuhtah salutes you! :)")) except: try: from colorama import Fore, Style def red(text): return Fore.RED + text + Style.RESET_ALL def green(text): return Fore.GREEN + text + Style.RESET_ALL def blue(text): return Fore.BLUE + text + Style.RESET_ALL def turquoise(text): return Fore.CYAN + text + Style.RESET_ALL def yellow(text): return Fore.YELLOW + text + Style.RESET_ALL except: def red(text): return text def green(text): return text def blue(text): return text def turquoise(text): return text def yellow(text): return text PIVY_CLASSIFIERS = """\ Development Status :: 5 - Production/Stable Intended Audience :: Developers License :: OSI Approved :: BSD License Operating System :: MacOS :: MacOS X Operating System :: Microsoft :: Windows Operating System :: Unix Programming Language :: Python Topic :: Multimedia :: Graphics Topic :: Multimedia :: Graphics :: 3D Modeling Topic :: Multimedia :: Graphics :: 3D Rendering Topic :: Software Development :: Libraries :: Python Modules """ __dir_name__ = os.path.dirname(__file__) pivy_dir = os.path.join(__dir_name__, "pivy") sys.path.append(pivy_dir) import pivy_meta PIVY_VERSION = pivy_meta.__version__ sys.path.pop(-1) class pivy_build(build): PIVY_SNAKES = r""" _____ .-'` '. __/ __ \ / \ / \ | ___ | /`\| /`\| | .-' /^\/^\ | \(/| \(/| |/ |) |)| .-\__/ \__/ | \_/\_/__..._ _...---'-. / _ '. /, , \ '| `\ \ | )) )) /`| \ `. /) /) | | ` ` .' | `-._ / \ .' | ,_ `--....-' `. __.' , | / /`'''` `'-.____.-' / /, | / / `. `-.-` .' \ / / | `-.__.'| \ | | |-. _.._| | / | | `'. .-''`` | | | / | `-. .'` / / / | | '. /` / / | / |\ \ / | | | | /\ | || | / | / '. | |\ \ | / | '. / \ `. '. / | \ '---'/ \ '. `-./ \ '. / '. `'. `-._ '.__ '-._____.'--'''''--. '-. `'--._ `.__ `';----` \ `-. `-. `.''``` ; `'-..,_ `-. `'-. / '. '. '. .' ~~~ HISSSSSSSSSS ~~~ Welcome to Pivy %s! Building Pivy has never been so much fun! """ % PIVY_VERSION pivy_header_include = """\ #ifdef __PIVY__ %%include %s #endif """ SWIG = ((sys.platform == "win32" and "swig.exe") or "swig") SWIG_SUPPRESS_WARNINGS = "-w302,306,307,312,314,325,361,362,467,389,503,509,510" if sys.version_info.major < 3: SWIG_PARAMS = "-c++ -python -includeall -modern -D__PIVY__ " + \ "-I. -Ifake_headers -I\"%s\" %s -o %s_wrap.cpp " + \ "interfaces" + os.sep + "%s.i" else: SWIG_PARAMS = "-c++ -python -includeall -modern -py3 -D__PIVY__ " + \ "-I. -Ifake_headers -I\"%s\" %s -o %s_wrap.cpp " + \ "interfaces" + os.sep + "%s.i" SOGUI = ['soqt', 'soxt', 'sogtk', 'sowin'] MODULES = {} MODULES['coin'] = ['_coin', 'coin-config', 'pivy.', "coin"] MODULES['soqt'] = ['gui._soqt', 'soqt-config', 'pivy.gui.', "soqt"] if sys.version_info.major < 3: MODULES['simvoleon'] = ['_simvoleon', 'simvoleon-config', 'pivy.', "simvoleon"] MODULES['soxt'] = ['gui._soxt', 'soxt-config', 'pivy.gui.', "soxt"] MODULES['sogtk'] = ['gui._sogtk', 'sogtk-config', 'pivy.gui.', "sogtk"] MODULES['sowin'] = ['gui._sowin', 'sowin-config', 'pivy.gui.', "sowin"] if sys.version_info.major < 3: MODULES['coin'][3] = 'coin2' MODULES['soqt'][3] = 'soqt2' SUPPORTED_SWIG_VERSIONS = ['1.3.31', '1.3.33', '1.3.35', '1.3.40'] SWIG_VERSION = "" SWIG_COND_SYMBOLS = [] CXX_INCS = "-Iinterfaces " CXX_LIBS = "" ext_modules = [] py_modules = ['pivy.quarter.ContextMenu', 'pivy.quarter.ImageReader', 'pivy.quarter.QuarterWidget', 'pivy.quarter.SensorManager', 'pivy.quarter.SignalThread', 'pivy.quarter.devices.DeviceHandler', 'pivy.quarter.devices.DeviceManager', 'pivy.quarter.devices.KeyboardHandler', 'pivy.quarter.devices.MouseHandler', 'pivy.quarter.eventhandlers.DragDropHandler', 'pivy.quarter.eventhandlers.EventHandler', 'pivy.quarter.eventhandlers.EventManager', 'pivy.quarter.plugins.designer.python.PyQuarterWidgetPlugin', 'pivy.utils', 'pivy.graphics.'] if sys.version_info.major < 3: py_modules = ['pivy.sogui'] + py_modules def do_os_popen(self, cmd): "return the output of a command in a single line" fd = os.popen(cmd) lines = fd.readlines() for i in range(len(lines)): lines[i] = lines[i].strip() lines = " ".join(lines) fd.close() return lines def check_cmd_exists(self, cmd): "return the path of the specified command if it exists" print(blue("Checking for %s..." % cmd)) for path in os.environ['PATH'].split(os.path.pathsep): if os.path.exists(os.path.join(path, cmd)): print(blue("'%s'" % os.path.join(path, cmd))) return 1 print(red("not found.")) return 0 def check_python_version(self): "check the Python version" print(blue("Python version...%s" % sys.version.split(" ")[0])) if int(sys.version[0]) < 2: print(red("Pivy only works with Python versions >= 2.0.")) sys.exit(1) def check_coin_version(self): "check the Coin version" if sys.platform == "win32": return if not self.check_cmd_exists("coin-config"): sys.exit(1) print(blue("Coin version...")) version = self.do_os_popen("coin-config --version") print(blue("%s" % version)) if not version.startswith('3'): print(yellow("** Warning: Pivy has only been tested with Coin " "versions Coin-dev 3.")) def check_simvoleon_version(self): "return if SIMVoleon is available and check the version" if sys.platform == "win32" or not self.check_cmd_exists("simvoleon-config"): self.MODULES.pop('simvoleon', None) return False print(blue("SIMVoleon version...")) version = self.do_os_popen("simvoleon-config --version") print(blue("%s" % version)) if not version.startswith('2.0'): print(yellow("** Warning: Pivy has only been tested with SIMVoleon " "versions 2.0.x.")) return True def check_gui_bindings(self): "check for availability of SoGui bindings and removes the not available ones" if sys.platform == "win32": self.MODULES.pop('soxt', None) self.MODULES.pop('sogtk', None) print(blue("Checking for SoWin...")) if not os.path.exists(os.path.join(os.getenv("COINDIR"), "include", "Inventor", "Win", "SoWin.h")): self.MODULES.pop('sowin', None) print(red("COINDIR\\include\\Inventor\\Win\\SoWin.h not found. (SoWin bindings won't be built)")) print(blue("Checking for QTDIR environment variable...")) if os.getenv("QTDIR"): print(blue(os.getenv("QTDIR"))) else: self.MODULES.pop('soqt', None) print(red("not set. (SoQt bindings won't be built)")) else: for gui in self.SOGUI: if gui not in self.MODULES: continue gui_config_cmd = self.MODULES[gui][1] if not self.check_cmd_exists(gui_config_cmd): self.MODULES.pop(gui, None) else: print(blue("Checking for %s version..." % gui)) version = self.do_os_popen("%s --version" % gui_config_cmd) print(blue("%s" % version)) def get_coin_features(self): "set the global variable SWIG_COND_SYMBOLS needed for conditional " + \ "wrapping" if sys.platform == "win32": return print(blue("Checking for Coin features...")) if not os.system("coin-config --have-feature 3ds_import"): self.SWIG_COND_SYMBOLS.append("-DHAVE_FEATURE_3DS_IMPORT") print(green("3ds import ")) if not os.system("coin-config --have-feature vrml97"): self.SWIG_COND_SYMBOLS.append("-DHAVE_FEATURE_VRML97") print(green("vrml97 ")) if not os.system("coin-config --have-feature sound"): self.SWIG_COND_SYMBOLS.append("-DHAVE_FEATURE_SOUND") print(green("sound ")) if not os.system("coin-config --have-feature superglu"): self.SWIG_COND_SYMBOLS.append("-DHAVE_FEATURE_SUPERGLUE") print(green("superglu ")) if not os.system("coin-config --have-feature threads"): self.SWIG_COND_SYMBOLS.append("-DHAVE_FEATURE_THREADS") print(green("threads ")) if not os.system("coin-config --have-feature threadsafe"): self.SWIG_COND_SYMBOLS.append("-DHAVE_FEATURE_THREADSAFE") print(green("threadsafe ")) print() def check_swig_version(self, swig): "check for the swig version" global SWIG_VERSION if not self.check_cmd_exists(swig): # on some systems there is only a swig3.0 so check for this and # set SWIG to "swig3.0" swig = "swig3.0" if not self.check_cmd_exists(swig): sys.exit(1) else: self.SWIG = swig print(blue("Checking for SWIG version...")) p = subprocess.Popen("%s -version" % swig, shell=True, stdout=subprocess.PIPE) version = str(p.stdout.readlines()[1].strip()).split(" ")[2] p.stdout.close() print(blue("%s" % version)) SWIG_VERSION = version if not version in self.SUPPORTED_SWIG_VERSIONS: print(yellow("Warning: Pivy has only been tested with the following " + \ "SWIG versions: %s." % " ".join(self.SUPPORTED_SWIG_VERSIONS))) def copy_and_swigify_headers(self, includedir, dirname, files): """Copy the header files to the local include directories. Add an #include line at the beginning for the SWIG interface files...""" for file in files: if not os.path.isfile(os.path.join(dirname, file)): continue if file[-2:] == ".i": file_i = os.path.join(dirname, file) file_h = os.path.join(dirname, file)[:-2] + ".h" if (not os.path.exists(file_h) and os.path.exists(os.path.join(includedir, file_h))): shutil.copyfile(os.path.join(includedir, file_h), file_h) sys.stdout.write(' ' + turquoise(file_h)) fd = open(file_h, 'r+') contents = fd.readlines() ins_line_nr = -1 for line in contents: ins_line_nr += 1 if line.find("#include ") != -1: break if ins_line_nr != -1: contents.insert(ins_line_nr, self.pivy_header_include % (file_i)) fd.seek(0) fd.writelines(contents) else: print(blue("[") + red("failed") + blue("]")) sys.exit(1) fd.close # fixes for SWIG 1.3.21 and upwards # (mostly workarounding swig's preprocessor "function like macros" # preprocessor bug when no parameters are provided which then results # in no constructors being created in the wrapper) elif file[-4:] == ".fix": sys.stdout.write(' ' + red(os.path.join(dirname, file)[:-4])) shutil.copyfile(os.path.join(dirname, file), os.path.join(dirname, file)[:-4]) # had to introduce this because windows is a piece of crap elif sys.platform == "win32" and file[-6:] == ".win32": sys.stdout.write(' ' + red(os.path.join(dirname, file)[:-6])) shutil.copyfile(os.path.join(dirname, file), os.path.join(dirname, file)[:-6]) def pivy_configure(self): "configure Pivy" print(turquoise(self.PIVY_SNAKES)) print(blue("Platform...%s" % sys.platform)) self.check_python_version() self.check_swig_version(self.SWIG) self.check_coin_version() self.get_coin_features() if self.SOGUI: self.check_gui_bindings() if 'simvoleon' in self.MODULES and self.check_simvoleon_version(): if sys.platform == "win32": INCLUDE_DIR = os.getenv("SIMVOLEONDIR") + "\\include" else: INCLUDE_DIR = self.do_os_popen("simvoleon-config --includedir") sys.stdout.write(blue("Preparing") + green(" VolumeViz ") + blue("headers:")) dir_gen = os.walk("VolumeViz", INCLUDE_DIR) for _dir, _, names in dir_gen: self.copy_and_swigify_headers(INCLUDE_DIR, _dir, names) print(green(".")) if sys.platform == "win32": INCLUDE_DIR = os.path.join(os.getenv("COINDIR"), "include") else: INCLUDE_DIR = self.do_os_popen("coin-config --includedir") sys.stdout.write(blue("Preparing") + green(" Inventor ") + blue("headers:")) dir_gen = os.walk("Inventor", INCLUDE_DIR) for _dir, _, names in dir_gen: self.copy_and_swigify_headers(INCLUDE_DIR, _dir, names) print(green(".")) def swig_generate(self): "build all available modules" quote = lambda s : '"' + s + '"' for module in self.MODULES: module_name = self.MODULES[module][0] config_cmd = self.MODULES[module][1] module_pkg_name = self.MODULES[module][2] mod_hack_name = self.MODULES[module][3] mod_out_prefix = module_pkg_name.replace('.', os.sep) + module if sys.platform == "win32": INCLUDE_DIR = os.path.join(os.getenv("COINDIR"), "include") CPP_FLAGS = "-I" + quote(INCLUDE_DIR) + " " + \ "-I" + quote(os.path.join(os.getenv("COINDIR"), "include", "Inventor", "annex")) + \ " /DCOIN_DLL /wd4244 /wd4049" # aquire highest non-debug Coin library version try: LDFLAGS_LIBS = quote(max(glob.glob(os.path.join(os.getenv("COINDIR"), "lib", "coin?.lib")))) + " " # with cmake the coin library is named Coin4.lib except ValueError: LDFLAGS_LIBS = quote(max(glob.glob(os.path.join(os.getenv("COINDIR"), "lib", "Coin?.lib")))) + " " if module == "sowin": CPP_FLAGS += " /DSOWIN_DLL" LDFLAGS_LIBS += quote(os.path.join(os.getenv("COINDIR"), "lib", "sowin1.lib")) elif module == "soqt": CPP_FLAGS += " -I" + '"' + os.getenv("QTDIR") + "\\include\" /DSOQT_DLL" if os.path.isdir(os.getenv("QTDIR") + "\\include\Qt\""): CPP_FLAGS += " -I" + '"' + os.getenv("QTDIR") + "\\include\Qt\"" LDFLAGS_LIBS += os.path.join(os.getenv("COINDIR"), "lib", "soqt1.lib") + " " else: # workaround for conda qt4: CPP_FLAGS += " -I" + '"' + os.getenv("QTDIR") + "\\include\qt\Qt\"" CPP_FLAGS += " -I" + '"' + os.getenv("QTDIR") + "\\include\qt\"" LDFLAGS_LIBS += os.path.join(os.getenv("COINDIR"), "lib", "SoQt.lib") + " " else: INCLUDE_DIR = self.do_os_popen("coin-config --includedir") if module_name != 'coin': mod_include_dir = self.do_os_popen("%s --includedir" % config_cmd) if mod_include_dir != INCLUDE_DIR: INCLUDE_DIR += '\" -I\"%s' % mod_include_dir CPP_FLAGS = self.do_os_popen("%s --cppflags" % config_cmd) + " -Wno-unused -Wno-maybe-uninitialized" LDFLAGS_LIBS = self.do_os_popen("%s --ldflags --libs" % config_cmd) if not os.path.isfile(mod_out_prefix + "_wrap.cpp"): print(red("\n=== Generating %s_wrap.cpp for %s ===\n" % (mod_out_prefix, module))) print(blue(self.SWIG + " " + self.SWIG_SUPPRESS_WARNINGS + " " + self.SWIG_PARAMS % (INCLUDE_DIR, self.CXX_INCS, mod_out_prefix, module))) if os.system(self.SWIG + " " + self.SWIG_SUPPRESS_WARNINGS + " " + self.SWIG_PARAMS % (INCLUDE_DIR, self.CXX_INCS, mod_out_prefix, mod_hack_name)): print(red("SWIG did not generate wrappers successfully! ** Aborting **")) sys.exit(1) else: print(red("=== %s_wrap.cpp for %s already exists! ===" % (mod_out_prefix, module_pkg_name + module))) self.ext_modules.append(Extension(module_name, [mod_out_prefix + "_wrap.cpp"], extra_compile_args=(self.CXX_INCS + CPP_FLAGS).split(), extra_link_args=(self.CXX_LIBS + LDFLAGS_LIBS).split())) def run(self): "the entry point for the distutils build class" if sys.platform == "win32" and not os.getenv("COINDIR"): print("Please set the COINDIR environment variable to your Coin root directory! ** Aborting **") sys.exit(1) self.pivy_configure() self.swig_generate() for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) class pivy_clean(clean): pivy_path = 'pivy' + os.sep gui_path = 'pivy' + os.sep + 'gui' + os.sep REMOVE_FILES = (pivy_path + '__init__.pyc', gui_path + '__init__.pyc', pivy_path + 'coin_wrap.cpp', pivy_path + 'coin2_wrap.cpp', pivy_path + 'coin.py', pivy_path + 'coin.pyc', pivy_path + 'simvoleon_wrap.cpp', pivy_path + 'simvoleon.py', pivy_path + 'simvoleon.pyc', gui_path + 'soqt_wrap.cpp', gui_path + 'soqt.py', gui_path + 'soqt.pyc', gui_path + 'sogtk_wrap.cpp', gui_path + 'sogtk.py', gui_path + 'sogtk.py', gui_path + 'soxt_wrap.cpp', gui_path + 'soxt.py', gui_path + 'soxt.pyc', gui_path + 'sowin_wrap.cpp', gui_path + 'sowin.py', gui_path + 'sowin.pyc', pivy_path + 'sogui.pyc') def remove_headers(self, arg, dirname, files): "remove the coin headers from the pivy Inventor directory" for file in files: if not os.path.isfile(os.path.join(dirname, file)) or file[-2:] != ".h": continue sys.stdout.write(' ' + turquoise(os.path.join(dirname, file))) os.remove(os.path.join(dirname, file)) def run(self): "the entry point for the distutils clean class" sys.stdout.write(blue("Cleaning headers:")) dir_gen = os.walk("Inventor") for _dir, _, names in dir_gen: self.remove_headers(None, _dir, names) dir_gen = os.walk("VolumeViz") for _dir, _, names in dir_gen: self.remove_headers(None, _dir, names) # remove the SWIG generated wrappers for wrapper_file in self.REMOVE_FILES: if os.path.isfile(wrapper_file): sys.stdout.write(' ' + turquoise(wrapper_file)) os.remove(wrapper_file) print(green(".")) clean.run(self) for i in reversed(list(range(len(sys.argv)))): if sys.argv[i][:10] == "--without-": pivy_build.MODULES.pop(sys.argv[i][10:], None) del sys.argv[i] setup(name = "Pivy", version = PIVY_VERSION, description = "A Python binding for Coin", long_description = __doc__, author = "Tamer Fahmy", author_email = "tamer@sim.no", download_url="https://github.com/coin3d/pivy/releases", url = "http://pivy.coin3d.org/", cmdclass = {'build' : pivy_build, 'clean' : pivy_clean}, ext_package = 'pivy', ext_modules = pivy_build.ext_modules, py_modules = pivy_build.py_modules, packages = ['pivy', 'pivy.gui'], classifiers = [_f for _f in PIVY_CLASSIFIERS.split("\n") if _f], license = "BSD License", platforms = ['Any'] ) pivy-0.6.5/SConstruct0000644000175000017500000001265413606712377013323 0ustar kurtkurt### # Copyright (c) 2002-2009 Kongsberg SIM # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # import os, shutil import distutils.sysconfig, os SWIG_SUPPRESS_WARNINGS = "-w302,306,307,312,389,361,362,467,503,509,510" includedir='/export/home/tamer/Projects/coin/bininclib/include/' SOGUI = ('Qt', 'Xt', 'Gtk', 'Win') MODULES = {'Coin' : ('#pivy'+os.sep+'_coin', 'Inventor'), 'SIMVoleon' : ('#pivy'+os.sep+'_simvoleon', 'VolumeViz'), 'SoQt' : ('#pivy'+os.sep+'gui'+os.sep+'_soqt', 'Qt'), 'SoXt' : ('#pivy'+os.sep+'gui'+os.sep+'_soxt', 'Win'), 'SoGtk' : ('#pivy'+os.sep+'gui'+os.sep+'_sogtk', 'Gtk'), 'SoWin' : ('#pivy'+os.sep+'gui'+os.sep+'_sowin', 'Win')} def copy_and_swigify_header(target, source, env): """Copy the header files to the local include directories. Add an #include line at the beginning for the SWIG interface files.""" pivy_header_include = "\n#ifdef __PIVY__\n%%include %s\n#endif\n" nr = -1 for header in target: nr += 1 file_h = str(header) file_i = str(source[nr]) if not os.path.isfile(os.path.join(includedir, file_h)): target.remove(target[nr]) source.remove(source[nr]) else: shutil.copyfile(os.path.join(includedir, file_h), file_h) fd = open(str(header), 'r+') contents = fd.readlines() # insert right after #ifndef/#define header include protection contents.insert(2, pivy_header_include % (file_i)) fd.seek(0) fd.writelines(contents) fd.close bld_swigify = Builder(action = Action(copy_and_swigify_header, "Fixing header files for the following " + "swig interface files:\n\n${CHANGED_SOURCES}\n\n"), suffix = '.h', src_suffix = '.i') dist_vars = distutils.sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', 'CCSHARED', 'LDSHARED', 'SO') for i in range(len(dist_vars)): if dist_vars[i] is None: dist_vars[i] = "" (cc, cxx, opt, basecflags, ccshared, ldshared, so_ext) = dist_vars env = Environment(ENV = os.environ, CC=cxx, CPPPATH=[distutils.sysconfig.get_python_inc()], CPPFLAGS=basecflags + " " + opt, SHLINK=ldshared, SHLINKFLAGS=[], SHLIBPREFIX="", SHLIBSUFFIX=so_ext, SWIGFLAGS = Split('-c++ -python -includeall -modern -D__PIVY__') + [SWIG_SUPPRESS_WARNINGS] + ['-I'+str(Dir('#')), '-I'+str(Dir('#fake_headers'))], SWIGOUTDIR = 'pivy', BUILDERS = {'SWIGIFY' : bld_swigify}, tools=['default', 'suncc']) if str(Platform()) == 'win32': env['SHLIBSUFFIX'] = '.pyd' swig_interfaces = {'Coin': [], 'Qt' : [], 'Win' : []} # gather a list of all swig interface files in the header override subdirectories swig_interfaces['Coin'] += Glob('#Inventor'+os.path.sep+'*.i') for dirpath, dirnames, files in os.walk(str(Dir('#Inventor'))): for dirname in swig_interfaces: if dirname in dirnames: swig_interfaces[dirname] += Glob('#'+os.path.join(dirpath, dirname, '*.i')) dirnames.remove(dirname) for dirname in dirnames: swig_interfaces['Coin'] += Glob('#'+os.path.join(dirpath, dirname, '*.i')) # print [str(name) for name in swig_interfaces['Coin']] ### # Coin # coin_env = env.Clone() coin_env.ParseConfig('pkg-config Coin --cflags --libs') coin_env.Append(SWIGFLAGS = ['-I'+includedir]) coin_env.Append(SWIGFLAGS = ['-I'+str(Dir('#interfaces'))]) swigged_headers = coin_env.SWIGIFY([str(name)[:-2] for name in swig_interfaces['Coin']], [str(name)[:-2] for name in swig_interfaces['Coin']]) coin_wrapper = coin_env.CXXFile(['#interfaces/coin.i']) coin_env.SharedLibrary('#pivy/_coin', coin_wrapper[0]) coin_env.Depends(coin_wrapper, swig_interfaces['Coin']) coin_env.Depends(coin_wrapper, swigged_headers, ) ### # SoQt # soqt_env = env.Clone() soqt_env.ParseConfig('pkg-config SoQt --cflags --libs') soqt_env.Append(SWIGFLAGS = ['-I'+includedir]) soqt_env.Append(SWIGFLAGS = ['-I'+str(Dir('#interfaces'))]) swigged_qt_headers = soqt_env.SWIGIFY([str(name)[:-2] for name in swig_interfaces['Qt']], [str(name)[:-2] for name in swig_interfaces['Qt']]) soqt_wrapper = soqt_env.CXXFile(['#interfaces/soqt.i']) soqt_env.SharedLibrary('#pivy/gui/_soqt', soqt_wrapper[0]) soqt_env.Depends(soqt_wrapper, swig_interfaces['Qt']) soqt_env.Depends(soqt_wrapper, swigged_qt_headers) pivy-0.6.5/scons/0000755000175000017500000000000013606712377012406 5ustar kurtkurtpivy-0.6.5/scons/scons-LICENSE0000644000175000017500000000244013606712377014536 0ustar kurtkurt Copyright and license for SCons - a software construction tool This copyright and license do not apply to any other software with which this software may have been included. Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pivy-0.6.5/scons/sconsign.py0000755000175000017500000004051713606712377014615 0ustar kurtkurt#! /usr/bin/env python # # SCons - a Software Constructor # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # from __future__ import print_function __revision__ = "src/script/sconsign.py 4369 2009/09/19 16:58:54 scons" __version__ = "1.2.0.d20090919" __build__ = "r4369[MODIFIED]" __buildsys__ = "scons-dev" __date__ = "2009/09/19 16:58:54" __developer__ = "scons" import os import os.path import sys import time ############################################################################## # BEGIN STANDARD SCons SCRIPT HEADER # # This is the cut-and-paste logic so that a self-contained script can # interoperate correctly with different SCons versions and installation # locations for the engine. If you modify anything in this section, you # should also change other scripts that use this same header. ############################################################################## # Strip the script directory from sys.path() so on case-insensitive # (WIN32) systems Python doesn't think that the "scons" script is the # "SCons" package. Replace it with our own library directories # (version-specific first, in case they installed by hand there, # followed by generic) so we pick up the right version of the build # engine modules if they're in either directory. script_dir = sys.path[0] if script_dir in sys.path: sys.path.remove(script_dir) libs = [] if "SCONS_LIB_DIR" in os.environ: libs.append(os.environ["SCONS_LIB_DIR"]) local_version = 'scons-local-' + __version__ local = 'scons-local' if script_dir: local_version = os.path.join(script_dir, local_version) local = os.path.join(script_dir, local) libs.append(os.path.abspath(local_version)) libs.append(os.path.abspath(local)) scons_version = 'scons-%s' % __version__ prefs = [] if sys.platform == 'win32': # sys.prefix is (likely) C:\Python*; # check only C:\Python*. prefs.append(sys.prefix) prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages')) else: # On other (POSIX) platforms, things are more complicated due to # the variety of path names and library locations. Try to be smart # about it. if script_dir == 'bin': # script_dir is `pwd`/bin; # check `pwd`/lib/scons*. prefs.append(os.getcwd()) else: if script_dir == '.' or script_dir == '': script_dir = os.getcwd() head, tail = os.path.split(script_dir) if tail == "bin": # script_dir is /foo/bin; # check /foo/lib/scons*. prefs.append(head) head, tail = os.path.split(sys.prefix) if tail == "usr": # sys.prefix is /foo/usr; # check /foo/usr/lib/scons* first, # then /foo/usr/local/lib/scons*. prefs.append(sys.prefix) prefs.append(os.path.join(sys.prefix, "local")) elif tail == "local": h, t = os.path.split(head) if t == "usr": # sys.prefix is /foo/usr/local; # check /foo/usr/local/lib/scons* first, # then /foo/usr/lib/scons*. prefs.append(sys.prefix) prefs.append(head) else: # sys.prefix is /foo/local; # check only /foo/local/lib/scons*. prefs.append(sys.prefix) else: # sys.prefix is /foo (ends in neither /usr or /local); # check only /foo/lib/scons*. prefs.append(sys.prefix) temp = map(lambda x: os.path.join(x, 'lib'), prefs) temp.extend(map(lambda x: os.path.join(x, 'lib', 'python' + sys.version[:3], 'site-packages'), prefs)) prefs = temp # Add the parent directory of the current python's library to the # preferences. On SuSE-91/AMD64, for example, this is /usr/lib64, # not /usr/lib. try: libpath = os.__file__ except AttributeError: pass else: # Split /usr/libfoo/python*/os.py to /usr/libfoo/python*. libpath, tail = os.path.split(libpath) # Split /usr/libfoo/python* to /usr/libfoo libpath, tail = os.path.split(libpath) # Check /usr/libfoo/scons*. prefs.append(libpath) # Look first for 'scons-__version__' in all of our preference libs, # then for 'scons'. libs.extend(map(lambda x: os.path.join(x, scons_version), prefs)) libs.extend(map(lambda x: os.path.join(x, 'scons'), prefs)) sys.path = libs + sys.path ############################################################################## # END STANDARD SCons SCRIPT HEADER ############################################################################## import cPickle import imp import string import whichdb import SCons.SConsign def my_whichdb(filename): if filename[-7:] == ".dblite": return "SCons.dblite" try: f = open(filename + ".dblite", "rb") f.close() return "SCons.dblite" except IOError: pass return _orig_whichdb(filename) _orig_whichdb = whichdb.whichdb whichdb.whichdb = my_whichdb def my_import(mname): if '.' in mname: i = string.rfind(mname, '.') parent = my_import(mname[:i]) fp, pathname, description = imp.find_module(mname[i+1:], parent.__path__) else: fp, pathname, description = imp.find_module(mname) return imp.load_module(mname, fp, pathname, description) class Flagger: default_value = 1 def __setitem__(self, item, value): self.__dict__[item] = value self.default_value = 0 def __getitem__(self, item): return self.__dict__.get(item, self.default_value) Do_Call = None Print_Directories = [] Print_Entries = [] Print_Flags = Flagger() Verbose = 0 Readable = 0 def default_mapper(entry, name): try: val = eval("entry."+name) except: val = None return str(val) def map_action(entry, name): try: bact = entry.bact bactsig = entry.bactsig except AttributeError: return None return '%s [%s]' % (bactsig, bact) def map_timestamp(entry, name): try: timestamp = entry.timestamp except AttributeError: timestamp = None if Readable and timestamp: return "'" + time.ctime(timestamp) + "'" else: return str(timestamp) def map_bkids(entry, name): try: bkids = entry.bsources + entry.bdepends + entry.bimplicit bkidsigs = entry.bsourcesigs + entry.bdependsigs + entry.bimplicitsigs except AttributeError: return None result = [] for i in xrange(len(bkids)): result.append(nodeinfo_string(bkids[i], bkidsigs[i], " ")) if result == []: return None return string.join(result, "\n ") map_field = { 'action' : map_action, 'timestamp' : map_timestamp, 'bkids' : map_bkids, } map_name = { 'implicit' : 'bkids', } def field(name, entry, verbose=Verbose): if not Print_Flags[name]: return None fieldname = map_name.get(name, name) mapper = map_field.get(fieldname, default_mapper) val = mapper(entry, name) if verbose: val = name + ": " + val return val def nodeinfo_raw(name, ninfo, prefix=""): # This just formats the dictionary, which we would normally use str() # to do, except that we want the keys sorted for deterministic output. d = ninfo.__dict__ try: keys = ninfo.field_list + ['_version_id'] except AttributeError: keys = sorted(d.keys()) l = [] for k in keys: l.append('%s: %s' % (repr(k), repr(d.get(k)))) if '\n' in name: name = repr(name) return name + ': {' + string.join(l, ', ') + '}' def nodeinfo_cooked(name, ninfo, prefix=""): try: field_list = ninfo.field_list except AttributeError: field_list = [] f = lambda x, ni=ninfo, v=Verbose: field(x, ni, v) if '\n' in name: name = repr(name) outlist = [name+':'] + filter(None, map(f, field_list)) if Verbose: sep = '\n ' + prefix else: sep = ' ' return string.join(outlist, sep) nodeinfo_string = nodeinfo_cooked def printfield(name, entry, prefix=""): outlist = field("implicit", entry, 0) if outlist: if Verbose: print(" implicit:") print(" " + outlist) outact = field("action", entry, 0) if outact: if Verbose: print(" action: " + outact) else: print(" " + outact) def printentries(entries, location): if Print_Entries: for name in Print_Entries: try: entry = entries[name] except KeyError: sys.stderr.write("sconsign: no entry `%s' in `%s'\n" % (name, location)) else: try: ninfo = entry.ninfo except AttributeError: print(name + ":") else: print(nodeinfo_string(name, entry.ninfo)) printfield(name, entry.binfo) else: names = sorted(entries.keys()) for name in names: entry = entries[name] try: ninfo = entry.ninfo except AttributeError: print(name + ":") else: print(nodeinfo_string(name, entry.ninfo)) printfield(name, entry.binfo) class Do_SConsignDB: def __init__(self, dbm_name, dbm): self.dbm_name = dbm_name self.dbm = dbm def __call__(self, fname): # The *dbm modules stick their own file suffixes on the names # that are passed in. This is causes us to jump through some # hoops here to be able to allow the user try: # Try opening the specified file name. Example: # SPECIFIED OPENED BY self.dbm.open() # --------- ------------------------- # .sconsign => .sconsign.dblite # .sconsign.dblite => .sconsign.dblite.dblite db = self.dbm.open(fname, "r") except (IOError, OSError) as e: print_e = e try: # That didn't work, so try opening the base name, # so that if the actually passed in 'sconsign.dblite' # (for example), the dbm module will put the suffix back # on for us and open it anyway. db = self.dbm.open(os.path.splitext(fname)[0], "r") except (IOError, OSError): # That didn't work either. See if the file name # they specified just exists (independent of the dbm # suffix-mangling). try: open(fname, "r") except (IOError, OSError) as e: # Nope, that file doesn't even exist, so report that # fact back. print_e = e sys.stderr.write("sconsign: %s\n" % (print_e)) return except KeyboardInterrupt: raise except cPickle.UnpicklingError: sys.stderr.write("sconsign: ignoring invalid `%s' file `%s'\n" % (self.dbm_name, fname)) return except Exception as e: sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n" % (self.dbm_name, fname, e)) return if Print_Directories: for dir in Print_Directories: try: val = db[dir] except KeyError: sys.stderr.write("sconsign: no dir `%s' in `%s'\n" % (dir, args[0])) else: self.printentries(dir, val) else: keys = sorted(db.keys()) for dir in keys: self.printentries(dir, db[dir]) def printentries(self, dir, val): print('=== ' + dir + ':') printentries(cPickle.loads(val), dir) def Do_SConsignDir(name): try: fp = open(name, 'rb') except (IOError, OSError) as e: sys.stderr.write("sconsign: %s\n" % (e)) return try: sconsign = SCons.SConsign.Dir(fp) except KeyboardInterrupt: raise except cPickle.UnpicklingError: sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s'\n" % (name)) return except Exception as e: sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s': %s\n" % (name, e)) return printentries(sconsign.entries, args[0]) ############################################################################## import getopt helpstr = """\ Usage: sconsign [OPTIONS] FILE [...] Options: -a, --act, --action Print build action information. -c, --csig Print content signature information. -d DIR, --dir=DIR Print only info about DIR. -e ENTRY, --entry=ENTRY Print only info about ENTRY. -f FORMAT, --format=FORMAT FILE is in the specified FORMAT. -h, --help Print this message and exit. -i, --implicit Print implicit dependency information. -r, --readable Print timestamps in human-readable form. --raw Print raw Python object representations. -s, --size Print file sizes. -t, --timestamp Print timestamp information. -v, --verbose Verbose, describe each field. """ opts, args = getopt.getopt(sys.argv[1:], "acd:e:f:hirstv", ['act', 'action', 'csig', 'dir=', 'entry=', 'format=', 'help', 'implicit', 'raw', 'readable', 'size', 'timestamp', 'verbose']) for o, a in opts: if o in ('-a', '--act', '--action'): Print_Flags['action'] = 1 elif o in ('-c', '--csig'): Print_Flags['csig'] = 1 elif o in ('-d', '--dir'): Print_Directories.append(a) elif o in ('-e', '--entry'): Print_Entries.append(a) elif o in ('-f', '--format'): Module_Map = {'dblite' : 'SCons.dblite', 'sconsign' : None} dbm_name = Module_Map.get(a, a) if dbm_name: try: dbm = my_import(dbm_name) except: sys.stderr.write("sconsign: illegal file format `%s'\n" % a) print(helpstr) sys.exit(2) Do_Call = Do_SConsignDB(a, dbm) else: Do_Call = Do_SConsignDir elif o in ('-h', '--help'): print(helpstr) sys.exit(0) elif o in ('-i', '--implicit'): Print_Flags['implicit'] = 1 elif o in ('--raw',): nodeinfo_string = nodeinfo_raw elif o in ('-r', '--readable'): Readable = 1 elif o in ('-s', '--size'): Print_Flags['size'] = 1 elif o in ('-t', '--timestamp'): Print_Flags['timestamp'] = 1 elif o in ('-v', '--verbose'): Verbose = 1 if Do_Call: for a in args: Do_Call(a) else: for a in args: dbm_name = whichdb.whichdb(a) if dbm_name: Map_Module = {'SCons.dblite' : 'dblite'} dbm = my_import(dbm_name) Do_SConsignDB(Map_Module.get(dbm_name, dbm_name), dbm)(a) else: Do_SConsignDir(a) sys.exit(0) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-time.py0000755000175000017500000013763613606712377015064 0ustar kurtkurt#!/usr/bin/env python # # scons-time - run SCons timings and collect statistics # # A script for running a configuration through SCons with a standard # set of invocations to collect timing and memory statistics and to # capture the results in a consistent set of output files for display # and analysis. # # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # from __future__ import nested_scopes from __future__ import print_function __revision__ = "src/script/scons-time.py 4369 2009/09/19 15:58:29 scons" import getopt import glob import os import os.path import re import shutil import string import sys import tempfile import time def make_temp_file(**kw): try: result = tempfile.mktemp(**kw) try: result = os.path.realpath(result) except AttributeError: # Python 2.1 has no os.path.realpath() method. pass except TypeError: try: save_template = tempfile.template prefix = kw['prefix'] del kw['prefix'] tempfile.template = prefix result = tempfile.mktemp(**kw) finally: tempfile.template = save_template return result def HACK_for_exec(cmd, *args): ''' For some reason, Python won't allow an exec() within a function that also declares an internal function (including lambda functions). This function is a hack that calls exec() in a function with no internal functions. ''' if not args: exec(cmd) elif len(args) == 1: exec(cmd, args[0]) else: exec(cmd, args[0], args[1]) class Plotter: def increment_size(self, largest): """ Return the size of each horizontal increment line for a specified maximum value. This returns a value that will provide somewhere between 5 and 9 horizontal lines on the graph, on some set of boundaries that are multiples of 10/100/1000/etc. """ i = largest / 5 if not i: return largest multiplier = 1 while i >= 10: i = i / 10 multiplier = multiplier * 10 return i * multiplier def max_graph_value(self, largest): # Round up to next integer. largest = int(largest) + 1 increment = self.increment_size(largest) return ((largest + increment - 1) / increment) * increment class Line: def __init__(self, points, type, title, label, comment, fmt="%s %s"): self.points = points self.type = type self.title = title self.label = label self.comment = comment self.fmt = fmt def print_label(self, inx, x, y): if self.label: print('set label %s "%s" at %s,%s right' % (inx, self.label, x, y)) def plot_string(self): if self.title: title_string = 'title "%s"' % self.title else: title_string = 'notitle' return "'-' %s with lines lt %s" % (title_string, self.type) def print_points(self, fmt=None): if fmt is None: fmt = self.fmt if self.comment: print('# %s' % self.comment) for x, y in self.points: # If y is None, it usually represents some kind of break # in the line's index number. We might want to represent # this some way rather than just drawing the line straight # between the two points on either side. if not y is None: print(fmt % (x, y)) print('e') def get_x_values(self): return [ p[0] for p in self.points ] def get_y_values(self): return [ p[1] for p in self.points ] class Gnuplotter(Plotter): def __init__(self, title, key_location): self.lines = [] self.title = title self.key_location = key_location def line(self, points, type, title=None, label=None, comment=None, fmt='%s %s'): if points: line = Line(points, type, title, label, comment, fmt) self.lines.append(line) def plot_string(self, line): return line.plot_string() def vertical_bar(self, x, type, label, comment): if self.get_min_x() <= x and x <= self.get_max_x(): points = [(x, 0), (x, self.max_graph_value(self.get_max_y()))] self.line(points, type, label, comment) def get_all_x_values(self): result = [] for line in self.lines: result.extend(line.get_x_values()) return filter(lambda r: not r is None, result) def get_all_y_values(self): result = [] for line in self.lines: result.extend(line.get_y_values()) return filter(lambda r: not r is None, result) def get_min_x(self): try: return self.min_x except AttributeError: try: self.min_x = min(self.get_all_x_values()) except ValueError: self.min_x = 0 return self.min_x def get_max_x(self): try: return self.max_x except AttributeError: try: self.max_x = max(self.get_all_x_values()) except ValueError: self.max_x = 0 return self.max_x def get_min_y(self): try: return self.min_y except AttributeError: try: self.min_y = min(self.get_all_y_values()) except ValueError: self.min_y = 0 return self.min_y def get_max_y(self): try: return self.max_y except AttributeError: try: self.max_y = max(self.get_all_y_values()) except ValueError: self.max_y = 0 return self.max_y def draw(self): if not self.lines: return if self.title: print('set title "%s"' % self.title) print('set key %s' % self.key_location) min_y = self.get_min_y() max_y = self.max_graph_value(self.get_max_y()) range = max_y - min_y incr = range / 10.0 start = min_y + (max_y / 2.0) + (2.0 * incr) position = [ start - (i * incr) for i in xrange(5) ] inx = 1 for line in self.lines: line.print_label(inx, line.points[0][0]-1, position[(inx-1) % len(position)]) inx += 1 plot_strings = [ self.plot_string(l) for l in self.lines ] print('plot ' + ', \\\n '.join(plot_strings)) for line in self.lines: line.print_points() def untar(fname): import tarfile tar = tarfile.open(name=fname, mode='r') for tarinfo in tar: tar.extract(tarinfo) tar.close() def unzip(fname): import zipfile zf = zipfile.ZipFile(fname, 'r') for name in zf.namelist(): dir = os.path.dirname(name) try: os.makedirs(dir) except: pass open(name, 'w').write(zf.read(name)) def read_tree(dir): def read_files(arg, dirname, fnames): for fn in fnames: fn = os.path.join(dirname, fn) if os.path.isfile(fn): open(fn, 'rb').read() os.path.walk('.', read_files, None) def redirect_to_file(command, log): return '%s > %s 2>&1' % (command, log) def tee_to_file(command, log): return '%s 2>&1 | tee %s' % (command, log) class SConsTimer: """ Usage: scons-time SUBCOMMAND [ARGUMENTS] Type "scons-time help SUBCOMMAND" for help on a specific subcommand. Available subcommands: func Extract test-run data for a function help Provides help mem Extract --debug=memory data from test runs obj Extract --debug=count data from test runs time Extract --debug=time data from test runs run Runs a test configuration """ name = 'scons-time' name_spaces = ' '*len(name) def makedict(**kw): return kw default_settings = makedict( aegis = 'aegis', aegis_project = None, chdir = None, config_file = None, initial_commands = [], key_location = 'bottom left', orig_cwd = os.getcwd(), outdir = None, prefix = '', python = '"%s"' % sys.executable, redirect = redirect_to_file, scons = None, scons_flags = '--debug=count --debug=memory --debug=time --debug=memoizer', scons_lib_dir = None, scons_wrapper = None, startup_targets = '--help', subdir = None, subversion_url = None, svn = 'svn', svn_co_flag = '-q', tar = 'tar', targets = '', targets0 = None, targets1 = None, targets2 = None, title = None, unzip = 'unzip', verbose = False, vertical_bars = [], unpack_map = { '.tar.gz' : (untar, '%(tar)s xzf %%s'), '.tgz' : (untar, '%(tar)s xzf %%s'), '.tar' : (untar, '%(tar)s xf %%s'), '.zip' : (unzip, '%(unzip)s %%s'), }, ) run_titles = [ 'Startup', 'Full build', 'Up-to-date build', ] run_commands = [ '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof0)s %(targets0)s', '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof1)s %(targets1)s', '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof2)s %(targets2)s', ] stages = [ 'pre-read', 'post-read', 'pre-build', 'post-build', ] stage_strings = { 'pre-read' : 'Memory before reading SConscript files:', 'post-read' : 'Memory after reading SConscript files:', 'pre-build' : 'Memory before building targets:', 'post-build' : 'Memory after building targets:', } memory_string_all = 'Memory ' default_stage = stages[-1] time_strings = { 'total' : 'Total build time', 'SConscripts' : 'Total SConscript file execution time', 'SCons' : 'Total SCons execution time', 'commands' : 'Total command execution time', } time_string_all = 'Total .* time' # def __init__(self): self.__dict__.update(self.default_settings) # Functions for displaying and executing commands. def subst(self, x, dictionary): try: return x % dictionary except TypeError: # x isn't a string (it's probably a Python function), # so just return it. return x def subst_variables(self, command, dictionary): """ Substitutes (via the format operator) the values in the specified dictionary into the specified command. The command can be an (action, string) tuple. In all cases, we perform substitution on strings and don't worry if something isn't a string. (It's probably a Python function to be executed.) """ try: command + '' except TypeError: action = command[0] string = command[1] args = command[2:] else: action = command string = action args = (()) action = self.subst(action, dictionary) string = self.subst(string, dictionary) return (action, string, args) def _do_not_display(self, msg, *args): pass def display(self, msg, *args): """ Displays the specified message. Each message is prepended with a standard prefix of our name plus the time. """ if callable(msg): msg = msg(*args) else: msg = msg % args if msg is None: return fmt = '%s[%s]: %s\n' sys.stdout.write(fmt % (self.name, time.strftime('%H:%M:%S'), msg)) def _do_not_execute(self, action, *args): pass def execute(self, action, *args): """ Executes the specified action. The action is called if it's a callable Python function, and otherwise passed to os.system(). """ if callable(action): action(*args) else: os.system(action % args) def run_command_list(self, commands, dict): """ Executes a list of commands, substituting values from the specified dictionary. """ commands = [ self.subst_variables(c, dict) for c in commands ] for action, string, args in commands: self.display(string, *args) sys.stdout.flush() status = self.execute(action, *args) if status: sys.exit(status) def log_display(self, command, log): command = self.subst(command, self.__dict__) if log: command = self.redirect(command, log) return command def log_execute(self, command, log): command = self.subst(command, self.__dict__) output = os.popen(command).read() if self.verbose: sys.stdout.write(output) open(log, 'wb').write(output) # def archive_splitext(self, path): """ Splits an archive name into a filename base and extension. This is like os.path.splitext() (which it calls) except that it also looks for '.tar.gz' and treats it as an atomic extensions. """ if path.endswith('.tar.gz'): return path[:-7], path[-7:] else: return os.path.splitext(path) def args_to_files(self, args, tail=None): """ Takes a list of arguments, expands any glob patterns, and returns the last "tail" files from the list. """ files = [] for a in args: g = sorted(glob.glob(a)) files.extend(g) if tail: files = files[-tail:] return files def ascii_table(self, files, columns, line_function, file_function=lambda x: x, *args, **kw): header_fmt = ' '.join(['%12s'] * len(columns)) line_fmt = header_fmt + ' %s' print(header_fmt % columns) for file in files: t = line_function(file, *args, **kw) if t is None: t = [] diff = len(columns) - len(t) if diff > 0: t += [''] * diff t.append(file_function(file)) print(line_fmt % tuple(t)) def collect_results(self, files, function, *args, **kw): results = {} for file in files: base = os.path.splitext(file)[0] run, index = string.split(base, '-')[-2:] run = int(run) index = int(index) value = function(file, *args, **kw) try: r = results[index] except KeyError: r = [] results[index] = r r.append((run, value)) return results def doc_to_help(self, obj): """ Translates an object's __doc__ string into help text. This strips a consistent number of spaces from each line in the help text, essentially "outdenting" the text to the left-most column. """ doc = obj.__doc__ if doc is None: return '' return self.outdent(doc) def find_next_run_number(self, dir, prefix): """ Returns the next run number in a directory for the specified prefix. Examines the contents the specified directory for files with the specified prefix, extracts the run numbers from each file name, and returns the next run number after the largest it finds. """ x = re.compile(re.escape(prefix) + '-([0-9]+).*') matches = map(lambda e, x=x: x.match(e), os.listdir(dir)) matches = filter(None, matches) if not matches: return 0 run_numbers = map(lambda m: int(m.group(1)), matches) return int(max(run_numbers)) + 1 def gnuplot_results(self, results, fmt='%s %.3f'): """ Prints out a set of results in Gnuplot format. """ gp = Gnuplotter(self.title, self.key_location) indices = sorted(results.keys()) for i in indices: try: t = self.run_titles[i] except IndexError: t = '??? %s ???' % i results[i].sort() gp.line(results[i], i+1, t, None, t, fmt=fmt) for bar_tuple in self.vertical_bars: try: x, type, label, comment = bar_tuple except ValueError: x, type, label = bar_tuple comment = label gp.vertical_bar(x, type, label, comment) gp.draw() def logfile_name(self, invocation): """ Returns the absolute path of a log file for the specificed invocation number. """ name = self.prefix_run + '-%d.log' % invocation return os.path.join(self.outdir, name) def outdent(self, s): """ Strip as many spaces from each line as are found at the beginning of the first line in the list. """ lines = s.split('\n') if lines[0] == '': lines = lines[1:] spaces = re.match(' *', lines[0]).group(0) def strip_initial_spaces(l, s=spaces): if l.startswith(spaces): l = l[len(spaces):] return l return '\n'.join([ strip_initial_spaces(l) for l in lines ]) + '\n' def profile_name(self, invocation): """ Returns the absolute path of a profile file for the specified invocation number. """ name = self.prefix_run + '-%d.prof' % invocation return os.path.join(self.outdir, name) def set_env(self, key, value): os.environ[key] = value # def get_debug_times(self, file, time_string=None): """ Fetch times from the --debug=time strings in the specified file. """ if time_string is None: search_string = self.time_string_all else: search_string = time_string contents = open(file).read() if not contents: sys.stderr.write('file %s has no contents!\n' % repr(file)) return None result = re.findall(r'%s: ([\d\.]*)' % search_string, contents)[-4:] result = [ float(r) for r in result ] if not time_string is None: try: result = result[0] except IndexError: sys.stderr.write('file %s has no results!\n' % repr(file)) return None return result def get_function_profile(self, file, function): """ Returns the file, line number, function name, and cumulative time. """ try: import pstats except ImportError as e: sys.stderr.write('%s: func: %s\n' % (self.name, e)) sys.stderr.write('%s This version of Python is missing the profiler.\n' % self.name_spaces) sys.stderr.write('%s Cannot use the "func" subcommand.\n' % self.name_spaces) sys.exit(1) statistics = pstats.Stats(file).stats matches = [ e for e in statistics.items() if e[0][2] == function ] r = matches[0] return r[0][0], r[0][1], r[0][2], r[1][3] def get_function_time(self, file, function): """ Returns just the cumulative time for the specified function. """ return self.get_function_profile(file, function)[3] def get_memory(self, file, memory_string=None): """ Returns a list of integers of the amount of memory used. The default behavior is to return all the stages. """ if memory_string is None: search_string = self.memory_string_all else: search_string = memory_string lines = open(file).readlines() lines = [ l for l in lines if l.startswith(search_string) ][-4:] result = [ int(l.split()[-1]) for l in lines[-4:] ] if len(result) == 1: result = result[0] return result def get_object_counts(self, file, object_name, index=None): """ Returns the counts of the specified object_name. """ object_string = ' ' + object_name + '\n' lines = open(file).readlines() line = [ l for l in lines if l.endswith(object_string) ][0] result = [ int(field) for field in line.split()[:4] ] if index is not None: result = result[index] return result # command_alias = {} def execute_subcommand(self, argv): """ Executes the do_*() function for the specified subcommand (argv[0]). """ if not argv: return cmdName = self.command_alias.get(argv[0], argv[0]) try: func = getattr(self, 'do_' + cmdName) except AttributeError: return self.default(argv) try: return func(argv) except TypeError as e: sys.stderr.write("%s %s: %s\n" % (self.name, cmdName, e)) import traceback traceback.print_exc(file=sys.stderr) sys.stderr.write("Try '%s help %s'\n" % (self.name, cmdName)) def default(self, argv): """ The default behavior for an unknown subcommand. Prints an error message and exits. """ sys.stderr.write('%s: Unknown subcommand "%s".\n' % (self.name, argv[0])) sys.stderr.write('Type "%s help" for usage.\n' % self.name) sys.exit(1) # def do_help(self, argv): """ """ if argv[1:]: for arg in argv[1:]: try: func = getattr(self, 'do_' + arg) except AttributeError: sys.stderr.write('%s: No help for "%s"\n' % (self.name, arg)) else: try: help = getattr(self, 'help_' + arg) except AttributeError: sys.stdout.write(self.doc_to_help(func)) sys.stdout.flush() else: help() else: doc = self.doc_to_help(self.__class__) if doc: sys.stdout.write(doc) sys.stdout.flush() return None # def help_func(self): help = """\ Usage: scons-time func [OPTIONS] FILE [...] -C DIR, --chdir=DIR Change to DIR before looking for files -f FILE, --file=FILE Read configuration from specified FILE --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT --func=NAME, --function=NAME Report time for function NAME -h, --help Print this help and exit -p STRING, --prefix=STRING Use STRING as log file/profile prefix -t NUMBER, --tail=NUMBER Only report the last NUMBER files --title=TITLE Specify the output plot TITLE """ sys.stdout.write(self.outdent(help)) sys.stdout.flush() def do_func(self, argv): """ """ format = 'ascii' function_name = '_main' tail = None short_opts = '?C:f:hp:t:' long_opts = [ 'chdir=', 'file=', 'fmt=', 'format=', 'func=', 'function=', 'help', 'prefix=', 'tail=', 'title=', ] opts, args = getopt.getopt(argv[1:], short_opts, long_opts) for o, a in opts: if o in ('-C', '--chdir'): self.chdir = a elif o in ('-f', '--file'): self.config_file = a elif o in ('--fmt', '--format'): format = a elif o in ('--func', '--function'): function_name = a elif o in ('-?', '-h', '--help'): self.do_help(['help', 'func']) sys.exit(0) elif o in ('--max',): max_time = int(a) elif o in ('-p', '--prefix'): self.prefix = a elif o in ('-t', '--tail'): tail = int(a) elif o in ('--title',): self.title = a if self.config_file: exec(open(self.config_file, 'rU').read(), self.__dict__) if self.chdir: os.chdir(self.chdir) if not args: pattern = '%s*.prof' % self.prefix args = self.args_to_files([pattern], tail) if not args: if self.chdir: directory = self.chdir else: directory = os.getcwd() sys.stderr.write('%s: func: No arguments specified.\n' % self.name) sys.stderr.write('%s No %s*.prof files found in "%s".\n' % (self.name_spaces, self.prefix, directory)) sys.stderr.write('%s Type "%s help func" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) else: args = self.args_to_files(args, tail) cwd_ = os.getcwd() + os.sep if format == 'ascii': for file in args: try: f, line, func, time = \ self.get_function_profile(file, function_name) except ValueError as e: sys.stderr.write("%s: func: %s: %s\n" % (self.name, file, e)) else: if f.startswith(cwd_): f = f[len(cwd_):] print("%.3f %s:%d(%s)" % (time, f, line, func)) elif format == 'gnuplot': results = self.collect_results(args, self.get_function_time, function_name) self.gnuplot_results(results) else: sys.stderr.write('%s: func: Unknown format "%s".\n' % (self.name, format)) sys.exit(1) # def help_mem(self): help = """\ Usage: scons-time mem [OPTIONS] FILE [...] -C DIR, --chdir=DIR Change to DIR before looking for files -f FILE, --file=FILE Read configuration from specified FILE --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT -h, --help Print this help and exit -p STRING, --prefix=STRING Use STRING as log file/profile prefix --stage=STAGE Plot memory at the specified stage: pre-read, post-read, pre-build, post-build (default: post-build) -t NUMBER, --tail=NUMBER Only report the last NUMBER files --title=TITLE Specify the output plot TITLE """ sys.stdout.write(self.outdent(help)) sys.stdout.flush() def do_mem(self, argv): format = 'ascii' logfile_path = lambda x: x stage = self.default_stage tail = None short_opts = '?C:f:hp:t:' long_opts = [ 'chdir=', 'file=', 'fmt=', 'format=', 'help', 'prefix=', 'stage=', 'tail=', 'title=', ] opts, args = getopt.getopt(argv[1:], short_opts, long_opts) for o, a in opts: if o in ('-C', '--chdir'): self.chdir = a elif o in ('-f', '--file'): self.config_file = a elif o in ('--fmt', '--format'): format = a elif o in ('-?', '-h', '--help'): self.do_help(['help', 'mem']) sys.exit(0) elif o in ('-p', '--prefix'): self.prefix = a elif o in ('--stage',): if not a in self.stages: sys.stderr.write('%s: mem: Unrecognized stage "%s".\n' % (self.name, a)) sys.exit(1) stage = a elif o in ('-t', '--tail'): tail = int(a) elif o in ('--title',): self.title = a if self.config_file: HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__) if self.chdir: os.chdir(self.chdir) logfile_path = lambda x, c=self.chdir: os.path.join(c, x) if not args: pattern = '%s*.log' % self.prefix args = self.args_to_files([pattern], tail) if not args: if self.chdir: directory = self.chdir else: directory = os.getcwd() sys.stderr.write('%s: mem: No arguments specified.\n' % self.name) sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory)) sys.stderr.write('%s Type "%s help mem" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) else: args = self.args_to_files(args, tail) cwd_ = os.getcwd() + os.sep if format == 'ascii': self.ascii_table(args, tuple(self.stages), self.get_memory, logfile_path) elif format == 'gnuplot': results = self.collect_results(args, self.get_memory, self.stage_strings[stage]) self.gnuplot_results(results) else: sys.stderr.write('%s: mem: Unknown format "%s".\n' % (self.name, format)) sys.exit(1) return 0 # def help_obj(self): help = """\ Usage: scons-time obj [OPTIONS] OBJECT FILE [...] -C DIR, --chdir=DIR Change to DIR before looking for files -f FILE, --file=FILE Read configuration from specified FILE --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT -h, --help Print this help and exit -p STRING, --prefix=STRING Use STRING as log file/profile prefix --stage=STAGE Plot memory at the specified stage: pre-read, post-read, pre-build, post-build (default: post-build) -t NUMBER, --tail=NUMBER Only report the last NUMBER files --title=TITLE Specify the output plot TITLE """ sys.stdout.write(self.outdent(help)) sys.stdout.flush() def do_obj(self, argv): format = 'ascii' logfile_path = lambda x: x stage = self.default_stage tail = None short_opts = '?C:f:hp:t:' long_opts = [ 'chdir=', 'file=', 'fmt=', 'format=', 'help', 'prefix=', 'stage=', 'tail=', 'title=', ] opts, args = getopt.getopt(argv[1:], short_opts, long_opts) for o, a in opts: if o in ('-C', '--chdir'): self.chdir = a elif o in ('-f', '--file'): self.config_file = a elif o in ('--fmt', '--format'): format = a elif o in ('-?', '-h', '--help'): self.do_help(['help', 'obj']) sys.exit(0) elif o in ('-p', '--prefix'): self.prefix = a elif o in ('--stage',): if not a in self.stages: sys.stderr.write('%s: obj: Unrecognized stage "%s".\n' % (self.name, a)) sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) stage = a elif o in ('-t', '--tail'): tail = int(a) elif o in ('--title',): self.title = a if not args: sys.stderr.write('%s: obj: Must specify an object name.\n' % self.name) sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) object_name = args.pop(0) if self.config_file: HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__) if self.chdir: os.chdir(self.chdir) logfile_path = lambda x, c=self.chdir: os.path.join(c, x) if not args: pattern = '%s*.log' % self.prefix args = self.args_to_files([pattern], tail) if not args: if self.chdir: directory = self.chdir else: directory = os.getcwd() sys.stderr.write('%s: obj: No arguments specified.\n' % self.name) sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory)) sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) else: args = self.args_to_files(args, tail) cwd_ = os.getcwd() + os.sep if format == 'ascii': self.ascii_table(args, tuple(self.stages), self.get_object_counts, logfile_path, object_name) elif format == 'gnuplot': stage_index = 0 for s in self.stages: if stage == s: break stage_index = stage_index + 1 results = self.collect_results(args, self.get_object_counts, object_name, stage_index) self.gnuplot_results(results) else: sys.stderr.write('%s: obj: Unknown format "%s".\n' % (self.name, format)) sys.exit(1) return 0 # def help_run(self): help = """\ Usage: scons-time run [OPTIONS] [FILE ...] --aegis=PROJECT Use SCons from the Aegis PROJECT --chdir=DIR Name of unpacked directory for chdir -f FILE, --file=FILE Read configuration from specified FILE -h, --help Print this help and exit -n, --no-exec No execute, just print command lines --number=NUMBER Put output in files for run NUMBER --outdir=OUTDIR Put output files in OUTDIR -p STRING, --prefix=STRING Use STRING as log file/profile prefix --python=PYTHON Time using the specified PYTHON -q, --quiet Don't print command lines --scons=SCONS Time using the specified SCONS --svn=URL, --subversion=URL Use SCons from Subversion URL -v, --verbose Display output of commands """ sys.stdout.write(self.outdent(help)) sys.stdout.flush() def do_run(self, argv): """ """ run_number_list = [None] short_opts = '?f:hnp:qs:v' long_opts = [ 'aegis=', 'file=', 'help', 'no-exec', 'number=', 'outdir=', 'prefix=', 'python=', 'quiet', 'scons=', 'svn=', 'subdir=', 'subversion=', 'verbose', ] opts, args = getopt.getopt(argv[1:], short_opts, long_opts) for o, a in opts: if o in ('--aegis',): self.aegis_project = a elif o in ('-f', '--file'): self.config_file = a elif o in ('-?', '-h', '--help'): self.do_help(['help', 'run']) sys.exit(0) elif o in ('-n', '--no-exec'): self.execute = self._do_not_execute elif o in ('--number',): run_number_list = self.split_run_numbers(a) elif o in ('--outdir',): self.outdir = a elif o in ('-p', '--prefix'): self.prefix = a elif o in ('--python',): self.python = a elif o in ('-q', '--quiet'): self.display = self._do_not_display elif o in ('-s', '--subdir'): self.subdir = a elif o in ('--scons',): self.scons = a elif o in ('--svn', '--subversion'): self.subversion_url = a elif o in ('-v', '--verbose'): self.redirect = tee_to_file self.verbose = True self.svn_co_flag = '' if not args and not self.config_file: sys.stderr.write('%s: run: No arguments or -f config file specified.\n' % self.name) sys.stderr.write('%s Type "%s help run" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) if self.config_file: exec(open(self.config_file, 'rU').read(), self.__dict__) if args: self.archive_list = args archive_file_name = os.path.split(self.archive_list[0])[1] if not self.subdir: self.subdir = self.archive_splitext(archive_file_name)[0] if not self.prefix: self.prefix = self.archive_splitext(archive_file_name)[0] prepare = None if self.subversion_url: prepare = self.prep_subversion_run elif self.aegis_project: prepare = self.prep_aegis_run for run_number in run_number_list: self.individual_run(run_number, self.archive_list, prepare) def split_run_numbers(self, s): result = [] for n in s.split(','): try: x, y = n.split('-') except ValueError: result.append(int(n)) else: result.extend(range(int(x), int(y)+1)) return result def scons_path(self, dir): return os.path.join(dir, 'src', 'script', 'scons.py') def scons_lib_dir_path(self, dir): return os.path.join(dir, 'src', 'engine') def prep_aegis_run(self, commands, removals): self.aegis_tmpdir = make_temp_file(prefix = self.name + '-aegis-') removals.append((shutil.rmtree, 'rm -rf %%s', self.aegis_tmpdir)) self.aegis_parent_project = os.path.splitext(self.aegis_project)[0] self.scons = self.scons_path(self.aegis_tmpdir) self.scons_lib_dir = self.scons_lib_dir_path(self.aegis_tmpdir) commands.extend([ 'mkdir %(aegis_tmpdir)s', (lambda: os.chdir(self.aegis_tmpdir), 'cd %(aegis_tmpdir)s'), '%(aegis)s -cp -ind -p %(aegis_parent_project)s .', '%(aegis)s -cp -ind -p %(aegis_project)s -delta %(run_number)s .', ]) def prep_subversion_run(self, commands, removals): self.svn_tmpdir = make_temp_file(prefix = self.name + '-svn-') removals.append((shutil.rmtree, 'rm -rf %%s', self.svn_tmpdir)) self.scons = self.scons_path(self.svn_tmpdir) self.scons_lib_dir = self.scons_lib_dir_path(self.svn_tmpdir) commands.extend([ 'mkdir %(svn_tmpdir)s', '%(svn)s co %(svn_co_flag)s -r %(run_number)s %(subversion_url)s %(svn_tmpdir)s', ]) def individual_run(self, run_number, archive_list, prepare=None): """ Performs an individual run of the default SCons invocations. """ commands = [] removals = [] if prepare: prepare(commands, removals) save_scons = self.scons save_scons_wrapper = self.scons_wrapper save_scons_lib_dir = self.scons_lib_dir if self.outdir is None: self.outdir = self.orig_cwd elif not os.path.isabs(self.outdir): self.outdir = os.path.join(self.orig_cwd, self.outdir) if self.scons is None: self.scons = self.scons_path(self.orig_cwd) if self.scons_lib_dir is None: self.scons_lib_dir = self.scons_lib_dir_path(self.orig_cwd) if self.scons_wrapper is None: self.scons_wrapper = self.scons if not run_number: run_number = self.find_next_run_number(self.outdir, self.prefix) self.run_number = str(run_number) self.prefix_run = self.prefix + '-%03d' % run_number if self.targets0 is None: self.targets0 = self.startup_targets if self.targets1 is None: self.targets1 = self.targets if self.targets2 is None: self.targets2 = self.targets self.tmpdir = make_temp_file(prefix = self.name + '-') commands.extend([ 'mkdir %(tmpdir)s', (os.chdir, 'cd %%s', self.tmpdir), ]) for archive in archive_list: if not os.path.isabs(archive): archive = os.path.join(self.orig_cwd, archive) if os.path.isdir(archive): dest = os.path.split(archive)[1] commands.append((shutil.copytree, 'cp -r %%s %%s', archive, dest)) else: suffix = self.archive_splitext(archive)[1] unpack_command = self.unpack_map.get(suffix) if not unpack_command: dest = os.path.split(archive)[1] commands.append((shutil.copyfile, 'cp %%s %%s', archive, dest)) else: commands.append(unpack_command + (archive,)) commands.extend([ (os.chdir, 'cd %%s', self.subdir), ]) commands.extend(self.initial_commands) commands.extend([ (lambda: read_tree('.'), 'find * -type f | xargs cat > /dev/null'), (self.set_env, 'export %%s=%%s', 'SCONS_LIB_DIR', self.scons_lib_dir), '%(python)s %(scons_wrapper)s --version', ]) index = 0 for run_command in self.run_commands: setattr(self, 'prof%d' % index, self.profile_name(index)) c = ( self.log_execute, self.log_display, run_command, self.logfile_name(index), ) commands.append(c) index = index + 1 commands.extend([ (os.chdir, 'cd %%s', self.orig_cwd), ]) if not os.environ.get('PRESERVE'): commands.extend(removals) commands.append((shutil.rmtree, 'rm -rf %%s', self.tmpdir)) self.run_command_list(commands, self.__dict__) self.scons = save_scons self.scons_lib_dir = save_scons_lib_dir self.scons_wrapper = save_scons_wrapper # def help_time(self): help = """\ Usage: scons-time time [OPTIONS] FILE [...] -C DIR, --chdir=DIR Change to DIR before looking for files -f FILE, --file=FILE Read configuration from specified FILE --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT -h, --help Print this help and exit -p STRING, --prefix=STRING Use STRING as log file/profile prefix -t NUMBER, --tail=NUMBER Only report the last NUMBER files --which=TIMER Plot timings for TIMER: total, SConscripts, SCons, commands. """ sys.stdout.write(self.outdent(help)) sys.stdout.flush() def do_time(self, argv): format = 'ascii' logfile_path = lambda x: x tail = None which = 'total' short_opts = '?C:f:hp:t:' long_opts = [ 'chdir=', 'file=', 'fmt=', 'format=', 'help', 'prefix=', 'tail=', 'title=', 'which=', ] opts, args = getopt.getopt(argv[1:], short_opts, long_opts) for o, a in opts: if o in ('-C', '--chdir'): self.chdir = a elif o in ('-f', '--file'): self.config_file = a elif o in ('--fmt', '--format'): format = a elif o in ('-?', '-h', '--help'): self.do_help(['help', 'time']) sys.exit(0) elif o in ('-p', '--prefix'): self.prefix = a elif o in ('-t', '--tail'): tail = int(a) elif o in ('--title',): self.title = a elif o in ('--which',): if not a in self.time_strings.keys(): sys.stderr.write('%s: time: Unrecognized timer "%s".\n' % (self.name, a)) sys.stderr.write('%s Type "%s help time" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) which = a if self.config_file: HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__) if self.chdir: os.chdir(self.chdir) logfile_path = lambda x, c=self.chdir: os.path.join(c, x) if not args: pattern = '%s*.log' % self.prefix args = self.args_to_files([pattern], tail) if not args: if self.chdir: directory = self.chdir else: directory = os.getcwd() sys.stderr.write('%s: time: No arguments specified.\n' % self.name) sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self.name_spaces, self.prefix, directory)) sys.stderr.write('%s Type "%s help time" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) else: args = self.args_to_files(args, tail) cwd_ = os.getcwd() + os.sep if format == 'ascii': columns = ("Total", "SConscripts", "SCons", "commands") self.ascii_table(args, columns, self.get_debug_times, logfile_path) elif format == 'gnuplot': results = self.collect_results(args, self.get_debug_times, self.time_strings[which]) self.gnuplot_results(results, fmt='%s %.6f') else: sys.stderr.write('%s: time: Unknown format "%s".\n' % (self.name, format)) sys.exit(1) if __name__ == '__main__': opts, args = getopt.getopt(sys.argv[1:], 'h?V', ['help', 'version']) ST = SConsTimer() for o, a in opts: if o in ('-?', '-h', '--help'): ST.do_help(['help']) sys.exit(0) elif o in ('-V', '--version'): sys.stdout.write('scons-time version\n') sys.exit(0) if not args: sys.stderr.write('Type "%s help" for usage.\n' % ST.name) sys.exit(1) ST.execute_subcommand(args) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-README0000644000175000017500000001450613606712377014417 0ustar kurtkurt# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation SCons - a software construction tool This is the scons-README file for a version of SCons packaged for local execution--that is, execution out of a specific local directory, without having to install SCons as a system-wide utility. You are likely reading this file in one of the following two situations: 1) You have unpacked an scons-local-{version} package and are examining the contents. In this case, you are presumably interested in using this package to include a local copy of SCons with some other software that you package, so that you can use SCons to build your software without forcing all of your users to have it fully installed. Instructions for this can be found below. If you are not looking to use SCons in this way, then please use either the scons-{version} package to install SCons on your system, or the scons-src-{version} package if you want the full source to SCons, including its packaging code and underlying tests and testing infrastructure. 2) This file was included in some other software package so that the package could be built using SCons. In this case, follow the instructions provided with the rest of the software package for how to use SCons to build and/or install the software. The file containing build and installation instructions will typically be named README or INSTALL. LATEST VERSION ============== Before going further, you can check for the latest version of the scons-local package, or any SCons package, at the SCons download page: http://www.scons.org/download.html EXECUTION REQUIREMENTS ====================== Running SCons requires Python version 1.5.2 or later. There should be no other dependencies or requirements to run SCons. The default SCons configuration assumes use of the Microsoft Visual C++ compiler suite on WIN32 systems, and assumes a C compiler named 'cc', a C++ compiler named 'c++', and a Fortran compiler named 'g77' (such as found in the GNU C compiler suite) on any other type of system. You may, of course, override these default values by appropriate configuration of Environment construction variables. INSTALLATION ============ Installation of this package should be as simple as unpacking the archive (either .tar.gz or .zip) in any directory (top-level or a subdirectory) within the software package with which you want to ship SCons. Once you have installed this package, you should write an SConstruct file at the top level of your source tree to build your software as you see fit. Then modify the build/install instructions for your package to instruct your users to execute SCons as follows (if you installed this package in your top-level directory): $ python scons.py Or (if, for example, you installed this package in a subdirectory named "scons"): $ python scons/scons.py That should be all you have to do. (If it isn't that simple, please let us know!) CONTENTS OF THIS PACKAGE ======================== This scons-local package consists of the following: scons-LICENSE A copy of the copyright and terms under which SCons is distributed (the Open Source Initiative-approved MIT license). A disclaimer has been added to the beginning to make clear that this license applies only to SCons, and not to any separate software you've written with which you're planning to package SCons. scons-README What you're looking at right now. scons-local-{version}/ The SCons build engine. This is structured as a Python library. scons.py The SCons script itself. The script sets up the Python sys.path variable to use the build engine found in the scons-local-{version}/ directory in preference to any other SCons build engine installed on your system. DOCUMENTATION ============= Because this package is intended to be included with other software by experienced users, we have not included any SCons documentation in this package (other than this scons-README file you're reading right now). If, however, you need documentation about SCons, then consult any of the following from the corresponding scons-{version} or scons-src-{version} package: The RELEASE.txt file (src/RELEASE.txt file in the scons-src-{version} package), which contains notes about this specific release, including known problems. The CHANGES.txt file (src/CHANGES.txt file in the scons-src-{version} package), which contains a list of changes since the previous release. The scons.1 man page (doc/man/scons.1 in the scons-src-{version} package), which contains a section of small examples for getting started using SCons. Additional documentation for SCons is available at: http://www.scons.org/doc.html LICENSING ========= SCons is distributed under the MIT license, a full copy of which is available in the scons-LICENSE file in this package. The MIT license is an approved Open Source license, which means: This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. More information about OSI certifications and Open Source software is available at: http://www.opensource.org/ REPORTING BUGS ============== You can report bugs either by following the "Tracker - Bugs" link on the SCons project page: http://sourceforge.net/projects/scons/ or by sending mail to the SCons developers mailing list: scons-devel@lists.sourceforge.net MAILING LISTS ============= A mailing list for users of SCons is available. You may send questions or comments to the list at: scons-users@lists.sourceforge.net You may subscribe to the scons-users mailing list at: http://lists.sourceforge.net/lists/listinfo/scons-users FOR MORE INFORMATION ==================== Check the SCons web site at: http://www.scons.org/ AUTHOR INFO =========== Steven Knight knight at baldmt dot com http://www.baldmt.com/~knight/ With plenty of help from the SCons Development team: Chad Austin Charles Crain Steve Leblanc Anthony Roach Terrel Shumway pivy-0.6.5/scons/scons-local-1.2.0.d20090919/0000755000175000017500000000000013606712377016337 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/0000755000175000017500000000000013606712377017364 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/SConf.py0000644000175000017500000011447113606712377020756 0ustar kurtkurt"""SCons.SConf Autoconf-like configuration support. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/SConf.py 4369 2009/09/19 15:58:29 scons" import os import re import string import StringIO import sys import traceback import types import SCons.Action import SCons.Builder import SCons.Errors import SCons.Job import SCons.Node.FS import SCons.Taskmaster import SCons.Util import SCons.Warnings import SCons.Conftest from SCons.Debug import Trace # Turn off the Conftest error logging SCons.Conftest.LogInputFiles = 0 SCons.Conftest.LogErrorMessages = 0 # Set build_type = None build_types = ['clean', 'help'] def SetBuildType(type): global build_type build_type = type # to be set, if we are in dry-run mode dryrun = 0 AUTO=0 # use SCons dependency scanning for up-to-date checks FORCE=1 # force all tests to be rebuilt CACHE=2 # force all tests to be taken from cache (raise an error, if necessary) cache_mode = AUTO def SetCacheMode(mode): """Set the Configure cache mode. mode must be one of "auto", "force", or "cache".""" global cache_mode if mode == "auto": cache_mode = AUTO elif mode == "force": cache_mode = FORCE elif mode == "cache": cache_mode = CACHE else: raise ValueError("SCons.SConf.SetCacheMode: Unknown mode " + mode) progress_display = SCons.Util.display # will be overwritten by SCons.Script def SetProgressDisplay(display): """Set the progress display to use (called from SCons.Script)""" global progress_display progress_display = display SConfFS = None _ac_build_counter = 0 # incremented, whenever TryBuild is called _ac_config_logs = {} # all config.log files created in this build _ac_config_hs = {} # all config.h files created in this build sconf_global = None # current sconf object def _createConfigH(target, source, env): t = open(str(target[0]), "w") defname = re.sub('[^A-Za-z0-9_]', '_', string.upper(str(target[0]))) t.write("""#ifndef %(DEFNAME)s_SEEN #define %(DEFNAME)s_SEEN """ % {'DEFNAME' : defname}) t.write(source[0].get_contents()) t.write(""" #endif /* %(DEFNAME)s_SEEN */ """ % {'DEFNAME' : defname}) t.close() def _stringConfigH(target, source, env): return "scons: Configure: creating " + str(target[0]) def CreateConfigHBuilder(env): """Called just before the building targets phase begins.""" if len(_ac_config_hs) == 0: return action = SCons.Action.Action(_createConfigH, _stringConfigH) sconfigHBld = SCons.Builder.Builder(action=action) env.Append( BUILDERS={'SConfigHBuilder':sconfigHBld} ) for k in _ac_config_hs.keys(): env.SConfigHBuilder(k, env.Value(_ac_config_hs[k])) class SConfWarning(SCons.Warnings.Warning): pass SCons.Warnings.enableWarningClass(SConfWarning) # some error definitions class SConfError(SCons.Errors.UserError): def __init__(self,msg): SCons.Errors.UserError.__init__(self,msg) class ConfigureDryRunError(SConfError): """Raised when a file or directory needs to be updated during a Configure process, but the user requested a dry-run""" def __init__(self,target): if not isinstance(target, SCons.Node.FS.File): msg = 'Cannot create configure directory "%s" within a dry-run.' % str(target) else: msg = 'Cannot update configure test "%s" within a dry-run.' % str(target) SConfError.__init__(self,msg) class ConfigureCacheError(SConfError): """Raised when a use explicitely requested the cache feature, but the test is run the first time.""" def __init__(self,target): SConfError.__init__(self, '"%s" is not yet built and cache is forced.' % str(target)) # define actions for building text files def _createSource( target, source, env ): fd = open(str(target[0]), "w") fd.write(source[0].get_contents()) fd.close() def _stringSource( target, source, env ): return (str(target[0]) + ' <-\n |' + string.replace( source[0].get_contents(), '\n', "\n |" ) ) # python 2.2 introduces types.BooleanType BooleanTypes = [int] if hasattr(types, 'BooleanType'): BooleanTypes.append(bool) class SConfBuildInfo(SCons.Node.FS.FileBuildInfo): """ Special build info for targets of configure tests. Additional members are result (did the builder succeed last time?) and string, which contains messages of the original build phase. """ result = None # -> 0/None -> no error, != 0 error string = None # the stdout / stderr output when building the target def set_build_result(self, result, string): self.result = result self.string = string class Streamer: """ 'Sniffer' for a file-like writable object. Similar to the unix tool tee. """ def __init__(self, orig): self.orig = orig self.s = StringIO.StringIO() def write(self, str): if self.orig: self.orig.write(str) self.s.write(str) def writelines(self, lines): for l in lines: self.write(l + '\n') def getvalue(self): """ Return everything written to orig since the Streamer was created. """ return self.s.getvalue() def flush(self): if self.orig: self.orig.flush() self.s.flush() class SConfBuildTask(SCons.Taskmaster.AlwaysTask): """ This is almost the same as SCons.Script.BuildTask. Handles SConfErrors correctly and knows about the current cache_mode. """ def display(self, message): if sconf_global.logstream: sconf_global.logstream.write("scons: Configure: " + message + "\n") def display_cached_string(self, bi): """ Logs the original builder messages, given the SConfBuildInfo instance bi. """ if not isinstance(bi, SConfBuildInfo): SCons.Warnings.warn(SConfWarning, "The stored build information has an unexpected class: %s" % bi.__class__) else: self.display("The original builder output was:\n" + string.replace(" |" + str(bi.string), "\n", "\n |")) def failed(self): # check, if the reason was a ConfigureDryRunError or a # ConfigureCacheError and if yes, reraise the exception exc_type = self.exc_info()[0] if issubclass(exc_type, SConfError): raise elif issubclass(exc_type, SCons.Errors.BuildError): # we ignore Build Errors (occurs, when a test doesn't pass) # Clear the exception to prevent the contained traceback # to build a reference cycle. self.exc_clear() else: self.display('Caught exception while building "%s":\n' % self.targets[0]) try: excepthook = sys.excepthook except AttributeError: # Earlier versions of Python don't have sys.excepthook... def excepthook(type, value, tb): traceback.print_tb(tb) print(type, value) excepthook(*self.exc_info()) return SCons.Taskmaster.Task.failed(self) def collect_node_states(self): # returns (is_up_to_date, cached_error, cachable) # where is_up_to_date is 1, if the node(s) are up_to_date # cached_error is 1, if the node(s) are up_to_date, but the # build will fail # cachable is 0, if some nodes are not in our cache T = 0 changed = False cached_error = False cachable = True for t in self.targets: if T: Trace('%s' % (t)) bi = t.get_stored_info().binfo if isinstance(bi, SConfBuildInfo): if T: Trace(': SConfBuildInfo') if cache_mode == CACHE: t.set_state(SCons.Node.up_to_date) if T: Trace(': set_state(up_to-date)') else: if T: Trace(': get_state() %s' % t.get_state()) if T: Trace(': changed() %s' % t.changed()) if (t.get_state() != SCons.Node.up_to_date and t.changed()): changed = True if T: Trace(': changed %s' % changed) cached_error = cached_error or bi.result else: if T: Trace(': else') # the node hasn't been built in a SConf context or doesn't # exist cachable = False changed = ( t.get_state() != SCons.Node.up_to_date ) if T: Trace(': changed %s' % changed) if T: Trace('\n') return (not changed, cached_error, cachable) def execute(self): if not self.targets[0].has_builder(): return sconf = sconf_global is_up_to_date, cached_error, cachable = self.collect_node_states() if cache_mode == CACHE and not cachable: raise ConfigureCacheError(self.targets[0]) elif cache_mode == FORCE: is_up_to_date = 0 if cached_error and is_up_to_date: self.display("Building \"%s\" failed in a previous run and all " "its sources are up to date." % str(self.targets[0])) binfo = self.targets[0].get_stored_info().binfo self.display_cached_string(binfo) raise SCons.Errors.BuildError # will be 'caught' in self.failed elif is_up_to_date: self.display("\"%s\" is up to date." % str(self.targets[0])) binfo = self.targets[0].get_stored_info().binfo self.display_cached_string(binfo) elif dryrun: raise ConfigureDryRunError(self.targets[0]) else: # note stdout and stderr are the same here s = sys.stdout = sys.stderr = Streamer(sys.stdout) try: env = self.targets[0].get_build_env() if cache_mode == FORCE: # Set up the Decider() to force rebuilds by saying # that every source has changed. Note that we still # call the environment's underlying source decider so # that the correct .sconsign info will get calculated # and keep the build state consistent. def force_build(dependency, target, prev_ni, env_decider=env.decide_source): env_decider(dependency, target, prev_ni) return True env.Decider(force_build) env['PSTDOUT'] = env['PSTDERR'] = s try: sconf.cached = 0 self.targets[0].build() finally: sys.stdout = sys.stderr = env['PSTDOUT'] = \ env['PSTDERR'] = sconf.logstream except KeyboardInterrupt: raise except SystemExit: exc_value = sys.exc_info()[1] raise SCons.Errors.ExplicitExit(self.targets[0],exc_value.code) except Exception as e: for t in self.targets: binfo = t.get_binfo() binfo.__class__ = SConfBuildInfo binfo.set_build_result(1, s.getvalue()) sconsign_entry = SCons.SConsign.SConsignEntry() sconsign_entry.binfo = binfo #sconsign_entry.ninfo = self.get_ninfo() # We'd like to do this as follows: # t.store_info(binfo) # However, we need to store it as an SConfBuildInfo # object, and store_info() will turn it into a # regular FileNodeInfo if the target is itself a # regular File. sconsign = t.dir.sconsign() sconsign.set_entry(t.name, sconsign_entry) sconsign.merge() raise e else: for t in self.targets: binfo = t.get_binfo() binfo.__class__ = SConfBuildInfo binfo.set_build_result(0, s.getvalue()) sconsign_entry = SCons.SConsign.SConsignEntry() sconsign_entry.binfo = binfo #sconsign_entry.ninfo = self.get_ninfo() # We'd like to do this as follows: # t.store_info(binfo) # However, we need to store it as an SConfBuildInfo # object, and store_info() will turn it into a # regular FileNodeInfo if the target is itself a # regular File. sconsign = t.dir.sconsign() sconsign.set_entry(t.name, sconsign_entry) sconsign.merge() class SConfBase: """This is simply a class to represent a configure context. After creating a SConf object, you can call any tests. After finished with your tests, be sure to call the Finish() method, which returns the modified environment. Some words about caching: In most cases, it is not necessary to cache Test results explicitely. Instead, we use the scons dependency checking mechanism. For example, if one wants to compile a test program (SConf.TryLink), the compiler is only called, if the program dependencies have changed. However, if the program could not be compiled in a former SConf run, we need to explicitely cache this error. """ def __init__(self, env, custom_tests = {}, conf_dir='$CONFIGUREDIR', log_file='$CONFIGURELOG', config_h = None, _depth = 0): """Constructor. Pass additional tests in the custom_tests-dictinary, e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest defines a custom test. Note also the conf_dir and log_file arguments (you may want to build tests in the VariantDir, not in the SourceDir) """ global SConfFS if not SConfFS: SConfFS = SCons.Node.FS.default_fs or \ SCons.Node.FS.FS(env.fs.pathTop) if sconf_global is not None: raise SCons.Errors.UserError self.env = env if log_file is not None: log_file = SConfFS.File(env.subst(log_file)) self.logfile = log_file self.logstream = None self.lastTarget = None self.depth = _depth self.cached = 0 # will be set, if all test results are cached # add default tests default_tests = { 'CheckCC' : CheckCC, 'CheckCXX' : CheckCXX, 'CheckSHCC' : CheckSHCC, 'CheckSHCXX' : CheckSHCXX, 'CheckFunc' : CheckFunc, 'CheckType' : CheckType, 'CheckTypeSize' : CheckTypeSize, 'CheckDeclaration' : CheckDeclaration, 'CheckHeader' : CheckHeader, 'CheckCHeader' : CheckCHeader, 'CheckCXXHeader' : CheckCXXHeader, 'CheckLib' : CheckLib, 'CheckLibWithHeader' : CheckLibWithHeader, } self.AddTests(default_tests) self.AddTests(custom_tests) self.confdir = SConfFS.Dir(env.subst(conf_dir)) if config_h is not None: config_h = SConfFS.File(config_h) self.config_h = config_h self._startup() def Finish(self): """Call this method after finished with your tests: env = sconf.Finish() """ self._shutdown() return self.env def Define(self, name, value = None, comment = None): """ Define a pre processor symbol name, with the optional given value in the current config header. If value is None (default), then #define name is written. If value is not none, then #define name value is written. comment is a string which will be put as a C comment in the header, to explain the meaning of the value (appropriate C comments /* and */ will be put automatically.""" lines = [] if comment: comment_str = "/* %s */" % comment lines.append(comment_str) if value is not None: define_str = "#define %s %s" % (name, value) else: define_str = "#define %s" % name lines.append(define_str) lines.append('') self.config_h_text = self.config_h_text + string.join(lines, '\n') def BuildNodes(self, nodes): """ Tries to build the given nodes immediately. Returns 1 on success, 0 on error. """ if self.logstream is not None: # override stdout / stderr to write in log file oldStdout = sys.stdout sys.stdout = self.logstream oldStderr = sys.stderr sys.stderr = self.logstream # the engine assumes the current path is the SConstruct directory ... old_fs_dir = SConfFS.getcwd() old_os_dir = os.getcwd() SConfFS.chdir(SConfFS.Top, change_os_dir=1) # Because we take responsibility here for writing out our # own .sconsign info (see SConfBuildTask.execute(), above), # we override the store_info() method with a null place-holder # so we really control how it gets written. for n in nodes: n.store_info = n.do_not_store_info ret = 1 try: # ToDo: use user options for calc save_max_drift = SConfFS.get_max_drift() SConfFS.set_max_drift(0) tm = SCons.Taskmaster.Taskmaster(nodes, SConfBuildTask) # we don't want to build tests in parallel jobs = SCons.Job.Jobs(1, tm ) jobs.run() for n in nodes: state = n.get_state() if (state != SCons.Node.executed and state != SCons.Node.up_to_date): # the node could not be built. we return 0 in this case ret = 0 finally: SConfFS.set_max_drift(save_max_drift) os.chdir(old_os_dir) SConfFS.chdir(old_fs_dir, change_os_dir=0) if self.logstream is not None: # restore stdout / stderr sys.stdout = oldStdout sys.stderr = oldStderr return ret def pspawn_wrapper(self, sh, escape, cmd, args, env): """Wrapper function for handling piped spawns. This looks to the calling interface (in Action.py) like a "normal" spawn, but associates the call with the PSPAWN variable from the construction environment and with the streams to which we want the output logged. This gets slid into the construction environment as the SPAWN variable so Action.py doesn't have to know or care whether it's spawning a piped command or not. """ return self.pspawn(sh, escape, cmd, args, env, self.logstream, self.logstream) def TryBuild(self, builder, text = None, extension = ""): """Low level TryBuild implementation. Normally you don't need to call that - you can use TryCompile / TryLink / TryRun instead """ global _ac_build_counter # Make sure we have a PSPAWN value, and save the current # SPAWN value. try: self.pspawn = self.env['PSPAWN'] except KeyError: raise SCons.Errors.UserError('Missing PSPAWN construction variable.') try: save_spawn = self.env['SPAWN'] except KeyError: raise SCons.Errors.UserError('Missing SPAWN construction variable.') nodesToBeBuilt = [] f = "conftest_" + str(_ac_build_counter) pref = self.env.subst( builder.builder.prefix ) suff = self.env.subst( builder.builder.suffix ) target = self.confdir.File(pref + f + suff) try: # Slide our wrapper into the construction environment as # the SPAWN function. self.env['SPAWN'] = self.pspawn_wrapper sourcetext = self.env.Value(text) if text is not None: textFile = self.confdir.File(f + extension) textFileNode = self.env.SConfSourceBuilder(target=textFile, source=sourcetext) nodesToBeBuilt.extend(textFileNode) source = textFileNode else: source = None nodes = builder(target = target, source = source) if not SCons.Util.is_List(nodes): nodes = [nodes] nodesToBeBuilt.extend(nodes) result = self.BuildNodes(nodesToBeBuilt) finally: self.env['SPAWN'] = save_spawn _ac_build_counter = _ac_build_counter + 1 if result: self.lastTarget = nodes[0] else: self.lastTarget = None return result def TryAction(self, action, text = None, extension = ""): """Tries to execute the given action with optional source file contents and optional source file extension , Returns the status (0 : failed, 1 : ok) and the contents of the output file. """ builder = SCons.Builder.Builder(action=action) self.env.Append( BUILDERS = {'SConfActionBuilder' : builder} ) ok = self.TryBuild(self.env.SConfActionBuilder, text, extension) del self.env['BUILDERS']['SConfActionBuilder'] if ok: outputStr = self.lastTarget.get_contents() return (1, outputStr) return (0, "") def TryCompile( self, text, extension): """Compiles the program given in text to an env.Object, using extension as file extension (e.g. '.c'). Returns 1, if compilation was successful, 0 otherwise. The target is saved in self.lastTarget (for further processing). """ return self.TryBuild(self.env.Object, text, extension) def TryLink( self, text, extension ): """Compiles the program given in text to an executable env.Program, using extension as file extension (e.g. '.c'). Returns 1, if compilation was successful, 0 otherwise. The target is saved in self.lastTarget (for further processing). """ return self.TryBuild(self.env.Program, text, extension ) def TryRun(self, text, extension ): """Compiles and runs the program given in text, using extension as file extension (e.g. '.c'). Returns (1, outputStr) on success, (0, '') otherwise. The target (a file containing the program's stdout) is saved in self.lastTarget (for further processing). """ ok = self.TryLink(text, extension) if( ok ): prog = self.lastTarget pname = prog.path output = self.confdir.File(os.path.basename(pname)+'.out') node = self.env.Command(output, prog, [ [ pname, ">", "${TARGET}"] ]) ok = self.BuildNodes(node) if ok: outputStr = output.get_contents() return( 1, outputStr) return (0, "") class TestWrapper: """A wrapper around Tests (to ensure sanity)""" def __init__(self, test, sconf): self.test = test self.sconf = sconf def __call__(self, *args, **kw): if not self.sconf.active: raise SCons.Errors.UserError context = CheckContext(self.sconf) ret = self.test(*(context,) + args, **kw) if self.sconf.config_h is not None: self.sconf.config_h_text = self.sconf.config_h_text + context.config_h context.Result("error: no result") return ret def AddTest(self, test_name, test_instance): """Adds test_class to this SConf instance. It can be called with self.test_name(...)""" setattr(self, test_name, SConfBase.TestWrapper(test_instance, self)) def AddTests(self, tests): """Adds all the tests given in the tests dictionary to this SConf instance """ for name in tests.keys(): self.AddTest(name, tests[name]) def _createDir( self, node ): dirName = str(node) if dryrun: if not os.path.isdir( dirName ): raise ConfigureDryRunError(dirName) else: if not os.path.isdir( dirName ): os.makedirs( dirName ) node._exists = 1 def _startup(self): """Private method. Set up logstream, and set the environment variables necessary for a piped build """ global _ac_config_logs global sconf_global global SConfFS self.lastEnvFs = self.env.fs self.env.fs = SConfFS self._createDir(self.confdir) self.confdir.up().add_ignore( [self.confdir] ) if self.logfile is not None and not dryrun: # truncate logfile, if SConf.Configure is called for the first time # in a build if self.logfile in _ac_config_logs: log_mode = "a" else: _ac_config_logs[self.logfile] = None log_mode = "w" fp = open(str(self.logfile), log_mode) self.logstream = SCons.Util.Unbuffered(fp) # logfile may stay in a build directory, so we tell # the build system not to override it with a eventually # existing file with the same name in the source directory self.logfile.dir.add_ignore( [self.logfile] ) tb = traceback.extract_stack()[-3-self.depth] old_fs_dir = SConfFS.getcwd() SConfFS.chdir(SConfFS.Top, change_os_dir=0) self.logstream.write('file %s,line %d:\n\tConfigure(confdir = %s)\n' % (tb[0], tb[1], str(self.confdir)) ) SConfFS.chdir(old_fs_dir) else: self.logstream = None # we use a special builder to create source files from TEXT action = SCons.Action.Action(_createSource, _stringSource) sconfSrcBld = SCons.Builder.Builder(action=action) self.env.Append( BUILDERS={'SConfSourceBuilder':sconfSrcBld} ) self.config_h_text = _ac_config_hs.get(self.config_h, "") self.active = 1 # only one SConf instance should be active at a time ... sconf_global = self def _shutdown(self): """Private method. Reset to non-piped spawn""" global sconf_global, _ac_config_hs if not self.active: raise SCons.Errors.UserError("Finish may be called only once!") if self.logstream is not None and not dryrun: self.logstream.write("\n") self.logstream.close() self.logstream = None # remove the SConfSourceBuilder from the environment blds = self.env['BUILDERS'] del blds['SConfSourceBuilder'] self.env.Replace( BUILDERS=blds ) self.active = 0 sconf_global = None if not self.config_h is None: _ac_config_hs[self.config_h] = self.config_h_text self.env.fs = self.lastEnvFs class CheckContext: """Provides a context for configure tests. Defines how a test writes to the screen and log file. A typical test is just a callable with an instance of CheckContext as first argument: def CheckCustom(context, ...) context.Message('Checking my weird test ... ') ret = myWeirdTestFunction(...) context.Result(ret) Often, myWeirdTestFunction will be one of context.TryCompile/context.TryLink/context.TryRun. The results of those are cached, for they are only rebuild, if the dependencies have changed. """ def __init__(self, sconf): """Constructor. Pass the corresponding SConf instance.""" self.sconf = sconf self.did_show_result = 0 # for Conftest.py: self.vardict = {} self.havedict = {} self.headerfilename = None self.config_h = "" # config_h text will be stored here # we don't regenerate the config.h file after each test. That means, # that tests won't be able to include the config.h file, and so # they can't do an #ifdef HAVE_XXX_H. This shouldn't be a major # issue, though. If it turns out, that we need to include config.h # in tests, we must ensure, that the dependencies are worked out # correctly. Note that we can't use Conftest.py's support for config.h, # cause we will need to specify a builder for the config.h file ... def Message(self, text): """Inform about what we are doing right now, e.g. 'Checking for SOMETHING ... ' """ self.Display(text) self.sconf.cached = 1 self.did_show_result = 0 def Result(self, res): """Inform about the result of the test. res may be an integer or a string. In case of an integer, the written text will be 'yes' or 'no'. The result is only displayed when self.did_show_result is not set. """ if type(res) in BooleanTypes: if res: text = "yes" else: text = "no" elif isinstance(res, bytes): text = res else: raise TypeError("Expected string, int or bool, got " + str(type(res))) if self.did_show_result == 0: # Didn't show result yet, do it now. self.Display(text + "\n") self.did_show_result = 1 def TryBuild(self, *args, **kw): return self.sconf.TryBuild(*args, **kw) def TryAction(self, *args, **kw): return self.sconf.TryAction(*args, **kw) def TryCompile(self, *args, **kw): return self.sconf.TryCompile(*args, **kw) def TryLink(self, *args, **kw): return self.sconf.TryLink(*args, **kw) def TryRun(self, *args, **kw): return self.sconf.TryRun(*args, **kw) def __getattr__( self, attr ): if( attr == 'env' ): return self.sconf.env elif( attr == 'lastTarget' ): return self.sconf.lastTarget else: raise AttributeError("CheckContext instance has no attribute '%s'" % attr) #### Stuff used by Conftest.py (look there for explanations). def BuildProg(self, text, ext): self.sconf.cached = 1 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc. return not self.TryBuild(self.env.Program, text, ext) def CompileProg(self, text, ext): self.sconf.cached = 1 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc. return not self.TryBuild(self.env.Object, text, ext) def CompileSharedObject(self, text, ext): self.sconf.cached = 1 # TODO: should use self.vardict for $SHCC, $CPPFLAGS, etc. return not self.TryBuild(self.env.SharedObject, text, ext) def RunProg(self, text, ext): self.sconf.cached = 1 # TODO: should use self.vardict for $CC, $CPPFLAGS, etc. st, out = self.TryRun(text, ext) return not st, out def AppendLIBS(self, lib_name_list): oldLIBS = self.env.get( 'LIBS', [] ) self.env.Append(LIBS = lib_name_list) return oldLIBS def PrependLIBS(self, lib_name_list): oldLIBS = self.env.get( 'LIBS', [] ) self.env.Prepend(LIBS = lib_name_list) return oldLIBS def SetLIBS(self, val): oldLIBS = self.env.get( 'LIBS', [] ) self.env.Replace(LIBS = val) return oldLIBS def Display(self, msg): if self.sconf.cached: # We assume that Display is called twice for each test here # once for the Checking for ... message and once for the result. # The self.sconf.cached flag can only be set between those calls msg = "(cached) " + msg self.sconf.cached = 0 progress_display(msg, append_newline=0) self.Log("scons: Configure: " + msg + "\n") def Log(self, msg): if self.sconf.logstream is not None: self.sconf.logstream.write(msg) #### End of stuff used by Conftest.py. def SConf(*args, **kw): if kw.get(build_type, True): kw['_depth'] = kw.get('_depth', 0) + 1 for bt in build_types: try: del kw[bt] except KeyError: pass return SConfBase(*args, **kw) else: return SCons.Util.Null() def CheckFunc(context, function_name, header = None, language = None): res = SCons.Conftest.CheckFunc(context, function_name, header = header, language = language) context.did_show_result = 1 return not res def CheckType(context, type_name, includes = "", language = None): res = SCons.Conftest.CheckType(context, type_name, header = includes, language = language) context.did_show_result = 1 return not res def CheckTypeSize(context, type_name, includes = "", language = None, expect = None): res = SCons.Conftest.CheckTypeSize(context, type_name, header = includes, language = language, expect = expect) context.did_show_result = 1 return res def CheckDeclaration(context, declaration, includes = "", language = None): res = SCons.Conftest.CheckDeclaration(context, declaration, includes = includes, language = language) context.did_show_result = 1 return not res def createIncludesFromHeaders(headers, leaveLast, include_quotes = '""'): # used by CheckHeader and CheckLibWithHeader to produce C - #include # statements from the specified header (list) if not SCons.Util.is_List(headers): headers = [headers] l = [] if leaveLast: lastHeader = headers[-1] headers = headers[:-1] else: lastHeader = None for s in headers: l.append("#include %s%s%s\n" % (include_quotes[0], s, include_quotes[1])) return string.join(l, ''), lastHeader def CheckHeader(context, header, include_quotes = '<>', language = None): """ A test for a C or C++ header file. """ prog_prefix, hdr_to_check = \ createIncludesFromHeaders(header, 1, include_quotes) res = SCons.Conftest.CheckHeader(context, hdr_to_check, prog_prefix, language = language, include_quotes = include_quotes) context.did_show_result = 1 return not res def CheckCC(context): res = SCons.Conftest.CheckCC(context) context.did_show_result = 1 return not res def CheckCXX(context): res = SCons.Conftest.CheckCXX(context) context.did_show_result = 1 return not res def CheckSHCC(context): res = SCons.Conftest.CheckSHCC(context) context.did_show_result = 1 return not res def CheckSHCXX(context): res = SCons.Conftest.CheckSHCXX(context) context.did_show_result = 1 return not res # Bram: Make this function obsolete? CheckHeader() is more generic. def CheckCHeader(context, header, include_quotes = '""'): """ A test for a C header file. """ return CheckHeader(context, header, include_quotes, language = "C") # Bram: Make this function obsolete? CheckHeader() is more generic. def CheckCXXHeader(context, header, include_quotes = '""'): """ A test for a C++ header file. """ return CheckHeader(context, header, include_quotes, language = "C++") def CheckLib(context, library = None, symbol = "main", header = None, language = None, autoadd = 1): """ A test for a library. See also CheckLibWithHeader. Note that library may also be None to test whether the given symbol compiles without flags. """ if library == []: library = [None] if not SCons.Util.is_List(library): library = [library] # ToDo: accept path for the library res = SCons.Conftest.CheckLib(context, library, symbol, header = header, language = language, autoadd = autoadd) context.did_show_result = 1 return not res # XXX # Bram: Can only include one header and can't use #ifdef HAVE_HEADER_H. def CheckLibWithHeader(context, libs, header, language, call = None, autoadd = 1): # ToDo: accept path for library. Support system header files. """ Another (more sophisticated) test for a library. Checks, if library and header is available for language (may be 'C' or 'CXX'). Call maybe be a valid expression _with_ a trailing ';'. As in CheckLib, we support library=None, to test if the call compiles without extra link flags. """ prog_prefix, dummy = \ createIncludesFromHeaders(header, 0) if libs == []: libs = [None] if not SCons.Util.is_List(libs): libs = [libs] res = SCons.Conftest.CheckLib(context, libs, None, prog_prefix, call = call, language = language, autoadd = autoadd) context.did_show_result = 1 return not res # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Errors.py0000644000175000017500000001655113606712377021222 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # """SCons.Errors This file contains the exception classes used to handle internal and user errors in SCons. """ __revision__ = "src/engine/SCons/Errors.py 4369 2009/09/19 15:58:29 scons" import SCons.Util import exceptions class BuildError(Exception): """ Errors occuring while building. BuildError have the following attributes: Information about the cause of the build error: ----------------------------------------------- errstr : a description of the error message status : the return code of the action that caused the build error. Must be set to a non-zero value even if the build error is not due to an action returning a non-zero returned code. exitstatus : SCons exit status due to this build error. Must be nonzero unless due to an explicit Exit() call. Not always the same as status, since actions return a status code that should be respected, but SCons typically exits with 2 irrespective of the return value of the failed action. filename : The name of the file or directory that caused the build error. Set to None if no files are associated with this error. This might be different from the target being built. For example, failure to create the directory in which the target file will appear. It can be None if the error is not due to a particular filename. exc_info : Info about exception that caused the build error. Set to (None, None, None) if this build error is not due to an exception. Information about the cause of the location of the error: --------------------------------------------------------- node : the error occured while building this target node(s) executor : the executor that caused the build to fail (might be None if the build failures is not due to the executor failing) action : the action that caused the build to fail (might be None if the build failures is not due to the an action failure) command : the command line for the action that caused the build to fail (might be None if the build failures is not due to the an action failure) """ def __init__(self, node=None, errstr="Unknown error", status=2, exitstatus=2, filename=None, executor=None, action=None, command=None, exc_info=(None, None, None)): self.errstr = errstr self.status = status self.exitstatus = exitstatus self.filename = filename self.exc_info = exc_info self.node = node self.executor = executor self.action = action self.command = command Exception.__init__(self, node, errstr, status, exitstatus, filename, executor, action, command, exc_info) def __str__(self): if self.filename: return self.filename + ': ' + self.errstr else: return self.errstr class InternalError(Exception): pass class UserError(Exception): pass class StopError(Exception): pass class EnvironmentError(Exception): pass class MSVCError(IOError): pass class ExplicitExit(Exception): def __init__(self, node=None, status=None, *args): self.node = node self.status = status self.exitstatus = status Exception.__init__(*(self,) + args) def convert_to_BuildError(status, exc_info=None): """ Convert any return code a BuildError Exception. `status' can either be a return code or an Exception. The buildError.status we set here will normally be used as the exit status of the "scons" process. """ if not exc_info and isinstance(status, Exception): exc_info = (status.__class__, status, None) if isinstance(status, BuildError): buildError = status buildError.exitstatus = 2 # always exit with 2 on build errors elif isinstance(status, ExplicitExit): status = status.status errstr = 'Explicit exit, status %s' % status buildError = BuildError( errstr=errstr, status=status, # might be 0, OK here exitstatus=status, # might be 0, OK here exc_info=exc_info) # TODO(1.5): #elif isinstance(status, (StopError, UserError)): elif isinstance(status, StopError) or isinstance(status, UserError): buildError = BuildError( errstr=str(status), status=2, exitstatus=2, exc_info=exc_info) elif isinstance(status, exceptions.EnvironmentError): # If an IOError/OSError happens, raise a BuildError. # Report the name of the file or directory that caused the # error, which might be different from the target being built # (for example, failure to create the directory in which the # target file will appear). try: filename = status.filename except AttributeError: filename = None buildError = BuildError( errstr=status.strerror, status=status.errno, exitstatus=2, filename=filename, exc_info=exc_info) elif isinstance(status, Exception): buildError = BuildError( errstr='%s : %s' % (status.__class__.__name__, status), status=2, exitstatus=2, exc_info=exc_info) elif SCons.Util.is_String(status): buildError = BuildError( errstr=status, status=2, exitstatus=2) else: buildError = BuildError( errstr="Error %s" % status, status=status, exitstatus=2) #import sys #sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)"%(status,buildError.errstr, buildError.status)) return buildError # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Script/0000755000175000017500000000000013606712377020630 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Script/__init__.py0000644000175000017500000003366513606712377022756 0ustar kurtkurt"""SCons.Script This file implements the main() function used by the scons script. Architecturally, this *is* the scons script, and will likely only be called from the external "scons" wrapper. Consequently, anything here should not be, or be considered, part of the build engine. If it's something that we expect other software to want to use, it should go in some other module. If it's specific to the "scons" script invocation, it goes here. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Script/__init__.py 4369 2009/09/19 15:58:29 scons" import time start_time = time.time() import os import string import sys import UserList # Special chicken-and-egg handling of the "--debug=memoizer" flag: # # SCons.Memoize contains a metaclass implementation that affects how # the other classes are instantiated. The Memoizer may add shim methods # to classes that have methods that cache computed values in order to # count and report the hits and misses. # # If we wait to enable the Memoization until after we've parsed the # command line options normally, it will be too late, because the Memoizer # will have already analyzed the classes that it's Memoizing and decided # to not add the shims. So we use a special-case, up-front check for # the "--debug=memoizer" flag and enable Memoizer before we import any # of the other modules that use it. _args = sys.argv + string.split(os.environ.get('SCONSFLAGS', '')) if "--debug=memoizer" in _args: import SCons.Memoize import SCons.Warnings try: SCons.Memoize.EnableMemoization() except SCons.Warnings.Warning: # Some warning was thrown (inability to --debug=memoizer on # Python 1.5.2 because it doesn't have metaclasses). Arrange # for it to be displayed or not after warnings are configured. import Main exc_type, exc_value, tb = sys.exc_info() Main.delayed_warnings.append((exc_type, exc_value)) del _args import SCons.Action import SCons.Builder import SCons.Environment import SCons.Node.FS import SCons.Options import SCons.Platform import SCons.Scanner import SCons.SConf import SCons.Subst import SCons.Tool import SCons.Util import SCons.Variables import SCons.Defaults import Main main = Main.main # The following are global class definitions and variables that used to # live directly in this module back before 0.96.90, when it contained # a lot of code. Some SConscript files in widely-distributed packages # (Blender is the specific example) actually reached into SCons.Script # directly to use some of these. Rather than break those SConscript # files, we're going to propagate these names into the SCons.Script # namespace here. # # Some of these are commented out because it's *really* unlikely anyone # used them, but we're going to leave the comment here to try to make # it obvious what to do if the situation arises. BuildTask = Main.BuildTask CleanTask = Main.CleanTask QuestionTask = Main.QuestionTask #PrintHelp = Main.PrintHelp #SConscriptSettableOptions = Main.SConscriptSettableOptions AddOption = Main.AddOption GetOption = Main.GetOption SetOption = Main.SetOption Progress = Main.Progress GetBuildFailures = Main.GetBuildFailures #keep_going_on_error = Main.keep_going_on_error #print_dtree = Main.print_dtree #print_explanations = Main.print_explanations #print_includes = Main.print_includes #print_objects = Main.print_objects #print_time = Main.print_time #print_tree = Main.print_tree #memory_stats = Main.memory_stats #ignore_errors = Main.ignore_errors #sconscript_time = Main.sconscript_time #command_time = Main.command_time #exit_status = Main.exit_status #profiling = Main.profiling #repositories = Main.repositories # import SConscript _SConscript = SConscript call_stack = _SConscript.call_stack # Action = SCons.Action.Action AddMethod = SCons.Util.AddMethod AllowSubstExceptions = SCons.Subst.SetAllowableExceptions Builder = SCons.Builder.Builder Configure = _SConscript.Configure Environment = SCons.Environment.Environment #OptParser = SCons.SConsOptions.OptParser FindPathDirs = SCons.Scanner.FindPathDirs Platform = SCons.Platform.Platform Return = _SConscript.Return Scanner = SCons.Scanner.Base Tool = SCons.Tool.Tool WhereIs = SCons.Util.WhereIs # BoolVariable = SCons.Variables.BoolVariable EnumVariable = SCons.Variables.EnumVariable ListVariable = SCons.Variables.ListVariable PackageVariable = SCons.Variables.PackageVariable PathVariable = SCons.Variables.PathVariable # Deprecated names that will go away some day. BoolOption = SCons.Options.BoolOption EnumOption = SCons.Options.EnumOption ListOption = SCons.Options.ListOption PackageOption = SCons.Options.PackageOption PathOption = SCons.Options.PathOption # Action factories. Chmod = SCons.Defaults.Chmod Copy = SCons.Defaults.Copy Delete = SCons.Defaults.Delete Mkdir = SCons.Defaults.Mkdir Move = SCons.Defaults.Move Touch = SCons.Defaults.Touch # Pre-made, public scanners. CScanner = SCons.Tool.CScanner DScanner = SCons.Tool.DScanner DirScanner = SCons.Defaults.DirScanner ProgramScanner = SCons.Tool.ProgramScanner SourceFileScanner = SCons.Tool.SourceFileScanner # Functions we might still convert to Environment methods. CScan = SCons.Defaults.CScan DefaultEnvironment = SCons.Defaults.DefaultEnvironment # Other variables we provide. class TargetList(UserList.UserList): def _do_nothing(self, *args, **kw): pass def _add_Default(self, list): self.extend(list) def _clear(self): del self[:] ARGUMENTS = {} ARGLIST = [] BUILD_TARGETS = TargetList() COMMAND_LINE_TARGETS = [] DEFAULT_TARGETS = [] # BUILD_TARGETS can be modified in the SConscript files. If so, we # want to treat the modified BUILD_TARGETS list as if they specified # targets on the command line. To do that, though, we need to know if # BUILD_TARGETS was modified through "official" APIs or by hand. We do # this by updating two lists in parallel, the documented BUILD_TARGETS # list, above, and this internal _build_plus_default targets list which # should only have "official" API changes. Then Script/Main.py can # compare these two afterwards to figure out if the user added their # own targets to BUILD_TARGETS. _build_plus_default = TargetList() def _Add_Arguments(alist): for arg in alist: a, b = string.split(arg, '=', 1) ARGUMENTS[a] = b ARGLIST.append((a, b)) def _Add_Targets(tlist): if tlist: COMMAND_LINE_TARGETS.extend(tlist) BUILD_TARGETS.extend(tlist) BUILD_TARGETS._add_Default = BUILD_TARGETS._do_nothing BUILD_TARGETS._clear = BUILD_TARGETS._do_nothing _build_plus_default.extend(tlist) _build_plus_default._add_Default = _build_plus_default._do_nothing _build_plus_default._clear = _build_plus_default._do_nothing def _Set_Default_Targets_Has_Been_Called(d, fs): return DEFAULT_TARGETS def _Set_Default_Targets_Has_Not_Been_Called(d, fs): if d is None: d = [fs.Dir('.')] return d _Get_Default_Targets = _Set_Default_Targets_Has_Not_Been_Called def _Set_Default_Targets(env, tlist): global DEFAULT_TARGETS global _Get_Default_Targets _Get_Default_Targets = _Set_Default_Targets_Has_Been_Called for t in tlist: if t is None: # Delete the elements from the list in-place, don't # reassign an empty list to DEFAULT_TARGETS, so that the # variables will still point to the same object we point to. del DEFAULT_TARGETS[:] BUILD_TARGETS._clear() _build_plus_default._clear() elif isinstance(t, SCons.Node.Node): DEFAULT_TARGETS.append(t) BUILD_TARGETS._add_Default([t]) _build_plus_default._add_Default([t]) else: nodes = env.arg2nodes(t, env.fs.Entry) DEFAULT_TARGETS.extend(nodes) BUILD_TARGETS._add_Default(nodes) _build_plus_default._add_Default(nodes) # help_text = None def HelpFunction(text): global help_text if SCons.Script.help_text is None: SCons.Script.help_text = text else: help_text = help_text + text # # Will be non-zero if we are reading an SConscript file. sconscript_reading = 0 # def Variables(files=[], args=ARGUMENTS): return SCons.Variables.Variables(files, args) def Options(files=[], args=ARGUMENTS): return SCons.Options.Options(files, args) # The list of global functions to add to the SConscript name space # that end up calling corresponding methods or Builders in the # DefaultEnvironment(). GlobalDefaultEnvironmentFunctions = [ # Methods from the SConsEnvironment class, above. 'Default', 'EnsurePythonVersion', 'EnsureSConsVersion', 'Exit', 'Export', 'GetLaunchDir', 'Help', 'Import', #'SConscript', is handled separately, below. 'SConscriptChdir', # Methods from the Environment.Base class. 'AddPostAction', 'AddPreAction', 'Alias', 'AlwaysBuild', 'BuildDir', 'CacheDir', 'Clean', #The Command() method is handled separately, below. 'Decider', 'Depends', 'Dir', 'NoClean', 'NoCache', 'Entry', 'Execute', 'File', 'FindFile', 'FindInstalledFiles', 'FindSourceFiles', 'Flatten', 'GetBuildPath', 'Glob', 'Ignore', 'Install', 'InstallAs', 'Literal', 'Local', 'ParseDepends', 'Precious', 'Repository', 'Requires', 'SConsignFile', 'SideEffect', 'SourceCode', 'SourceSignatures', 'Split', 'Tag', 'TargetSignatures', 'Value', 'VariantDir', ] GlobalDefaultBuilders = [ # Supported builders. 'CFile', 'CXXFile', 'DVI', 'Jar', 'Java', 'JavaH', 'Library', 'M4', 'MSVSProject', 'Object', 'PCH', 'PDF', 'PostScript', 'Program', 'RES', 'RMIC', 'SharedLibrary', 'SharedObject', 'StaticLibrary', 'StaticObject', 'Tar', 'TypeLibrary', 'Zip', 'Package', ] for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders: exec("%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))) del name # There are a handful of variables that used to live in the # Script/SConscript.py module that some SConscript files out there were # accessing directly as SCons.Script.SConscript.*. The problem is that # "SConscript" in this namespace is no longer a module, it's a global # function call--or more precisely, an object that implements a global # function call through the default Environment. Nevertheless, we can # maintain backwards compatibility for SConscripts that were reaching in # this way by hanging some attributes off the "SConscript" object here. SConscript = _SConscript.DefaultEnvironmentCall('SConscript') # Make SConscript look enough like the module it used to be so # that pychecker doesn't barf. SConscript.__name__ = 'SConscript' SConscript.Arguments = ARGUMENTS SConscript.ArgList = ARGLIST SConscript.BuildTargets = BUILD_TARGETS SConscript.CommandLineTargets = COMMAND_LINE_TARGETS SConscript.DefaultTargets = DEFAULT_TARGETS # The global Command() function must be handled differently than the # global functions for other construction environment methods because # we want people to be able to use Actions that must expand $TARGET # and $SOURCE later, when (and if) the Action is invoked to build # the target(s). We do this with the subst=1 argument, which creates # a DefaultEnvironmentCall instance that wraps up a normal default # construction environment that performs variable substitution, not a # proxy that doesn't. # # There's a flaw here, though, because any other $-variables on a command # line will *also* be expanded, each to a null string, but that should # only be a problem in the unusual case where someone was passing a '$' # on a command line and *expected* the $ to get through to the shell # because they were calling Command() and not env.Command()... This is # unlikely enough that we're going to leave this as is and cross that # bridge if someone actually comes to it. Command = _SConscript.DefaultEnvironmentCall('Command', subst=1) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Script/Interactive.py0000644000175000017500000003347713606712377023475 0ustar kurtkurtfrom __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Script/Interactive.py 4369 2009/09/19 15:58:29 scons" __doc__ = """ SCons interactive mode """ # TODO: # # This has the potential to grow into something with a really big life # of its own, which might or might not be a good thing. Nevertheless, # here are some enhancements that will probably be requested some day # and are worth keeping in mind (assuming this takes off): # # - A command to re-read / re-load the SConscript files. This may # involve allowing people to specify command-line options (e.g. -f, # -I, --no-site-dir) that affect how the SConscript files are read. # # - Additional command-line options on the "build" command. # # Of the supported options that seemed to make sense (after a quick # pass through the list), the ones that seemed likely enough to be # used are listed in the man page and have explicit test scripts. # # These had code changed in Script/Main.py to support them, but didn't # seem likely to be used regularly, so had no test scripts added: # # build --diskcheck=* # build --implicit-cache=* # build --implicit-deps-changed=* # build --implicit-deps-unchanged=* # # These look like they should "just work" with no changes to the # existing code, but like those above, look unlikely to be used and # therefore had no test scripts added: # # build --random # # These I'm not sure about. They might be useful for individual # "build" commands, and may even work, but they seem unlikely enough # that we'll wait until they're requested before spending any time on # writing test scripts for them, or investigating whether they work. # # build -q [??? is there a useful analog to the exit status?] # build --duplicate= # build --profile= # build --max-drift= # build --warn=* # build --Y # # - Most of the SCons command-line options that the "build" command # supports should be settable as default options that apply to all # subsequent "build" commands. Maybe a "set {option}" command that # maps to "SetOption('{option}')". # # - Need something in the 'help' command that prints the -h output. # # - A command to run the configure subsystem separately (must see how # this interacts with the new automake model). # # - Command-line completion of target names; maybe even of SCons options? # Completion is something that's supported by the Python cmd module, # so this should be doable without too much trouble. # import cmd import copy import os import re import shlex import string import sys try: import readline except ImportError: pass class SConsInteractiveCmd(cmd.Cmd): """\ build [TARGETS] Build the specified TARGETS and their dependencies. 'b' is a synonym. clean [TARGETS] Clean (remove) the specified TARGETS and their dependencies. 'c' is a synonym. exit Exit SCons interactive mode. help [COMMAND] Prints help for the specified COMMAND. 'h' and '?' are synonyms. shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and '!' are synonyms. version Prints SCons version information. """ synonyms = { 'b' : 'build', 'c' : 'clean', 'h' : 'help', 'scons' : 'build', 'sh' : 'shell', } def __init__(self, **kw): cmd.Cmd.__init__(self) for key, val in kw.items(): setattr(self, key, val) if sys.platform == 'win32': self.shell_variable = 'COMSPEC' else: self.shell_variable = 'SHELL' def default(self, argv): print("*** Unknown command: %s" % argv[0]) def onecmd(self, line): line = string.strip(line) if not line: print(self.lastcmd) return self.emptyline() self.lastcmd = line if line[0] == '!': line = 'shell ' + line[1:] elif line[0] == '?': line = 'help ' + line[1:] if os.sep == '\\': line = string.replace(line, '\\', '\\\\') argv = shlex.split(line) argv[0] = self.synonyms.get(argv[0], argv[0]) if not argv[0]: return self.default(line) else: try: func = getattr(self, 'do_' + argv[0]) except AttributeError: return self.default(argv) return func(argv) def do_build(self, argv): """\ build [TARGETS] Build the specified TARGETS and their dependencies. 'b' is a synonym. """ import SCons.Node import SCons.SConsign import SCons.Script.Main options = copy.deepcopy(self.options) options, targets = self.parser.parse_args(argv[1:], values=options) SCons.Script.COMMAND_LINE_TARGETS = targets if targets: SCons.Script.BUILD_TARGETS = targets else: # If the user didn't specify any targets on the command line, # use the list of default targets. SCons.Script.BUILD_TARGETS = SCons.Script._build_plus_default nodes = SCons.Script.Main._build_targets(self.fs, options, targets, self.target_top) if not nodes: return # Call each of the Node's alter_targets() methods, which may # provide additional targets that ended up as part of the build # (the canonical example being a VariantDir() when we're building # from a source directory) and which we therefore need their # state cleared, too. x = [] for n in nodes: x.extend(n.alter_targets()[0]) nodes.extend(x) # Clean up so that we can perform the next build correctly. # # We do this by walking over all the children of the targets, # and clearing their state. # # We currently have to re-scan each node to find their # children, because built nodes have already been partially # cleared and don't remember their children. (In scons # 0.96.1 and earlier, this wasn't the case, and we didn't # have to re-scan the nodes.) # # Because we have to re-scan each node, we can't clear the # nodes as we walk over them, because we may end up rescanning # a cleared node as we scan a later node. Therefore, only # store the list of nodes that need to be cleared as we walk # the tree, and clear them in a separate pass. # # XXX: Someone more familiar with the inner workings of scons # may be able to point out a more efficient way to do this. SCons.Script.Main.progress_display("scons: Clearing cached node information ...") seen_nodes = {} def get_unseen_children(node, parent, seen_nodes=seen_nodes): def is_unseen(node, seen_nodes=seen_nodes): return node not in seen_nodes return filter(is_unseen, node.children(scan=1)) def add_to_seen_nodes(node, parent, seen_nodes=seen_nodes): seen_nodes[node] = 1 # If this file is in a VariantDir and has a # corresponding source file in the source tree, remember the # node in the source tree, too. This is needed in # particular to clear cached implicit dependencies on the # source file, since the scanner will scan it if the # VariantDir was created with duplicate=0. try: rfile_method = node.rfile except AttributeError: return else: rfile = rfile_method() if rfile != node: seen_nodes[rfile] = 1 for node in nodes: walker = SCons.Node.Walker(node, kids_func=get_unseen_children, eval_func=add_to_seen_nodes) n = next(walker) while n: n = next(walker) for node in seen_nodes.keys(): # Call node.clear() to clear most of the state node.clear() # node.clear() doesn't reset node.state, so call # node.set_state() to reset it manually node.set_state(SCons.Node.no_state) node.implicit = None # Debug: Uncomment to verify that all Taskmaster reference # counts have been reset to zero. #if node.ref_count != 0: # from SCons.Debug import Trace # Trace('node %s, ref_count %s !!!\n' % (node, node.ref_count)) SCons.SConsign.Reset() SCons.Script.Main.progress_display("scons: done clearing node information.") def do_clean(self, argv): """\ clean [TARGETS] Clean (remove) the specified TARGETS and their dependencies. 'c' is a synonym. """ return self.do_build(['build', '--clean'] + argv[1:]) def do_EOF(self, argv): print() self.do_exit(argv) def _do_one_help(self, arg): try: # If help_() exists, then call it. func = getattr(self, 'help_' + arg) except AttributeError: try: func = getattr(self, 'do_' + arg) except AttributeError: doc = None else: doc = self._doc_to_help(func) if doc: sys.stdout.write(doc + '\n') sys.stdout.flush() else: doc = self.strip_initial_spaces(func()) if doc: sys.stdout.write(doc + '\n') sys.stdout.flush() def _doc_to_help(self, obj): doc = obj.__doc__ if doc is None: return '' return self._strip_initial_spaces(doc) def _strip_initial_spaces(self, s): #lines = s.split('\n') lines = string.split(s, '\n') spaces = re.match(' *', lines[0]).group(0) #def strip_spaces(l): # if l.startswith(spaces): # l = l[len(spaces):] # return l #return '\n'.join([ strip_spaces(l) for l in lines ]) def strip_spaces(l, spaces=spaces): if l[:len(spaces)] == spaces: l = l[len(spaces):] return l lines = map(strip_spaces, lines) return string.join(lines, '\n') def do_exit(self, argv): """\ exit Exit SCons interactive mode. """ sys.exit(0) def do_help(self, argv): """\ help [COMMAND] Prints help for the specified COMMAND. 'h' and '?' are synonyms. """ if argv[1:]: for arg in argv[1:]: if self._do_one_help(arg): break else: # If bare 'help' is called, print this class's doc # string (if it has one). doc = self._doc_to_help(self.__class__) if doc: sys.stdout.write(doc + '\n') sys.stdout.flush() def do_shell(self, argv): """\ shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and '!' are synonyms. """ import subprocess argv = argv[1:] if not argv: argv = os.environ[self.shell_variable] try: # Per "[Python-Dev] subprocess insufficiently platform-independent?" # http://mail.python.org/pipermail/python-dev/2008-August/081979.html "+ # Doing the right thing with an argument list currently # requires different shell= values on Windows and Linux. p = subprocess.Popen(argv, shell=(sys.platform=='win32')) except EnvironmentError as e: sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror)) else: p.wait() def do_version(self, argv): """\ version Prints SCons version information. """ sys.stdout.write(self.parser.version + '\n') def interact(fs, parser, options, targets, target_top): c = SConsInteractiveCmd(prompt = 'scons>>> ', fs = fs, parser = parser, options = options, targets = targets, target_top = target_top) c.cmdloop() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Script/Main.py0000644000175000017500000014164313606712377022077 0ustar kurtkurt"""SCons.Script This file implements the main() function used by the scons script. Architecturally, this *is* the scons script, and will likely only be called from the external "scons" wrapper. Consequently, anything here should not be, or be considered, part of the build engine. If it's something that we expect other software to want to use, it should go in some other module. If it's specific to the "scons" script invocation, it goes here. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Script/Main.py 4369 2009/09/19 15:58:29 scons" import os import os.path import string import sys import time import traceback # Strip the script directory from sys.path() so on case-insensitive # (Windows) systems Python doesn't think that the "scons" script is the # "SCons" package. Replace it with our own version directory so, if # if they're there, we pick up the right version of the build engine # modules. #sys.path = [os.path.join(sys.prefix, # 'lib', # 'scons-%d' % SCons.__version__)] + sys.path[1:] import SCons.CacheDir import SCons.Debug import SCons.Defaults import SCons.Environment import SCons.Errors import SCons.Job import SCons.Node import SCons.Node.FS import SCons.SConf import SCons.Script import SCons.Taskmaster import SCons.Util import SCons.Warnings import SCons.Script.Interactive def fetch_win32_parallel_msg(): # A subsidiary function that exists solely to isolate this import # so we don't have to pull it in on all platforms, and so that an # in-line "import" statement in the _main() function below doesn't # cause warnings about local names shadowing use of the 'SCons' # globl in nest scopes and UnboundLocalErrors and the like in some # versions (2.1) of Python. import SCons.Platform.win32 return SCons.Platform.win32.parallel_msg # class SConsPrintHelpException(Exception): pass display = SCons.Util.display progress_display = SCons.Util.DisplayEngine() first_command_start = None last_command_end = None class Progressor: prev = '' count = 0 target_string = '$TARGET' def __init__(self, obj, interval=1, file=None, overwrite=False): if file is None: file = sys.stdout self.obj = obj self.file = file self.interval = interval self.overwrite = overwrite if callable(obj): self.func = obj elif SCons.Util.is_List(obj): self.func = self.spinner elif string.find(obj, self.target_string) != -1: self.func = self.replace_string else: self.func = self.string def write(self, s): self.file.write(s) self.file.flush() self.prev = s def erase_previous(self): if self.prev: length = len(self.prev) if self.prev[-1] in ('\n', '\r'): length = length - 1 self.write(' ' * length + '\r') self.prev = '' def spinner(self, node): self.write(self.obj[self.count % len(self.obj)]) def string(self, node): self.write(self.obj) def replace_string(self, node): self.write(string.replace(self.obj, self.target_string, str(node))) def __call__(self, node): self.count = self.count + 1 if (self.count % self.interval) == 0: if self.overwrite: self.erase_previous() self.func(node) ProgressObject = SCons.Util.Null() def Progress(*args, **kw): global ProgressObject ProgressObject = Progressor(*args, **kw) # Task control. # _BuildFailures = [] def GetBuildFailures(): return _BuildFailures class BuildTask(SCons.Taskmaster.OutOfDateTask): """An SCons build task.""" progress = ProgressObject def display(self, message): display('scons: ' + message) def prepare(self): self.progress(self.targets[0]) return SCons.Taskmaster.OutOfDateTask.prepare(self) def needs_execute(self): if SCons.Taskmaster.OutOfDateTask.needs_execute(self): return True if self.top and self.targets[0].has_builder(): display("scons: `%s' is up to date." % str(self.node)) return False def execute(self): if print_time: start_time = time.time() global first_command_start if first_command_start is None: first_command_start = start_time SCons.Taskmaster.OutOfDateTask.execute(self) if print_time: global cumulative_command_time global last_command_end finish_time = time.time() last_command_end = finish_time cumulative_command_time = cumulative_command_time+finish_time-start_time sys.stdout.write("Command execution time: %f seconds\n"%(finish_time-start_time)) def do_failed(self, status=2): _BuildFailures.append(self.exception[1]) global exit_status global this_build_status if self.options.ignore_errors: SCons.Taskmaster.OutOfDateTask.executed(self) elif self.options.keep_going: SCons.Taskmaster.OutOfDateTask.fail_continue(self) exit_status = status this_build_status = status else: SCons.Taskmaster.OutOfDateTask.fail_stop(self) exit_status = status this_build_status = status def executed(self): t = self.targets[0] if self.top and not t.has_builder() and not t.side_effect: if not t.exists(): def classname(obj): return string.split(str(obj.__class__), '.')[-1] if classname(t) in ('File', 'Dir', 'Entry'): errstr="Do not know how to make %s target `%s' (%s)." % (classname(t), t, t.abspath) else: # Alias or Python or ... errstr="Do not know how to make %s target `%s'." % (classname(t), t) sys.stderr.write("scons: *** " + errstr) if not self.options.keep_going: sys.stderr.write(" Stop.") sys.stderr.write("\n") try: raise SCons.Errors.BuildError(t, errstr) except KeyboardInterrupt: raise except: self.exception_set() self.do_failed() else: print("scons: Nothing to be done for `%s'." % t) SCons.Taskmaster.OutOfDateTask.executed(self) else: SCons.Taskmaster.OutOfDateTask.executed(self) def failed(self): # Handle the failure of a build task. The primary purpose here # is to display the various types of Errors and Exceptions # appropriately. exc_info = self.exc_info() try: t, e, tb = exc_info except ValueError: t, e = exc_info tb = None if t is None: # The Taskmaster didn't record an exception for this Task; # see if the sys module has one. try: t, e, tb = sys.exc_info()[:] except ValueError: t, e = exc_info tb = None # Deprecated string exceptions will have their string stored # in the first entry of the tuple. if e is None: e = t buildError = SCons.Errors.convert_to_BuildError(e) if not buildError.node: buildError.node = self.node node = buildError.node if not SCons.Util.is_List(node): node = [ node ] nodename = string.join(map(str, node), ', ') errfmt = "scons: *** [%s] %s\n" sys.stderr.write(errfmt % (nodename, buildError)) if (buildError.exc_info[2] and buildError.exc_info[1] and # TODO(1.5) #not isinstance( # buildError.exc_info[1], # (EnvironmentError, SCons.Errors.StopError, SCons.Errors.UserError))): not isinstance(buildError.exc_info[1], EnvironmentError) and not isinstance(buildError.exc_info[1], SCons.Errors.StopError) and not isinstance(buildError.exc_info[1], SCons.Errors.UserError)): type, value, trace = buildError.exc_info traceback.print_exception(type, value, trace) elif tb and print_stacktrace: sys.stderr.write("scons: internal stack trace:\n") traceback.print_tb(tb, file=sys.stderr) self.exception = (e, buildError, tb) # type, value, traceback self.do_failed(buildError.exitstatus) self.exc_clear() def postprocess(self): if self.top: t = self.targets[0] for tp in self.options.tree_printers: tp.display(t) if self.options.debug_includes: tree = t.render_include_tree() if tree: print() print(tree) SCons.Taskmaster.OutOfDateTask.postprocess(self) def make_ready(self): """Make a task ready for execution""" SCons.Taskmaster.OutOfDateTask.make_ready(self) if self.out_of_date and self.options.debug_explain: explanation = self.out_of_date[0].explain() if explanation: sys.stdout.write("scons: " + explanation) class CleanTask(SCons.Taskmaster.AlwaysTask): """An SCons clean task.""" def fs_delete(self, path, pathstr, remove=1): try: if os.path.lexists(path): if os.path.isfile(path) or os.path.islink(path): if remove: os.unlink(path) display("Removed " + pathstr) elif os.path.isdir(path) and not os.path.islink(path): # delete everything in the dir entries = sorted(os.listdir(path)) # Sort for deterministic output (os.listdir() Can # return entries in a random order). for e in entries: p = os.path.join(path, e) s = os.path.join(pathstr, e) if os.path.isfile(p): if remove: os.unlink(p) display("Removed " + s) else: self.fs_delete(p, s, remove) # then delete dir itself if remove: os.rmdir(path) display("Removed directory " + pathstr) else: errstr = "Path '%s' exists but isn't a file or directory." raise SCons.Errors.UserError(errstr % (pathstr)) except SCons.Errors.UserError as e: print(e) except (IOError, OSError) as e: print("scons: Could not remove '%s':" % pathstr, e.strerror) def show(self): target = self.targets[0] if (target.has_builder() or target.side_effect) and not target.noclean: for t in self.targets: if not t.isdir(): display("Removed " + str(t)) if target in SCons.Environment.CleanTargets: files = SCons.Environment.CleanTargets[target] for f in files: self.fs_delete(f.abspath, str(f), 0) def remove(self): target = self.targets[0] if (target.has_builder() or target.side_effect) and not target.noclean: for t in self.targets: try: removed = t.remove() except OSError as e: # An OSError may indicate something like a permissions # issue, an IOError would indicate something like # the file not existing. In either case, print a # message and keep going to try to remove as many # targets aa possible. print("scons: Could not remove '%s':" % str(t), e.strerror) else: if removed: display("Removed " + str(t)) if target in SCons.Environment.CleanTargets: files = SCons.Environment.CleanTargets[target] for f in files: self.fs_delete(f.abspath, str(f)) execute = remove # We want the Taskmaster to update the Node states (and therefore # handle reference counts, etc.), but we don't want to call # back to the Node's post-build methods, which would do things # we don't want, like store .sconsign information. executed = SCons.Taskmaster.Task.executed_without_callbacks # Have the taskmaster arrange to "execute" all of the targets, because # we'll figure out ourselves (in remove() or show() above) whether # anything really needs to be done. make_ready = SCons.Taskmaster.Task.make_ready_all def prepare(self): pass class QuestionTask(SCons.Taskmaster.AlwaysTask): """An SCons task for the -q (question) option.""" def prepare(self): pass def execute(self): if self.targets[0].get_state() != SCons.Node.up_to_date or \ (self.top and not self.targets[0].exists()): global exit_status global this_build_status exit_status = 1 this_build_status = 1 self.tm.stop() def executed(self): pass class TreePrinter: def __init__(self, derived=False, prune=False, status=False): self.derived = derived self.prune = prune self.status = status def get_all_children(self, node): return node.all_children() def get_derived_children(self, node): children = node.all_children(None) return filter(lambda x: x.has_builder(), children) def display(self, t): if self.derived: func = self.get_derived_children else: func = self.get_all_children s = self.status and 2 or 0 SCons.Util.print_tree(t, func, prune=self.prune, showtags=s) def python_version_string(): return string.split(sys.version)[0] def python_version_unsupported(version=sys.version_info): return version < (1, 5, 2) def python_version_deprecated(version=sys.version_info): return version < (2, 4, 0) # Global variables print_objects = 0 print_memoizer = 0 print_stacktrace = 0 print_time = 0 sconscript_time = 0 cumulative_command_time = 0 exit_status = 0 # final exit status, assume success by default this_build_status = 0 # "exit status" of an individual build num_jobs = None delayed_warnings = [] class FakeOptionParser: """ A do-nothing option parser, used for the initial OptionsParser variable. During normal SCons operation, the OptionsParser is created right away by the main() function. Certain tests scripts however, can introspect on different Tool modules, the initialization of which can try to add a new, local option to an otherwise uninitialized OptionsParser object. This allows that introspection to happen without blowing up. """ class FakeOptionValues: def __getattr__(self, attr): return None values = FakeOptionValues() def add_local_option(self, *args, **kw): pass OptionsParser = FakeOptionParser() def AddOption(*args, **kw): if 'default' not in kw: kw['default'] = None result = OptionsParser.add_local_option(*args, **kw) return result def GetOption(name): return getattr(OptionsParser.values, name) def SetOption(name, value): return OptionsParser.values.set_option(name, value) # class Stats: def __init__(self): self.stats = [] self.labels = [] self.append = self.do_nothing self.print_stats = self.do_nothing def enable(self, outfp): self.outfp = outfp self.append = self.do_append self.print_stats = self.do_print def do_nothing(self, *args, **kw): pass class CountStats(Stats): def do_append(self, label): self.labels.append(label) self.stats.append(SCons.Debug.fetchLoggedInstances()) def do_print(self): stats_table = {} for s in self.stats: for n in map(lambda t: t[0], s): stats_table[n] = [0, 0, 0, 0] i = 0 for s in self.stats: for n, c in s: stats_table[n][i] = c i = i + 1 keys = sorted(stats_table.keys()) self.outfp.write("Object counts:\n") pre = [" "] post = [" %s\n"] l = len(self.stats) fmt1 = string.join(pre + [' %7s']*l + post, '') fmt2 = string.join(pre + [' %7d']*l + post, '') labels = self.labels[:l] labels.append(("", "Class")) self.outfp.write(fmt1 % tuple(map(lambda x: x[0], labels))) self.outfp.write(fmt1 % tuple(map(lambda x: x[1], labels))) for k in keys: r = stats_table[k][:l] + [k] self.outfp.write(fmt2 % tuple(r)) count_stats = CountStats() class MemStats(Stats): def do_append(self, label): self.labels.append(label) self.stats.append(SCons.Debug.memory()) def do_print(self): fmt = 'Memory %-32s %12d\n' for label, stats in map(None, self.labels, self.stats): self.outfp.write(fmt % (label, stats)) memory_stats = MemStats() # utility functions def _scons_syntax_error(e): """Handle syntax errors. Print out a message and show where the error occurred. """ etype, value, tb = sys.exc_info() lines = traceback.format_exception_only(etype, value) for line in lines: sys.stderr.write(line+'\n') sys.exit(2) def find_deepest_user_frame(tb): """ Find the deepest stack frame that is not part of SCons. Input is a "pre-processed" stack trace in the form returned by traceback.extract_tb() or traceback.extract_stack() """ tb.reverse() # find the deepest traceback frame that is not part # of SCons: for frame in tb: filename = frame[0] if string.find(filename, os.sep+'SCons'+os.sep) == -1: return frame return tb[0] def _scons_user_error(e): """Handle user errors. Print out a message and a description of the error, along with the line number and routine where it occured. The file and line number will be the deepest stack frame that is not part of SCons itself. """ global print_stacktrace etype, value, tb = sys.exc_info() if print_stacktrace: traceback.print_exception(etype, value, tb) filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb)) sys.stderr.write("\nscons: *** %s\n" % value) sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine)) sys.exit(2) def _scons_user_warning(e): """Handle user warnings. Print out a message and a description of the warning, along with the line number and routine where it occured. The file and line number will be the deepest stack frame that is not part of SCons itself. """ etype, value, tb = sys.exc_info() filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb)) sys.stderr.write("\nscons: warning: %s\n" % e) sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine)) def _scons_internal_warning(e): """Slightly different from _scons_user_warning in that we use the *current call stack* rather than sys.exc_info() to get our stack trace. This is used by the warnings framework to print warnings.""" filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_stack()) sys.stderr.write("\nscons: warning: %s\n" % e[0]) sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine)) def _scons_internal_error(): """Handle all errors but user errors. Print out a message telling the user what to do in this case and print a normal trace. """ print('internal error') traceback.print_exc() sys.exit(2) def _SConstruct_exists(dirname='', repositories=[], filelist=None): """This function checks that an SConstruct file exists in a directory. If so, it returns the path of the file. By default, it checks the current directory. """ if not filelist: filelist = ['SConstruct', 'Sconstruct', 'sconstruct'] for file in filelist: sfile = os.path.join(dirname, file) if os.path.isfile(sfile): return sfile if not os.path.isabs(sfile): for rep in repositories: if os.path.isfile(os.path.join(rep, sfile)): return sfile return None def _set_debug_values(options): global print_memoizer, print_objects, print_stacktrace, print_time debug_values = options.debug if "count" in debug_values: # All of the object counts are within "if __debug__:" blocks, # which get stripped when running optimized (with python -O or # from compiled *.pyo files). Provide a warning if __debug__ is # stripped, so it doesn't just look like --debug=count is broken. enable_count = False if __debug__: enable_count = True if enable_count: count_stats.enable(sys.stdout) else: msg = "--debug=count is not supported when running SCons\n" + \ "\twith the python -O option or optimized (.pyo) modules." SCons.Warnings.warn(SCons.Warnings.NoObjectCountWarning, msg) if "dtree" in debug_values: options.tree_printers.append(TreePrinter(derived=True)) options.debug_explain = ("explain" in debug_values) if "findlibs" in debug_values: SCons.Scanner.Prog.print_find_libs = "findlibs" options.debug_includes = ("includes" in debug_values) print_memoizer = ("memoizer" in debug_values) if "memory" in debug_values: memory_stats.enable(sys.stdout) print_objects = ("objects" in debug_values) if "presub" in debug_values: SCons.Action.print_actions_presub = 1 if "stacktrace" in debug_values: print_stacktrace = 1 if "stree" in debug_values: options.tree_printers.append(TreePrinter(status=True)) if "time" in debug_values: print_time = 1 if "tree" in debug_values: options.tree_printers.append(TreePrinter()) def _create_path(plist): path = '.' for d in plist: if os.path.isabs(d): path = d else: path = path + '/' + d return path def _load_site_scons_dir(topdir, site_dir_name=None): """Load the site_scons dir under topdir. Adds site_scons to sys.path, imports site_scons/site_init.py, and adds site_scons/site_tools to default toolpath.""" if site_dir_name: err_if_not_found = True # user specified: err if missing else: site_dir_name = "site_scons" err_if_not_found = False site_dir = os.path.join(topdir.path, site_dir_name) if not os.path.exists(site_dir): if err_if_not_found: raise SCons.Errors.UserError("site dir %s not found."%site_dir) return site_init_filename = "site_init.py" site_init_modname = "site_init" site_tools_dirname = "site_tools" sys.path = [os.path.abspath(site_dir)] + sys.path site_init_file = os.path.join(site_dir, site_init_filename) site_tools_dir = os.path.join(site_dir, site_tools_dirname) if os.path.exists(site_init_file): import imp # TODO(2.4): turn this into try:-except:-finally: try: try: fp, pathname, description = imp.find_module(site_init_modname, [site_dir]) # Load the file into SCons.Script namespace. This is # opaque and clever; m is the module object for the # SCons.Script module, and the exec ... in call executes a # file (or string containing code) in the context of the # module's dictionary, so anything that code defines ends # up adding to that module. This is really short, but all # the error checking makes it longer. try: m = sys.modules['SCons.Script'] except Exception as e: fmt = 'cannot import site_init.py: missing SCons.Script module %s' raise SCons.Errors.InternalError(fmt % repr(e)) try: # This is the magic. exec(fp, m.__dict__) except KeyboardInterrupt: raise except Exception as e: fmt = '*** Error loading site_init file %s:\n' sys.stderr.write(fmt % repr(site_init_file)) raise except KeyboardInterrupt: raise except ImportError as e: fmt = '*** cannot import site init file %s:\n' sys.stderr.write(fmt % repr(site_init_file)) raise finally: if fp: fp.close() if os.path.exists(site_tools_dir): SCons.Tool.DefaultToolpath.append(os.path.abspath(site_tools_dir)) def version_string(label, module): version = module.__version__ build = module.__build__ if build: if build[0] != '.': build = '.' + build version = version + build fmt = "\t%s: v%s, %s, by %s on %s\n" return fmt % (label, version, module.__date__, module.__developer__, module.__buildsys__) def _main(parser): global exit_status global this_build_status options = parser.values # Here's where everything really happens. # First order of business: set up default warnings and then # handle the user's warning options, so that we can issue (or # suppress) appropriate warnings about anything that might happen, # as configured by the user. default_warnings = [ SCons.Warnings.CorruptSConsignWarning, SCons.Warnings.DeprecatedWarning, SCons.Warnings.DuplicateEnvironmentWarning, SCons.Warnings.FutureReservedVariableWarning, SCons.Warnings.LinkWarning, SCons.Warnings.MissingSConscriptWarning, SCons.Warnings.NoMD5ModuleWarning, SCons.Warnings.NoMetaclassSupportWarning, SCons.Warnings.NoObjectCountWarning, SCons.Warnings.NoParallelSupportWarning, SCons.Warnings.MisleadingKeywordsWarning, SCons.Warnings.ReservedVariableWarning, SCons.Warnings.StackSizeWarning, ] for warning in default_warnings: SCons.Warnings.enableWarningClass(warning) SCons.Warnings._warningOut = _scons_internal_warning SCons.Warnings.process_warn_strings(options.warn) # Now that we have the warnings configuration set up, we can actually # issue (or suppress) any warnings about warning-worthy things that # occurred while the command-line options were getting parsed. try: dw = options.delayed_warnings except AttributeError: pass else: delayed_warnings.extend(dw) for warning_type, message in delayed_warnings: SCons.Warnings.warn(warning_type, message) if options.diskcheck: SCons.Node.FS.set_diskcheck(options.diskcheck) # Next, we want to create the FS object that represents the outside # world's file system, as that's central to a lot of initialization. # To do this, however, we need to be in the directory from which we # want to start everything, which means first handling any relevant # options that might cause us to chdir somewhere (-C, -D, -U, -u). if options.directory: cdir = _create_path(options.directory) try: os.chdir(cdir) except OSError: sys.stderr.write("Could not change directory to %s\n" % cdir) target_top = None if options.climb_up: target_top = '.' # directory to prepend to targets script_dir = os.getcwd() # location of script while script_dir and not _SConstruct_exists(script_dir, options.repository, options.file): script_dir, last_part = os.path.split(script_dir) if last_part: target_top = os.path.join(last_part, target_top) else: script_dir = '' if script_dir and script_dir != os.getcwd(): display("scons: Entering directory `%s'" % script_dir) os.chdir(script_dir) # Now that we're in the top-level SConstruct directory, go ahead # and initialize the FS object that represents the file system, # and make it the build engine default. fs = SCons.Node.FS.get_default_fs() for rep in options.repository: fs.Repository(rep) # Now that we have the FS object, the next order of business is to # check for an SConstruct file (or other specified config file). # If there isn't one, we can bail before doing any more work. scripts = [] if options.file: scripts.extend(options.file) if not scripts: sfile = _SConstruct_exists(repositories=options.repository, filelist=options.file) if sfile: scripts.append(sfile) if not scripts: if options.help: # There's no SConstruct, but they specified -h. # Give them the options usage now, before we fail # trying to read a non-existent SConstruct file. raise SConsPrintHelpException raise SCons.Errors.UserError("No SConstruct file found.") if scripts[0] == "-": d = fs.getcwd() else: d = fs.File(scripts[0]).dir fs.set_SConstruct_dir(d) _set_debug_values(options) SCons.Node.implicit_cache = options.implicit_cache SCons.Node.implicit_deps_changed = options.implicit_deps_changed SCons.Node.implicit_deps_unchanged = options.implicit_deps_unchanged if options.no_exec: SCons.SConf.dryrun = 1 SCons.Action.execute_actions = None if options.question: SCons.SConf.dryrun = 1 if options.clean: SCons.SConf.SetBuildType('clean') if options.help: SCons.SConf.SetBuildType('help') SCons.SConf.SetCacheMode(options.config) SCons.SConf.SetProgressDisplay(progress_display) if options.no_progress or options.silent: progress_display.set_mode(0) if options.site_dir: _load_site_scons_dir(d, options.site_dir) elif not options.no_site_dir: _load_site_scons_dir(d) if options.include_dir: sys.path = options.include_dir + sys.path # That should cover (most of) the options. Next, set up the variables # that hold command-line arguments, so the SConscript files that we # read and execute have access to them. targets = [] xmit_args = [] for a in parser.largs: if a[:1] == '-': continue if '=' in a: xmit_args.append(a) else: targets.append(a) SCons.Script._Add_Targets(targets + parser.rargs) SCons.Script._Add_Arguments(xmit_args) # If stdout is not a tty, replace it with a wrapper object to call flush # after every write. # # Tty devices automatically flush after every newline, so the replacement # isn't necessary. Furthermore, if we replace sys.stdout, the readline # module will no longer work. This affects the behavior during # --interactive mode. --interactive should only be used when stdin and # stdout refer to a tty. if not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty(): sys.stdout = SCons.Util.Unbuffered(sys.stdout) if not hasattr(sys.stderr, 'isatty') or not sys.stderr.isatty(): sys.stderr = SCons.Util.Unbuffered(sys.stderr) memory_stats.append('before reading SConscript files:') count_stats.append(('pre-', 'read')) # And here's where we (finally) read the SConscript files. progress_display("scons: Reading SConscript files ...") start_time = time.time() try: for script in scripts: SCons.Script._SConscript._SConscript(fs, script) except SCons.Errors.StopError as e: # We had problems reading an SConscript file, such as it # couldn't be copied in to the VariantDir. Since we're just # reading SConscript files and haven't started building # things yet, stop regardless of whether they used -i or -k # or anything else. sys.stderr.write("scons: *** %s Stop.\n" % e) exit_status = 2 sys.exit(exit_status) global sconscript_time sconscript_time = time.time() - start_time progress_display("scons: done reading SConscript files.") memory_stats.append('after reading SConscript files:') count_stats.append(('post-', 'read')) # Re-{enable,disable} warnings in case they disabled some in # the SConscript file. # # We delay enabling the PythonVersionWarning class until here so that, # if they explicity disabled it in either in the command line or in # $SCONSFLAGS, or in the SConscript file, then the search through # the list of deprecated warning classes will find that disabling # first and not issue the warning. SCons.Warnings.enableWarningClass(SCons.Warnings.PythonVersionWarning) SCons.Warnings.process_warn_strings(options.warn) # Now that we've read the SConscript files, we can check for the # warning about deprecated Python versions--delayed until here # in case they disabled the warning in the SConscript files. if python_version_deprecated(): msg = "Support for pre-2.4 Python (%s) is deprecated.\n" + \ " If this will cause hardship, contact dev@scons.tigris.org." SCons.Warnings.warn(SCons.Warnings.PythonVersionWarning, msg % python_version_string()) if not options.help: SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment()) # Now re-parse the command-line options (any to the left of a '--' # argument, that is) with any user-defined command-line options that # the SConscript files may have added to the parser object. This will # emit the appropriate error message and exit if any unknown option # was specified on the command line. parser.preserve_unknown_options = False parser.parse_args(parser.largs, options) if options.help: help_text = SCons.Script.help_text if help_text is None: # They specified -h, but there was no Help() inside the # SConscript files. Give them the options usage. raise SConsPrintHelpException else: print(help_text) print("Use scons -H for help about command-line options.") exit_status = 0 return # Change directory to the top-level SConstruct directory, then tell # the Node.FS subsystem that we're all done reading the SConscript # files and calling Repository() and VariantDir() and changing # directories and the like, so it can go ahead and start memoizing # the string values of file system nodes. fs.chdir(fs.Top) SCons.Node.FS.save_strings(1) # Now that we've read the SConscripts we can set the options # that are SConscript settable: SCons.Node.implicit_cache = options.implicit_cache SCons.Node.FS.set_duplicate(options.duplicate) fs.set_max_drift(options.max_drift) SCons.Job.explicit_stack_size = options.stack_size if options.md5_chunksize: SCons.Node.FS.File.md5_chunksize = options.md5_chunksize platform = SCons.Platform.platform_module() if options.interactive: SCons.Script.Interactive.interact(fs, OptionsParser, options, targets, target_top) else: # Build the targets nodes = _build_targets(fs, options, targets, target_top) if not nodes: exit_status = 2 def _build_targets(fs, options, targets, target_top): global this_build_status this_build_status = 0 progress_display.set_mode(not (options.no_progress or options.silent)) display.set_mode(not options.silent) SCons.Action.print_actions = not options.silent SCons.Action.execute_actions = not options.no_exec SCons.Node.FS.do_store_info = not options.no_exec SCons.SConf.dryrun = options.no_exec if options.diskcheck: SCons.Node.FS.set_diskcheck(options.diskcheck) SCons.CacheDir.cache_enabled = not options.cache_disable SCons.CacheDir.cache_debug = options.cache_debug SCons.CacheDir.cache_force = options.cache_force SCons.CacheDir.cache_show = options.cache_show if options.no_exec: CleanTask.execute = CleanTask.show else: CleanTask.execute = CleanTask.remove lookup_top = None if targets or SCons.Script.BUILD_TARGETS != SCons.Script._build_plus_default: # They specified targets on the command line or modified # BUILD_TARGETS in the SConscript file(s), so if they used -u, # -U or -D, we have to look up targets relative to the top, # but we build whatever they specified. if target_top: lookup_top = fs.Dir(target_top) target_top = None targets = SCons.Script.BUILD_TARGETS else: # There are no targets specified on the command line, # so if they used -u, -U or -D, we may have to restrict # what actually gets built. d = None if target_top: if options.climb_up == 1: # -u, local directory and below target_top = fs.Dir(target_top) lookup_top = target_top elif options.climb_up == 2: # -D, all Default() targets target_top = None lookup_top = None elif options.climb_up == 3: # -U, local SConscript Default() targets target_top = fs.Dir(target_top) def check_dir(x, target_top=target_top): if hasattr(x, 'cwd') and not x.cwd is None: cwd = x.cwd.srcnode() return cwd == target_top else: # x doesn't have a cwd, so it's either not a target, # or not a file, so go ahead and keep it as a default # target and let the engine sort it out: return 1 d = filter(check_dir, SCons.Script.DEFAULT_TARGETS) SCons.Script.DEFAULT_TARGETS[:] = d target_top = None lookup_top = None targets = SCons.Script._Get_Default_Targets(d, fs) if not targets: sys.stderr.write("scons: *** No targets specified and no Default() targets found. Stop.\n") return None def Entry(x, ltop=lookup_top, ttop=target_top, fs=fs): if isinstance(x, SCons.Node.Node): node = x else: node = None # Why would ltop be None? Unfortunately this happens. if ltop is None: ltop = '' # Curdir becomes important when SCons is called with -u, -C, # or similar option that changes directory, and so the paths # of targets given on the command line need to be adjusted. curdir = os.path.join(os.getcwd(), str(ltop)) for lookup in SCons.Node.arg2nodes_lookups: node = lookup(x, curdir=curdir) if node is not None: break if node is None: node = fs.Entry(x, directory=ltop, create=1) if ttop and not node.is_under(ttop): if isinstance(node, SCons.Node.FS.Dir) and ttop.is_under(node): node = ttop else: node = None return node nodes = filter(None, map(Entry, targets)) task_class = BuildTask # default action is to build targets opening_message = "Building targets ..." closing_message = "done building targets." if options.keep_going: failure_message = "done building targets (errors occurred during build)." else: failure_message = "building terminated because of errors." if options.question: task_class = QuestionTask try: if options.clean: task_class = CleanTask opening_message = "Cleaning targets ..." closing_message = "done cleaning targets." if options.keep_going: failure_message = "done cleaning targets (errors occurred during clean)." else: failure_message = "cleaning terminated because of errors." except AttributeError: pass task_class.progress = ProgressObject if options.random: def order(dependencies): """Randomize the dependencies.""" import random # This is cribbed from the implementation of # random.shuffle() in Python 2.X. d = dependencies for i in xrange(len(d)-1, 0, -1): j = int(random.random() * (i+1)) d[i], d[j] = d[j], d[i] return d else: def order(dependencies): """Leave the order of dependencies alone.""" return dependencies if options.taskmastertrace_file == '-': tmtrace = sys.stdout elif options.taskmastertrace_file: tmtrace = open(options.taskmastertrace_file, 'wb') else: tmtrace = None taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace) # Let the BuildTask objects get at the options to respond to the # various print_* settings, tree_printer list, etc. BuildTask.options = options global num_jobs num_jobs = options.num_jobs jobs = SCons.Job.Jobs(num_jobs, taskmaster) if num_jobs > 1: msg = None if jobs.num_jobs == 1: msg = "parallel builds are unsupported by this version of Python;\n" + \ "\tignoring -j or num_jobs option.\n" elif sys.platform == 'win32': msg = fetch_win32_parallel_msg() if msg: SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg) memory_stats.append('before building targets:') count_stats.append(('pre-', 'build')) def jobs_postfunc( jobs=jobs, options=options, closing_message=closing_message, failure_message=failure_message ): if jobs.were_interrupted(): if not options.no_progress and not options.silent: sys.stderr.write("scons: Build interrupted.\n") global exit_status global this_build_status exit_status = 2 this_build_status = 2 if this_build_status: progress_display("scons: " + failure_message) else: progress_display("scons: " + closing_message) if not options.no_exec: if jobs.were_interrupted(): progress_display("scons: writing .sconsign file.") SCons.SConsign.write() progress_display("scons: " + opening_message) jobs.run(postfunc = jobs_postfunc) memory_stats.append('after building targets:') count_stats.append(('post-', 'build')) return nodes def _exec_main(parser, values): sconsflags = os.environ.get('SCONSFLAGS', '') all_args = string.split(sconsflags) + sys.argv[1:] options, args = parser.parse_args(all_args, values) if isinstance(options.debug, type([])) and "pdb" in options.debug: import pdb pdb.Pdb().runcall(_main, parser) elif options.profile_file: try: from cProfile import Profile except ImportError as e: from profile import Profile # Some versions of Python 2.4 shipped a profiler that had the # wrong 'c_exception' entry in its dispatch table. Make sure # we have the right one. (This may put an unnecessary entry # in the table in earlier versions of Python, but its presence # shouldn't hurt anything). try: dispatch = Profile.dispatch except AttributeError: pass else: dispatch['c_exception'] = Profile.trace_dispatch_return prof = Profile() try: prof.runcall(_main, parser) except SConsPrintHelpException as e: prof.dump_stats(options.profile_file) raise e except SystemExit: pass prof.dump_stats(options.profile_file) else: _main(parser) def main(): global OptionsParser global exit_status global first_command_start # Check up front for a Python version we do not support. We # delay the check for deprecated Python versions until later, # after the SConscript files have been read, in case they # disable that warning. if python_version_unsupported(): msg = "scons: *** SCons version %s does not run under Python version %s.\n" sys.stderr.write(msg % (SCons.__version__, python_version_string())) sys.exit(1) parts = ["SCons by Steven Knight et al.:\n"] try: import __main__ parts.append(version_string("script", __main__)) except (ImportError, AttributeError): # On Windows there is no scons.py, so there is no # __main__.__version__, hence there is no script version. pass parts.append(version_string("engine", SCons)) parts.append("Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation") version = string.join(parts, '') import SConsOptions parser = SConsOptions.Parser(version) values = SConsOptions.SConsValues(parser.get_default_values()) OptionsParser = parser try: _exec_main(parser, values) except SystemExit as s: if s: exit_status = s except KeyboardInterrupt: print("scons: Build interrupted.") sys.exit(2) except SyntaxError as e: _scons_syntax_error(e) except SCons.Errors.InternalError: _scons_internal_error() except SCons.Errors.UserError as e: _scons_user_error(e) except SConsPrintHelpException: parser.print_help() exit_status = 0 except SCons.Errors.BuildError as e: exit_status = e.exitstatus except: # An exception here is likely a builtin Python exception Python # code in an SConscript file. Show them precisely what the # problem was and where it happened. SCons.Script._SConscript.SConscript_exception() sys.exit(2) memory_stats.print_stats() count_stats.print_stats() if print_objects: SCons.Debug.listLoggedInstances('*') #SCons.Debug.dumpLoggedInstances('*') if print_memoizer: SCons.Memoize.Dump("Memoizer (memory cache) hits and misses:") # Dump any development debug info that may have been enabled. # These are purely for internal debugging during development, so # there's no need to control them with --debug= options; they're # controlled by changing the source code. SCons.Debug.dump_caller_counts() SCons.Taskmaster.dump_stats() if print_time: total_time = time.time() - SCons.Script.start_time if num_jobs == 1: ct = cumulative_command_time else: if last_command_end is None or first_command_start is None: ct = 0.0 else: ct = last_command_end - first_command_start scons_time = total_time - sconscript_time - ct print("Total build time: %f seconds"%total_time) print("Total SConscript file execution time: %f seconds"%sconscript_time) print("Total SCons execution time: %f seconds"%scons_time) print("Total command execution time: %f seconds"%ct) sys.exit(exit_status) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Script/SConscript.py0000644000175000017500000005730713606712377023305 0ustar kurtkurt"""SCons.Script.SConscript This module defines the Python API provided to SConscript and SConstruct files. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Script/SConscript.py 4369 2009/09/19 15:58:29 scons" import SCons import SCons.Action import SCons.Builder import SCons.Defaults import SCons.Environment import SCons.Errors import SCons.Node import SCons.Node.Alias import SCons.Node.FS import SCons.Platform import SCons.SConf import SCons.Script.Main import SCons.Tool import SCons.Util import os import os.path import re import string import sys import traceback import types import UserList # The following variables used to live in this module. Some # SConscript files out there may have referred to them directly as # SCons.Script.SConscript.*. This is now supported by some special # handling towards the bottom of the SConscript.__init__.py module. #Arguments = {} #ArgList = [] #BuildTargets = TargetList() #CommandLineTargets = [] #DefaultTargets = [] class SConscriptReturn(Exception): pass launch_dir = os.path.abspath(os.curdir) GlobalDict = None # global exports set by Export(): global_exports = {} # chdir flag sconscript_chdir = 1 def get_calling_namespaces(): """Return the locals and globals for the function that called into this module in the current call stack.""" try: 1/0 except ZeroDivisionError: # Don't start iterating with the current stack-frame to # prevent creating reference cycles (f_back is safe). frame = sys.exc_info()[2].tb_frame.f_back # Find the first frame that *isn't* from this file. This means # that we expect all of the SCons frames that implement an Export() # or SConscript() call to be in this file, so that we can identify # the first non-Script.SConscript frame as the user's local calling # environment, and the locals and globals dictionaries from that # frame as the calling namespaces. See the comment below preceding # the DefaultEnvironmentCall block for even more explanation. while frame.f_globals.get("__name__") == __name__: frame = frame.f_back return frame.f_locals, frame.f_globals def compute_exports(exports): """Compute a dictionary of exports given one of the parameters to the Export() function or the exports argument to SConscript().""" loc, glob = get_calling_namespaces() retval = {} try: for export in exports: if SCons.Util.is_Dict(export): retval.update(export) else: try: retval[export] = loc[export] except KeyError: retval[export] = glob[export] except KeyError as x: raise SCons.Errors.UserError("Export of non-existent variable '%s'"%x) return retval class Frame: """A frame on the SConstruct/SConscript call stack""" def __init__(self, fs, exports, sconscript): self.globals = BuildDefaultGlobals() self.retval = None self.prev_dir = fs.getcwd() self.exports = compute_exports(exports) # exports from the calling SConscript # make sure the sconscript attr is a Node. if isinstance(sconscript, SCons.Node.Node): self.sconscript = sconscript elif sconscript == '-': self.sconscript = None else: self.sconscript = fs.File(str(sconscript)) # the SConstruct/SConscript call stack: call_stack = [] # For documentation on the methods in this file, see the scons man-page def Return(*vars, **kw): retval = [] try: fvars = SCons.Util.flatten(vars) for var in fvars: for v in string.split(var): retval.append(call_stack[-1].globals[v]) except KeyError as x: raise SCons.Errors.UserError("Return of non-existent variable '%s'"%x) if len(retval) == 1: call_stack[-1].retval = retval[0] else: call_stack[-1].retval = tuple(retval) stop = kw.get('stop', True) if stop: raise SConscriptReturn stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :) def _SConscript(fs, *files, **kw): top = fs.Top sd = fs.SConstruct_dir.rdir() exports = kw.get('exports', []) # evaluate each SConscript file results = [] for fn in files: call_stack.append(Frame(fs, exports, fn)) old_sys_path = sys.path try: SCons.Script.sconscript_reading = SCons.Script.sconscript_reading + 1 if fn == "-": exec(sys.stdin, call_stack[-1].globals) else: if isinstance(fn, SCons.Node.Node): f = fn else: f = fs.File(str(fn)) _file_ = None # Change directory to the top of the source # tree to make sure the os's cwd and the cwd of # fs match so we can open the SConscript. fs.chdir(top, change_os_dir=1) if f.rexists(): actual = f.rfile() _file_ = open(actual.get_abspath(), "r") elif f.srcnode().rexists(): actual = f.srcnode().rfile() _file_ = open(actual.get_abspath(), "r") elif f.has_src_builder(): # The SConscript file apparently exists in a source # code management system. Build it, but then clear # the builder so that it doesn't get built *again* # during the actual build phase. f.build() f.built() f.builder_set(None) if f.exists(): _file_ = open(f.get_abspath(), "r") if _file_: # Chdir to the SConscript directory. Use a path # name relative to the SConstruct file so that if # we're using the -f option, we're essentially # creating a parallel SConscript directory structure # in our local directory tree. # # XXX This is broken for multiple-repository cases # where the SConstruct and SConscript files might be # in different Repositories. For now, cross that # bridge when someone comes to it. try: src_dir = kw['src_dir'] except KeyError: ldir = fs.Dir(f.dir.get_path(sd)) else: ldir = fs.Dir(src_dir) if not ldir.is_under(f.dir): # They specified a source directory, but # it's above the SConscript directory. # Do the sensible thing and just use the # SConcript directory. ldir = fs.Dir(f.dir.get_path(sd)) try: fs.chdir(ldir, change_os_dir=sconscript_chdir) except OSError: # There was no local directory, so we should be # able to chdir to the Repository directory. # Note that we do this directly, not through # fs.chdir(), because we still need to # interpret the stuff within the SConscript file # relative to where we are logically. fs.chdir(ldir, change_os_dir=0) os.chdir(actual.dir.get_abspath()) # Append the SConscript directory to the beginning # of sys.path so Python modules in the SConscript # directory can be easily imported. sys.path = [ f.dir.get_abspath() ] + sys.path # This is the magic line that actually reads up # and executes the stuff in the SConscript file. # The locals for this frame contain the special # bottom-of-the-stack marker so that any # exceptions that occur when processing this # SConscript can base the printed frames at this # level and not show SCons internals as well. call_stack[-1].globals.update({stack_bottom:1}) old_file = call_stack[-1].globals.get('__file__') try: del call_stack[-1].globals['__file__'] except KeyError: pass try: try: exec(_file_, call_stack[-1].globals) except SConscriptReturn: pass finally: if old_file is not None: call_stack[-1].globals.update({__file__:old_file}) else: SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, "Ignoring missing SConscript '%s'" % f.path) finally: SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1 sys.path = old_sys_path frame = call_stack.pop() try: fs.chdir(frame.prev_dir, change_os_dir=sconscript_chdir) except OSError: # There was no local directory, so chdir to the # Repository directory. Like above, we do this # directly. fs.chdir(frame.prev_dir, change_os_dir=0) rdir = frame.prev_dir.rdir() rdir._create() # Make sure there's a directory there. try: os.chdir(rdir.get_abspath()) except OSError as e: # We still couldn't chdir there, so raise the error, # but only if actions are being executed. # # If the -n option was used, the directory would *not* # have been created and we should just carry on and # let things muddle through. This isn't guaranteed # to work if the SConscript files are reading things # from disk (for example), but it should work well # enough for most configurations. if SCons.Action.execute_actions: raise e results.append(frame.retval) # if we only have one script, don't return a tuple if len(results) == 1: return results[0] else: return tuple(results) def SConscript_exception(file=sys.stderr): """Print an exception stack trace just for the SConscript file(s). This will show users who have Python errors where the problem is, without cluttering the output with all of the internal calls leading up to where we exec the SConscript.""" exc_type, exc_value, exc_tb = sys.exc_info() tb = exc_tb while tb and stack_bottom not in tb.tb_frame.f_locals: tb = tb.tb_next if not tb: # We did not find our exec statement, so this was actually a bug # in SCons itself. Show the whole stack. tb = exc_tb stack = traceback.extract_tb(tb) try: type = exc_type.__name__ except AttributeError: type = str(exc_type) if type[:11] == "exceptions.": type = type[11:] file.write('%s: %s:\n' % (type, exc_value)) for fname, line, func, text in stack: file.write(' File "%s", line %d:\n' % (fname, line)) file.write(' %s\n' % text) def annotate(node): """Annotate a node with the stack frame describing the SConscript file and line number that created it.""" tb = sys.exc_info()[2] while tb and stack_bottom not in tb.tb_frame.f_locals: tb = tb.tb_next if not tb: # We did not find any exec of an SConscript file: what?! raise SCons.Errors.InternalError("could not find SConscript stack frame") node.creator = traceback.extract_stack(tb)[0] # The following line would cause each Node to be annotated using the # above function. Unfortunately, this is a *huge* performance hit, so # leave this disabled until we find a more efficient mechanism. #SCons.Node.Annotate = annotate class SConsEnvironment(SCons.Environment.Base): """An Environment subclass that contains all of the methods that are particular to the wrapper SCons interface and which aren't (or shouldn't be) part of the build engine itself. Note that not all of the methods of this class have corresponding global functions, there are some private methods. """ # # Private methods of an SConsEnvironment. # def _exceeds_version(self, major, minor, v_major, v_minor): """Return 1 if 'major' and 'minor' are greater than the version in 'v_major' and 'v_minor', and 0 otherwise.""" return (major > v_major or (major == v_major and minor > v_minor)) def _get_major_minor_revision(self, version_string): """Split a version string into major, minor and (optionally) revision parts. This is complicated by the fact that a version string can be something like 3.2b1.""" version = string.split(string.split(version_string, ' ')[0], '.') v_major = int(version[0]) v_minor = int(re.match('\d+', version[1]).group()) if len(version) >= 3: v_revision = int(re.match('\d+', version[2]).group()) else: v_revision = 0 return v_major, v_minor, v_revision def _get_SConscript_filenames(self, ls, kw): """ Convert the parameters passed to # SConscript() calls into a list of files and export variables. If the parameters are invalid, throws SCons.Errors.UserError. Returns a tuple (l, e) where l is a list of SConscript filenames and e is a list of exports. """ exports = [] if len(ls) == 0: try: dirs = kw["dirs"] except KeyError: raise SCons.Errors.UserError("Invalid SConscript usage - no parameters") if not SCons.Util.is_List(dirs): dirs = [ dirs ] dirs = map(str, dirs) name = kw.get('name', 'SConscript') files = map(lambda n, name = name: os.path.join(n, name), dirs) elif len(ls) == 1: files = ls[0] elif len(ls) == 2: files = ls[0] exports = self.Split(ls[1]) else: raise SCons.Errors.UserError("Invalid SConscript() usage - too many arguments") if not SCons.Util.is_List(files): files = [ files ] if kw.get('exports'): exports.extend(self.Split(kw['exports'])) variant_dir = kw.get('variant_dir') or kw.get('build_dir') if variant_dir: if len(files) != 1: raise SCons.Errors.UserError("Invalid SConscript() usage - can only specify one SConscript with a variant_dir") duplicate = kw.get('duplicate', 1) src_dir = kw.get('src_dir') if not src_dir: src_dir, fname = os.path.split(str(files[0])) files = [os.path.join(str(variant_dir), fname)] else: if not isinstance(src_dir, SCons.Node.Node): src_dir = self.fs.Dir(src_dir) fn = files[0] if not isinstance(fn, SCons.Node.Node): fn = self.fs.File(fn) if fn.is_under(src_dir): # Get path relative to the source directory. fname = fn.get_path(src_dir) files = [os.path.join(str(variant_dir), fname)] else: files = [fn.abspath] kw['src_dir'] = variant_dir self.fs.VariantDir(variant_dir, src_dir, duplicate) return (files, exports) # # Public methods of an SConsEnvironment. These get # entry points in the global name space so they can be called # as global functions. # def Configure(self, *args, **kw): if not SCons.Script.sconscript_reading: raise SCons.Errors.UserError("Calling Configure from Builders is not supported.") kw['_depth'] = kw.get('_depth', 0) + 1 return SCons.Environment.Base.Configure(*(self,)+args, **kw) def Default(self, *targets): SCons.Script._Set_Default_Targets(self, targets) def EnsureSConsVersion(self, major, minor, revision=0): """Exit abnormally if the SCons version is not late enough.""" scons_ver = self._get_major_minor_revision(SCons.__version__) if scons_ver < (major, minor, revision): if revision: scons_ver_string = '%d.%d.%d' % (major, minor, revision) else: scons_ver_string = '%d.%d' % (major, minor) print("SCons %s or greater required, but you have SCons %s" % \ (scons_ver_string, SCons.__version__)) sys.exit(2) def EnsurePythonVersion(self, major, minor): """Exit abnormally if the Python version is not late enough.""" try: v_major, v_minor, v_micro, release, serial = sys.version_info python_ver = (v_major, v_minor) except AttributeError: python_ver = self._get_major_minor_revision(sys.version)[:2] if python_ver < (major, minor): v = string.split(sys.version, " ", 1)[0] print("Python %d.%d or greater required, but you have Python %s" %(major,minor,v)) sys.exit(2) def Exit(self, value=0): sys.exit(value) def Export(self, *vars, **kw): for var in vars: global_exports.update(compute_exports(self.Split(var))) global_exports.update(kw) def GetLaunchDir(self): global launch_dir return launch_dir def GetOption(self, name): name = self.subst(name) return SCons.Script.Main.GetOption(name) def Help(self, text): text = self.subst(text, raw=1) SCons.Script.HelpFunction(text) def Import(self, *vars): try: frame = call_stack[-1] globals = frame.globals exports = frame.exports for var in vars: var = self.Split(var) for v in var: if v == '*': globals.update(global_exports) globals.update(exports) else: if v in exports: globals[v] = exports[v] else: globals[v] = global_exports[v] except KeyError as x: raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x) def SConscript(self, *ls, **kw): def subst_element(x, subst=self.subst): if SCons.Util.is_List(x): x = map(subst, x) else: x = subst(x) return x ls = map(subst_element, ls) subst_kw = {} for key, val in kw.items(): if SCons.Util.is_String(val): val = self.subst(val) elif SCons.Util.is_List(val): result = [] for v in val: if SCons.Util.is_String(v): v = self.subst(v) result.append(v) val = result subst_kw[key] = val files, exports = self._get_SConscript_filenames(ls, subst_kw) subst_kw['exports'] = exports return _SConscript(*[self.fs,] + files, **subst_kw) def SConscriptChdir(self, flag): global sconscript_chdir sconscript_chdir = flag def SetOption(self, name, value): name = self.subst(name) SCons.Script.Main.SetOption(name, value) # # # SCons.Environment.Environment = SConsEnvironment def Configure(*args, **kw): if not SCons.Script.sconscript_reading: raise SCons.Errors.UserError("Calling Configure from Builders is not supported.") kw['_depth'] = 1 return SCons.SConf.SConf(*args, **kw) # It's very important that the DefaultEnvironmentCall() class stay in this # file, with the get_calling_namespaces() function, the compute_exports() # function, the Frame class and the SConsEnvironment.Export() method. # These things make up the calling stack leading up to the actual global # Export() or SConscript() call that the user issued. We want to allow # users to export local variables that they define, like so: # # def func(): # x = 1 # Export('x') # # To support this, the get_calling_namespaces() function assumes that # the *first* stack frame that's not from this file is the local frame # for the Export() or SConscript() call. _DefaultEnvironmentProxy = None def get_DefaultEnvironmentProxy(): global _DefaultEnvironmentProxy if not _DefaultEnvironmentProxy: default_env = SCons.Defaults.DefaultEnvironment() _DefaultEnvironmentProxy = SCons.Environment.NoSubstitutionProxy(default_env) return _DefaultEnvironmentProxy class DefaultEnvironmentCall: """A class that implements "global function" calls of Environment methods by fetching the specified method from the DefaultEnvironment's class. Note that this uses an intermediate proxy class instead of calling the DefaultEnvironment method directly so that the proxy can override the subst() method and thereby prevent expansion of construction variables (since from the user's point of view this was called as a global function, with no associated construction environment).""" def __init__(self, method_name, subst=0): self.method_name = method_name if subst: self.factory = SCons.Defaults.DefaultEnvironment else: self.factory = get_DefaultEnvironmentProxy def __call__(self, *args, **kw): env = self.factory() method = getattr(env, self.method_name) return method(*args, **kw) def BuildDefaultGlobals(): """ Create a dictionary containing all the default globals for SConstruct and SConscript files. """ global GlobalDict if GlobalDict is None: GlobalDict = {} import SCons.Script d = SCons.Script.__dict__ def not_a_module(m, d=d, mtype=type(SCons.Script)): return not isinstance(d[m], mtype) for m in filter(not_a_module, dir(SCons.Script)): GlobalDict[m] = d[m] return GlobalDict.copy() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Script/SConsOptions.py0000644000175000017500000011173113606712377023607 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Script/SConsOptions.py 4369 2009/09/19 15:58:29 scons" import optparse import re import string import sys import textwrap try: no_hyphen_re = re.compile(r'(\s+|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') except re.error: # Pre-2.0 Python versions don't have the (?<= negative # look-behind assertion. no_hyphen_re = re.compile(r'(\s+|-*\w{2,}-(?=\w{2,}))') try: from gettext import gettext except ImportError: def gettext(message): return message _ = gettext import SCons.Node.FS import SCons.Warnings OptionValueError = optparse.OptionValueError SUPPRESS_HELP = optparse.SUPPRESS_HELP diskcheck_all = SCons.Node.FS.diskcheck_types() def diskcheck_convert(value): if value is None: return [] if not SCons.Util.is_List(value): value = string.split(value, ',') result = [] for v in map(string.lower, value): if v == 'all': result = diskcheck_all elif v == 'none': result = [] elif v in diskcheck_all: result.append(v) else: raise ValueError(v) return result class SConsValues(optparse.Values): """ Holder class for uniform access to SCons options, regardless of whether or not they can be set on the command line or in the SConscript files (using the SetOption() function). A SCons option value can originate three different ways: 1) set on the command line; 2) set in an SConscript file; 3) the default setting (from the the op.add_option() calls in the Parser() function, below). The command line always overrides a value set in a SConscript file, which in turn always overrides default settings. Because we want to support user-specified options in the SConscript file itself, though, we may not know about all of the options when the command line is first parsed, so we can't make all the necessary precedence decisions at the time the option is configured. The solution implemented in this class is to keep these different sets of settings separate (command line, SConscript file, and default) and to override the __getattr__() method to check them in turn. This should allow the rest of the code to just fetch values as attributes of an instance of this class, without having to worry about where they came from. Note that not all command line options are settable from SConscript files, and the ones that are must be explicitly added to the "settable" list in this class, and optionally validated and coerced in the set_option() method. """ def __init__(self, defaults): self.__dict__['__defaults__'] = defaults self.__dict__['__SConscript_settings__'] = {} def __getattr__(self, attr): """ Fetches an options value, checking first for explicit settings from the command line (which are direct attributes), then the SConscript file settings, then the default values. """ try: return self.__dict__[attr] except KeyError: try: return self.__dict__['__SConscript_settings__'][attr] except KeyError: return getattr(self.__dict__['__defaults__'], attr) settable = [ 'clean', 'diskcheck', 'duplicate', 'help', 'implicit_cache', 'max_drift', 'md5_chunksize', 'no_exec', 'num_jobs', 'random', 'stack_size', 'warn', ] def set_option(self, name, value): """ Sets an option from an SConscript file. """ if not name in self.settable: raise SCons.Errors.UserError("This option is not settable from a SConscript file: %s"%name) if name == 'num_jobs': try: value = int(value) if value < 1: raise ValueError except ValueError: raise SCons.Errors.UserError("A positive integer is required: %s"%repr(value)) elif name == 'max_drift': try: value = int(value) except ValueError: raise SCons.Errors.UserError("An integer is required: %s"%repr(value)) elif name == 'duplicate': try: value = str(value) except ValueError: raise SCons.Errors.UserError("A string is required: %s"%repr(value)) if not value in SCons.Node.FS.Valid_Duplicates: raise SCons.Errors.UserError("Not a valid duplication style: %s" % value) # Set the duplicate style right away so it can affect linking # of SConscript files. SCons.Node.FS.set_duplicate(value) elif name == 'diskcheck': try: value = diskcheck_convert(value) except ValueError as v: raise SCons.Errors.UserError("Not a valid diskcheck value: %s"%v) if 'diskcheck' not in self.__dict__: # No --diskcheck= option was specified on the command line. # Set this right away so it can affect the rest of the # file/Node lookups while processing the SConscript files. SCons.Node.FS.set_diskcheck(value) elif name == 'stack_size': try: value = int(value) except ValueError: raise SCons.Errors.UserError("An integer is required: %s"%repr(value)) elif name == 'md5_chunksize': try: value = int(value) except ValueError: raise SCons.Errors.UserError("An integer is required: %s"%repr(value)) elif name == 'warn': if SCons.Util.is_String(value): value = [value] value = self.__SConscript_settings__.get(name, []) + value SCons.Warnings.process_warn_strings(value) self.__SConscript_settings__[name] = value class SConsOption(optparse.Option): def convert_value(self, opt, value): if value is not None: if self.nargs in (1, '?'): return self.check_value(opt, value) else: return tuple(map(lambda v, o=opt, s=self: s.check_value(o, v), value)) def process(self, opt, value, values, parser): # First, convert the value(s) to the right type. Howl if any # value(s) are bogus. value = self.convert_value(opt, value) # And then take whatever action is expected of us. # This is a separate method to make life easier for # subclasses to add new actions. return self.take_action( self.action, self.dest, opt, value, values, parser) def _check_nargs_optional(self): if self.nargs == '?' and self._short_opts: fmt = "option %s: nargs='?' is incompatible with short options" raise SCons.Errors.UserError(fmt % self._short_opts[0]) try: _orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS _orig_CHECK_METHODS = optparse.Option.CHECK_METHODS except AttributeError: # optparse.Option had no CONST_ACTIONS before Python 2.5. _orig_CONST_ACTIONS = ("store_const",) def _check_const(self): if self.action not in self.CONST_ACTIONS and self.const is not None: raise OptionError( "'const' must not be supplied for action %r" % self.action, self) # optparse.Option collects its list of unbound check functions # up front. This sucks because it means we can't just override # the _check_const() function like a normal method, we have to # actually replace it in the list. This seems to be the most # straightforward way to do that. _orig_CHECK_METHODS = [optparse.Option._check_action, optparse.Option._check_type, optparse.Option._check_choice, optparse.Option._check_dest, _check_const, optparse.Option._check_nargs, optparse.Option._check_callback] CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional] CONST_ACTIONS = _orig_CONST_ACTIONS + optparse.Option.TYPED_ACTIONS class SConsOptionGroup(optparse.OptionGroup): """ A subclass for SCons-specific option groups. The only difference between this and the base class is that we print the group's help text flush left, underneath their own title but lined up with the normal "SCons Options". """ def format_help(self, formatter): """ Format an option group's help text, outdenting the title so it's flush with the "SCons Options" title we print at the top. """ formatter.dedent() result = formatter.format_heading(self.title) formatter.indent() result = result + optparse.OptionContainer.format_help(self, formatter) return result class SConsOptionParser(optparse.OptionParser): preserve_unknown_options = False def error(self, msg): self.print_usage(sys.stderr) sys.stderr.write("SCons error: %s\n" % msg) sys.exit(2) def _process_long_opt(self, rargs, values): """ SCons-specific processing of long options. This is copied directly from the normal optparse._process_long_opt() method, except that, if configured to do so, we catch the exception thrown when an unknown option is encountered and just stick it back on the "leftover" arguments for later (re-)processing. """ arg = rargs.pop(0) # Value explicitly attached to arg? Pretend it's the next # argument. if "=" in arg: (opt, next_arg) = string.split(arg, "=", 1) rargs.insert(0, next_arg) had_explicit_value = True else: opt = arg had_explicit_value = False try: opt = self._match_long_opt(opt) except optparse.BadOptionError: if self.preserve_unknown_options: # SCons-specific: if requested, add unknown options to # the "leftover arguments" list for later processing. self.largs.append(arg) if had_explicit_value: # The unknown option will be re-processed later, # so undo the insertion of the explicit value. rargs.pop(0) return raise option = self._long_opt[opt] if option.takes_value(): nargs = option.nargs if nargs == '?': if had_explicit_value: value = rargs.pop(0) else: value = option.const elif len(rargs) < nargs: if nargs == 1: self.error(_("%s option requires an argument") % opt) else: self.error(_("%s option requires %d arguments") % (opt, nargs)) elif nargs == 1: value = rargs.pop(0) else: value = tuple(rargs[0:nargs]) del rargs[0:nargs] elif had_explicit_value: self.error(_("%s option does not take a value") % opt) else: value = None option.process(opt, value, values, self) def add_local_option(self, *args, **kw): """ Adds a local option to the parser. This is initiated by a SetOption() call to add a user-defined command-line option. We add the option to a separate option group for the local options, creating the group if necessary. """ try: group = self.local_option_group except AttributeError: group = SConsOptionGroup(self, 'Local Options') group = self.add_option_group(group) self.local_option_group = group result = group.add_option(*args, **kw) if result: # The option was added succesfully. We now have to add the # default value to our object that holds the default values # (so that an attempt to fetch the option's attribute will # yield the default value when not overridden) and then # we re-parse the leftover command-line options, so that # any value overridden on the command line is immediately # available if the user turns around and does a GetOption() # right away. setattr(self.values.__defaults__, result.dest, result.default) self.parse_args(self.largs, self.values) return result class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): def format_usage(self, usage): return "usage: %s\n" % usage def format_heading(self, heading): """ This translates any heading of "options" or "Options" into "SCons Options." Unfortunately, we have to do this here, because those titles are hard-coded in the optparse calls. """ if heading == 'options': # The versions of optparse.py shipped with Pythons 2.3 and # 2.4 pass this in uncapitalized; override that so we get # consistent output on all versions. heading = "Options" if heading == 'Options': heading = "SCons Options" return optparse.IndentedHelpFormatter.format_heading(self, heading) def format_option(self, option): """ A copy of the normal optparse.IndentedHelpFormatter.format_option() method. This has been snarfed so we can modify text wrapping to out liking: -- add our own regular expression that doesn't break on hyphens (so things like --no-print-directory don't get broken); -- wrap the list of options themselves when it's too long (the wrapper.fill(opts) call below); -- set the subsequent_indent when wrapping the help_text. """ # The help for each option consists of two parts: # * the opt strings and metavars # eg. ("-x", or "-fFILENAME, --file=FILENAME") # * the user-supplied help string # eg. ("turn on expert mode", "read data from FILENAME") # # If possible, we write both of these on the same line: # -x turn on expert mode # # But if the opt string list is too long, we put the help # string on a second line, indented to the same column it would # start in if it fit on the first line. # -fFILENAME, --file=FILENAME # read data from FILENAME result = [] try: opts = self.option_strings[option] except AttributeError: # The Python 2.3 version of optparse attaches this to # to the option argument, not to this object. opts = option.option_strings opt_width = self.help_position - self.current_indent - 2 if len(opts) > opt_width: wrapper = textwrap.TextWrapper(width=self.width, initial_indent = ' ', subsequent_indent = ' ') wrapper.wordsep_re = no_hyphen_re opts = wrapper.fill(opts) + '\n' indent_first = self.help_position else: # start help on same line as opts opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) indent_first = 0 result.append(opts) if option.help: try: expand_default = self.expand_default except AttributeError: # The HelpFormatter base class in the Python 2.3 version # of optparse has no expand_default() method. help_text = option.help else: help_text = expand_default(option) # SCons: indent every line of the help text but the first. wrapper = textwrap.TextWrapper(width=self.help_width, subsequent_indent = ' ') wrapper.wordsep_re = no_hyphen_re help_lines = wrapper.wrap(help_text) result.append("%*s%s\n" % (indent_first, "", help_lines[0])) for line in help_lines[1:]: result.append("%*s%s\n" % (self.help_position, "", line)) elif opts[-1] != "\n": result.append("\n") return string.join(result, "") # For consistent help output across Python versions, we provide a # subclass copy of format_option_strings() and these two variables. # This is necessary (?) for Python2.3, which otherwise concatenates # a short option with its metavar. _short_opt_fmt = "%s %s" _long_opt_fmt = "%s=%s" def format_option_strings(self, option): """Return a comma-separated list of option strings & metavariables.""" if option.takes_value(): metavar = option.metavar or string.upper(option.dest) short_opts = [] for sopt in option._short_opts: short_opts.append(self._short_opt_fmt % (sopt, metavar)) long_opts = [] for lopt in option._long_opts: long_opts.append(self._long_opt_fmt % (lopt, metavar)) else: short_opts = option._short_opts long_opts = option._long_opts if self.short_first: opts = short_opts + long_opts else: opts = long_opts + short_opts return string.join(opts, ", ") def Parser(version): """ Returns an options parser object initialized with the standard SCons options. """ formatter = SConsIndentedHelpFormatter(max_help_position=30) op = SConsOptionParser(option_class=SConsOption, add_help_option=False, formatter=formatter, usage="usage: scons [OPTION] [TARGET] ...",) op.preserve_unknown_options = True op.version = version # Add the options to the parser we just created. # # These are in the order we want them to show up in the -H help # text, basically alphabetical. Each op.add_option() call below # should have a consistent format: # # op.add_option("-L", "--long-option-name", # nargs=1, type="string", # dest="long_option_name", default='foo', # action="callback", callback=opt_long_option, # help="help text goes here", # metavar="VAR") # # Even though the optparse module constructs reasonable default # destination names from the long option names, we're going to be # explicit about each one for easier readability and so this code # will at least show up when grepping the source for option attribute # names, or otherwise browsing the source code. # options ignored for compatibility def opt_ignore(option, opt, value, parser): sys.stderr.write("Warning: ignoring %s option\n" % opt) op.add_option("-b", "-d", "-e", "-m", "-S", "-t", "-w", "--environment-overrides", "--no-keep-going", "--no-print-directory", "--print-directory", "--stop", "--touch", action="callback", callback=opt_ignore, help="Ignored for compatibility.") op.add_option('-c', '--clean', '--remove', dest="clean", default=False, action="store_true", help="Remove specified targets and dependencies.") op.add_option('-C', '--directory', nargs=1, type="string", dest="directory", default=[], action="append", help="Change to DIR before doing anything.", metavar="DIR") op.add_option('--cache-debug', nargs=1, dest="cache_debug", default=None, action="store", help="Print CacheDir debug info to FILE.", metavar="FILE") op.add_option('--cache-disable', '--no-cache', dest='cache_disable', default=False, action="store_true", help="Do not retrieve built targets from CacheDir.") op.add_option('--cache-force', '--cache-populate', dest='cache_force', default=False, action="store_true", help="Copy already-built targets into the CacheDir.") op.add_option('--cache-show', dest='cache_show', default=False, action="store_true", help="Print build actions for files from CacheDir.") config_options = ["auto", "force" ,"cache"] def opt_config(option, opt, value, parser, c_options=config_options): if not value in c_options: raise OptionValueError("Warning: %s is not a valid config type" % value) setattr(parser.values, option.dest, value) opt_config_help = "Controls Configure subsystem: %s." \ % string.join(config_options, ", ") op.add_option('--config', nargs=1, type="string", dest="config", default="auto", action="callback", callback=opt_config, help = opt_config_help, metavar="MODE") op.add_option('-D', dest="climb_up", default=None, action="store_const", const=2, help="Search up directory tree for SConstruct, " "build all Default() targets.") deprecated_debug_options = { "dtree" : '; please use --tree=derived instead', "nomemoizer" : ' and has no effect', "stree" : '; please use --tree=all,status instead', "tree" : '; please use --tree=all instead', } debug_options = ["count", "explain", "findlibs", "includes", "memoizer", "memory", "objects", "pdb", "presub", "stacktrace", "time"] + deprecated_debug_options.keys() def opt_debug(option, opt, value, parser, debug_options=debug_options, deprecated_debug_options=deprecated_debug_options): if value in debug_options: parser.values.debug.append(value) if value in deprecated_debug_options.keys(): try: parser.values.delayed_warnings except AttributeError: parser.values.delayed_warnings = [] msg = deprecated_debug_options[value] w = "The --debug=%s option is deprecated%s." % (value, msg) t = (SCons.Warnings.DeprecatedWarning, w) parser.values.delayed_warnings.append(t) else: raise OptionValueError("Warning: %s is not a valid debug type" % value) opt_debug_help = "Print various types of debugging information: %s." \ % string.join(debug_options, ", ") op.add_option('--debug', nargs=1, type="string", dest="debug", default=[], action="callback", callback=opt_debug, help=opt_debug_help, metavar="TYPE") def opt_diskcheck(option, opt, value, parser): try: diskcheck_value = diskcheck_convert(value) except ValueError as e: raise OptionValueError("Warning: `%s' is not a valid diskcheck type" % e) setattr(parser.values, option.dest, diskcheck_value) op.add_option('--diskcheck', nargs=1, type="string", dest='diskcheck', default=None, action="callback", callback=opt_diskcheck, help="Enable specific on-disk checks.", metavar="TYPE") def opt_duplicate(option, opt, value, parser): if not value in SCons.Node.FS.Valid_Duplicates: raise OptionValueError("`%s' is not a valid duplication style." % value) setattr(parser.values, option.dest, value) # Set the duplicate style right away so it can affect linking # of SConscript files. SCons.Node.FS.set_duplicate(value) opt_duplicate_help = "Set the preferred duplication methods. Must be one of " \ + string.join(SCons.Node.FS.Valid_Duplicates, ", ") op.add_option('--duplicate', nargs=1, type="string", dest="duplicate", default='hard-soft-copy', action="callback", callback=opt_duplicate, help=opt_duplicate_help) op.add_option('-f', '--file', '--makefile', '--sconstruct', nargs=1, type="string", dest="file", default=[], action="append", help="Read FILE as the top-level SConstruct file.") op.add_option('-h', '--help', dest="help", default=False, action="store_true", help="Print defined help message, or this one.") op.add_option("-H", "--help-options", action="help", help="Print this message and exit.") op.add_option('-i', '--ignore-errors', dest='ignore_errors', default=False, action="store_true", help="Ignore errors from build actions.") op.add_option('-I', '--include-dir', nargs=1, dest='include_dir', default=[], action="append", help="Search DIR for imported Python modules.", metavar="DIR") op.add_option('--implicit-cache', dest='implicit_cache', default=False, action="store_true", help="Cache implicit dependencies") def opt_implicit_deps(option, opt, value, parser): setattr(parser.values, 'implicit_cache', True) setattr(parser.values, option.dest, True) op.add_option('--implicit-deps-changed', dest="implicit_deps_changed", default=False, action="callback", callback=opt_implicit_deps, help="Ignore cached implicit dependencies.") op.add_option('--implicit-deps-unchanged', dest="implicit_deps_unchanged", default=False, action="callback", callback=opt_implicit_deps, help="Ignore changes in implicit dependencies.") op.add_option('--interact', '--interactive', dest='interactive', default=False, action="store_true", help="Run in interactive mode.") op.add_option('-j', '--jobs', nargs=1, type="int", dest="num_jobs", default=1, action="store", help="Allow N jobs at once.", metavar="N") op.add_option('-k', '--keep-going', dest='keep_going', default=False, action="store_true", help="Keep going when a target can't be made.") op.add_option('--max-drift', nargs=1, type="int", dest='max_drift', default=SCons.Node.FS.default_max_drift, action="store", help="Set maximum system clock drift to N seconds.", metavar="N") op.add_option('--md5-chunksize', nargs=1, type="int", dest='md5_chunksize', default=SCons.Node.FS.File.md5_chunksize, action="store", help="Set chunk-size for MD5 signature computation to N kilobytes.", metavar="N") op.add_option('-n', '--no-exec', '--just-print', '--dry-run', '--recon', dest='no_exec', default=False, action="store_true", help="Don't build; just print commands.") op.add_option('--no-site-dir', dest='no_site_dir', default=False, action="store_true", help="Don't search or use the usual site_scons dir.") op.add_option('--profile', nargs=1, dest="profile_file", default=None, action="store", help="Profile SCons and put results in FILE.", metavar="FILE") op.add_option('-q', '--question', dest="question", default=False, action="store_true", help="Don't build; exit status says if up to date.") op.add_option('-Q', dest='no_progress', default=False, action="store_true", help="Suppress \"Reading/Building\" progress messages.") op.add_option('--random', dest="random", default=False, action="store_true", help="Build dependencies in random order.") op.add_option('-s', '--silent', '--quiet', dest="silent", default=False, action="store_true", help="Don't print commands.") op.add_option('--site-dir', nargs=1, dest='site_dir', default=None, action="store", help="Use DIR instead of the usual site_scons dir.", metavar="DIR") op.add_option('--stack-size', nargs=1, type="int", dest='stack_size', action="store", help="Set the stack size of the threads used to run jobs to N kilobytes.", metavar="N") op.add_option('--taskmastertrace', nargs=1, dest="taskmastertrace_file", default=None, action="store", help="Trace Node evaluation to FILE.", metavar="FILE") tree_options = ["all", "derived", "prune", "status"] def opt_tree(option, opt, value, parser, tree_options=tree_options): import Main tp = Main.TreePrinter() for o in string.split(value, ','): if o == 'all': tp.derived = False elif o == 'derived': tp.derived = True elif o == 'prune': tp.prune = True elif o == 'status': tp.status = True else: raise OptionValueError("Warning: %s is not a valid --tree option" % o) parser.values.tree_printers.append(tp) opt_tree_help = "Print a dependency tree in various formats: %s." \ % string.join(tree_options, ", ") op.add_option('--tree', nargs=1, type="string", dest="tree_printers", default=[], action="callback", callback=opt_tree, help=opt_tree_help, metavar="OPTIONS") op.add_option('-u', '--up', '--search-up', dest="climb_up", default=0, action="store_const", const=1, help="Search up directory tree for SConstruct, " "build targets at or below current directory.") op.add_option('-U', dest="climb_up", default=0, action="store_const", const=3, help="Search up directory tree for SConstruct, " "build Default() targets from local SConscript.") def opt_version(option, opt, value, parser): sys.stdout.write(parser.version + '\n') sys.exit(0) op.add_option("-v", "--version", action="callback", callback=opt_version, help="Print the SCons version number and exit.") def opt_warn(option, opt, value, parser, tree_options=tree_options): if SCons.Util.is_String(value): value = string.split(value, ',') parser.values.warn.extend(value) op.add_option('--warn', '--warning', nargs=1, type="string", dest="warn", default=[], action="callback", callback=opt_warn, help="Enable or disable warnings.", metavar="WARNING-SPEC") op.add_option('-Y', '--repository', '--srcdir', nargs=1, dest="repository", default=[], action="append", help="Search REPOSITORY for source and target files.") # Options from Make and Cons classic that we do not yet support, # but which we may support someday and whose (potential) meanings # we don't want to change. These all get a "the -X option is not # yet implemented" message and don't show up in the help output. def opt_not_yet(option, opt, value, parser): msg = "Warning: the %s option is not yet implemented\n" % opt sys.stderr.write(msg) sys.exit(0) op.add_option('-l', '--load-average', '--max-load', nargs=1, type="int", dest="load_average", default=0, action="callback", callback=opt_not_yet, # action="store", # help="Don't start multiple jobs unless load is below " # "LOAD-AVERAGE." help=SUPPRESS_HELP) op.add_option('--list-actions', dest="list_actions", action="callback", callback=opt_not_yet, # help="Don't build; list files and build actions." help=SUPPRESS_HELP) op.add_option('--list-derived', dest="list_derived", action="callback", callback=opt_not_yet, # help="Don't build; list files that would be built." help=SUPPRESS_HELP) op.add_option('--list-where', dest="list_where", action="callback", callback=opt_not_yet, # help="Don't build; list files and where defined." help=SUPPRESS_HELP) op.add_option('-o', '--old-file', '--assume-old', nargs=1, type="string", dest="old_file", default=[], action="callback", callback=opt_not_yet, # action="append", # help = "Consider FILE to be old; don't rebuild it." help=SUPPRESS_HELP) op.add_option('--override', nargs=1, type="string", action="callback", callback=opt_not_yet, dest="override", # help="Override variables as specified in FILE." help=SUPPRESS_HELP) op.add_option('-p', action="callback", callback=opt_not_yet, dest="p", # help="Print internal environments/objects." help=SUPPRESS_HELP) op.add_option('-r', '-R', '--no-builtin-rules', '--no-builtin-variables', action="callback", callback=opt_not_yet, dest="no_builtin_rules", # help="Clear default environments and variables." help=SUPPRESS_HELP) op.add_option('--write-filenames', nargs=1, type="string", dest="write_filenames", action="callback", callback=opt_not_yet, # help="Write all filenames examined into FILE." help=SUPPRESS_HELP) op.add_option('-W', '--new-file', '--assume-new', '--what-if', nargs=1, type="string", dest="new_file", action="callback", callback=opt_not_yet, # help="Consider FILE to be changed." help=SUPPRESS_HELP) op.add_option('--warn-undefined-variables', dest="warn_undefined_variables", action="callback", callback=opt_not_yet, # help="Warn when an undefined variable is referenced." help=SUPPRESS_HELP) return op # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Executor.py0000644000175000017500000005175313606712377021547 0ustar kurtkurt"""SCons.Executor A module for executing actions with specific lists of target and source Nodes. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Executor.py 4369 2009/09/19 15:58:29 scons" import string import UserList from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Memoize class Batch: """Remembers exact association between targets and sources of executor.""" def __init__(self, targets=[], sources=[]): self.targets = targets self.sources = sources class TSList(UserList.UserList): """A class that implements $TARGETS or $SOURCES expansions by wrapping an executor Method. This class is used in the Executor.lvars() to delay creation of NodeList objects until they're needed. Note that we subclass UserList.UserList purely so that the is_Sequence() function will identify an object of this class as a list during variable expansion. We're not really using any UserList.UserList methods in practice. """ def __init__(self, func): self.func = func def __getattr__(self, attr): nl = self.func() return getattr(nl, attr) def __getitem__(self, i): nl = self.func() return nl[i] def __getslice__(self, i, j): nl = self.func() i = max(i, 0); j = max(j, 0) return nl[i:j] def __str__(self): nl = self.func() return str(nl) def __repr__(self): nl = self.func() return repr(nl) class TSObject: """A class that implements $TARGET or $SOURCE expansions by wrapping an Executor method. """ def __init__(self, func): self.func = func def __getattr__(self, attr): n = self.func() return getattr(n, attr) def __str__(self): n = self.func() if n: return str(n) return '' def __repr__(self): n = self.func() if n: return repr(n) return '' def rfile(node): """ A function to return the results of a Node's rfile() method, if it exists, and the Node itself otherwise (if it's a Value Node, e.g.). """ try: rfile = node.rfile except AttributeError: return node else: return rfile() class Executor: """A class for controlling instances of executing an action. This largely exists to hold a single association of an action, environment, list of environment override dictionaries, targets and sources for later processing as needed. """ if SCons.Memoize.use_memoizer: __metaclass__ = SCons.Memoize.Memoized_Metaclass memoizer_counters = [] def __init__(self, action, env=None, overridelist=[{}], targets=[], sources=[], builder_kw={}): if __debug__: logInstanceCreation(self, 'Executor.Executor') self.set_action_list(action) self.pre_actions = [] self.post_actions = [] self.env = env self.overridelist = overridelist if targets or sources: self.batches = [Batch(targets[:], sources[:])] else: self.batches = [] self.builder_kw = builder_kw self._memo = {} def get_lvars(self): try: return self.lvars except AttributeError: self.lvars = { 'CHANGED_SOURCES' : TSList(self._get_changed_sources), 'CHANGED_TARGETS' : TSList(self._get_changed_targets), 'SOURCE' : TSObject(self._get_source), 'SOURCES' : TSList(self._get_sources), 'TARGET' : TSObject(self._get_target), 'TARGETS' : TSList(self._get_targets), 'UNCHANGED_SOURCES' : TSList(self._get_unchanged_sources), 'UNCHANGED_TARGETS' : TSList(self._get_unchanged_targets), } return self.lvars def _get_changes(self): cs = [] ct = [] us = [] ut = [] for b in self.batches: if b.targets[0].is_up_to_date(): us.extend(map(rfile, b.sources)) ut.extend(b.targets) else: cs.extend(map(rfile, b.sources)) ct.extend(b.targets) self._changed_sources_list = SCons.Util.NodeList(cs) self._changed_targets_list = SCons.Util.NodeList(ct) self._unchanged_sources_list = SCons.Util.NodeList(us) self._unchanged_targets_list = SCons.Util.NodeList(ut) def _get_changed_sources(self, *args, **kw): try: return self._changed_sources_list except AttributeError: self._get_changes() return self._changed_sources_list def _get_changed_targets(self, *args, **kw): try: return self._changed_targets_list except AttributeError: self._get_changes() return self._changed_targets_list def _get_source(self, *args, **kw): #return SCons.Util.NodeList([rfile(self.batches[0].sources[0]).get_subst_proxy()]) return rfile(self.batches[0].sources[0]).get_subst_proxy() def _get_sources(self, *args, **kw): return SCons.Util.NodeList(map(lambda n: rfile(n).get_subst_proxy(), self.get_all_sources())) def _get_target(self, *args, **kw): #return SCons.Util.NodeList([self.batches[0].targets[0].get_subst_proxy()]) return self.batches[0].targets[0].get_subst_proxy() def _get_targets(self, *args, **kw): return SCons.Util.NodeList(map(lambda n: n.get_subst_proxy(), self.get_all_targets())) def _get_unchanged_sources(self, *args, **kw): try: return self._unchanged_sources_list except AttributeError: self._get_changes() return self._unchanged_sources_list def _get_unchanged_targets(self, *args, **kw): try: return self._unchanged_targets_list except AttributeError: self._get_changes() return self._unchanged_targets_list def get_action_targets(self): if not self.action_list: return [] targets_string = self.action_list[0].get_targets(self.env, self) if targets_string[0] == '$': targets_string = targets_string[1:] return self.get_lvars()[targets_string] def set_action_list(self, action): import SCons.Util if not SCons.Util.is_List(action): if not action: import SCons.Errors raise SCons.Errors.UserError("Executor must have an action.") action = [action] self.action_list = action def get_action_list(self): return self.pre_actions + self.action_list + self.post_actions def get_all_targets(self): """Returns all targets for all batches of this Executor.""" result = [] for batch in self.batches: # TODO(1.5): remove the list() cast result.extend(list(batch.targets)) return result def get_all_sources(self): """Returns all sources for all batches of this Executor.""" result = [] for batch in self.batches: # TODO(1.5): remove the list() cast result.extend(list(batch.sources)) return result def get_all_children(self): """Returns all unique children (dependencies) for all batches of this Executor. The Taskmaster can recognize when it's already evaluated a Node, so we don't have to make this list unique for its intended canonical use case, but we expect there to be a lot of redundancy (long lists of batched .cc files #including the same .h files over and over), so removing the duplicates once up front should save the Taskmaster a lot of work. """ result = SCons.Util.UniqueList([]) for target in self.get_all_targets(): result.extend(target.children()) return result def get_all_prerequisites(self): """Returns all unique (order-only) prerequisites for all batches of this Executor. """ result = SCons.Util.UniqueList([]) for target in self.get_all_targets(): # TODO(1.5): remove the list() cast result.extend(list(target.prerequisites)) return result def get_action_side_effects(self): """Returns all side effects for all batches of this Executor used by the underlying Action. """ result = SCons.Util.UniqueList([]) for target in self.get_action_targets(): result.extend(target.side_effects) return result memoizer_counters.append(SCons.Memoize.CountValue('get_build_env')) def get_build_env(self): """Fetch or create the appropriate build Environment for this Executor. """ try: return self._memo['get_build_env'] except KeyError: pass # Create the build environment instance with appropriate # overrides. These get evaluated against the current # environment's construction variables so that users can # add to existing values by referencing the variable in # the expansion. overrides = {} for odict in self.overridelist: overrides.update(odict) import SCons.Defaults env = self.env or SCons.Defaults.DefaultEnvironment() build_env = env.Override(overrides) self._memo['get_build_env'] = build_env return build_env def get_build_scanner_path(self, scanner): """Fetch the scanner path for this executor's targets and sources. """ env = self.get_build_env() try: cwd = self.batches[0].targets[0].cwd except (IndexError, AttributeError): cwd = None return scanner.path(env, cwd, self.get_all_targets(), self.get_all_sources()) def get_kw(self, kw={}): result = self.builder_kw.copy() result.update(kw) result['executor'] = self return result def do_nothing(self, target, kw): return 0 def do_execute(self, target, kw): """Actually execute the action list.""" env = self.get_build_env() kw = self.get_kw(kw) status = 0 for act in self.get_action_list(): #args = (self.get_all_targets(), self.get_all_sources(), env) args = ([], [], env) status = act(*args, **kw) if isinstance(status, SCons.Errors.BuildError): status.executor = self raise status elif status: msg = "Error %s" % status raise SCons.Errors.BuildError( errstr=msg, node=self.batches[0].targets, executor=self, action=act) return status # use extra indirection because with new-style objects (Python 2.2 # and above) we can't override special methods, and nullify() needs # to be able to do this. def __call__(self, target, **kw): return self.do_execute(target, kw) def cleanup(self): self._memo = {} def add_sources(self, sources): """Add source files to this Executor's list. This is necessary for "multi" Builders that can be called repeatedly to build up a source file list for a given target.""" # TODO(batch): extend to multiple batches assert (len(self.batches) == 1) # TODO(batch): remove duplicates? sources = filter(lambda x, s=self.batches[0].sources: x not in s, sources) self.batches[0].sources.extend(sources) def get_sources(self): return self.batches[0].sources def add_batch(self, targets, sources): """Add pair of associated target and source to this Executor's list. This is necessary for "batch" Builders that can be called repeatedly to build up a list of matching target and source files that will be used in order to update multiple target files at once from multiple corresponding source files, for tools like MSVC that support it.""" self.batches.append(Batch(targets, sources)) def prepare(self): """ Preparatory checks for whether this Executor can go ahead and (try to) build its targets. """ for s in self.get_all_sources(): if s.missing(): msg = "Source `%s' not found, needed by target `%s'." raise SCons.Errors.StopError(msg % (s, self.batches[0].targets[0])) def add_pre_action(self, action): self.pre_actions.append(action) def add_post_action(self, action): self.post_actions.append(action) # another extra indirection for new-style objects and nullify... def my_str(self): env = self.get_build_env() get = lambda action, t=self.get_all_targets(), s=self.get_all_sources(), e=env: \ action.genstring(t, s, e) return string.join(map(get, self.get_action_list()), "\n") def __str__(self): return self.my_str() def nullify(self): self.cleanup() self.do_execute = self.do_nothing self.my_str = lambda S=self: '' memoizer_counters.append(SCons.Memoize.CountValue('get_contents')) def get_contents(self): """Fetch the signature contents. This is the main reason this class exists, so we can compute this once and cache it regardless of how many target or source Nodes there are. """ try: return self._memo['get_contents'] except KeyError: pass env = self.get_build_env() get = lambda action, t=self.get_all_targets(), s=self.get_all_sources(), e=env: \ action.get_contents(t, s, e) result = string.join(map(get, self.get_action_list()), "") self._memo['get_contents'] = result return result def get_timestamp(self): """Fetch a time stamp for this Executor. We don't have one, of course (only files do), but this is the interface used by the timestamp module. """ return 0 def scan_targets(self, scanner): # TODO(batch): scan by batches self.scan(scanner, self.get_all_targets()) def scan_sources(self, scanner): # TODO(batch): scan by batches if self.batches[0].sources: self.scan(scanner, self.get_all_sources()) def scan(self, scanner, node_list): """Scan a list of this Executor's files (targets or sources) for implicit dependencies and update all of the targets with them. This essentially short-circuits an N*M scan of the sources for each individual target, which is a hell of a lot more efficient. """ env = self.get_build_env() # TODO(batch): scan by batches) deps = [] if scanner: for node in node_list: node.disambiguate() s = scanner.select(node) if not s: continue path = self.get_build_scanner_path(s) deps.extend(node.get_implicit_deps(env, s, path)) else: kw = self.get_kw() for node in node_list: node.disambiguate() scanner = node.get_env_scanner(env, kw) if not scanner: continue scanner = scanner.select(node) if not scanner: continue path = self.get_build_scanner_path(scanner) deps.extend(node.get_implicit_deps(env, scanner, path)) deps.extend(self.get_implicit_deps()) for tgt in self.get_all_targets(): tgt.add_to_implicit(deps) def _get_unignored_sources_key(self, node, ignore=()): return (node,) + tuple(ignore) memoizer_counters.append(SCons.Memoize.CountDict('get_unignored_sources', _get_unignored_sources_key)) def get_unignored_sources(self, node, ignore=()): key = (node,) + tuple(ignore) try: memo_dict = self._memo['get_unignored_sources'] except KeyError: memo_dict = {} self._memo['get_unignored_sources'] = memo_dict else: try: return memo_dict[key] except KeyError: pass if node: # TODO: better way to do this (it's a linear search, # but it may not be critical path)? sourcelist = [] for b in self.batches: if node in b.targets: sourcelist = b.sources break else: sourcelist = self.get_all_sources() if ignore: idict = {} for i in ignore: idict[i] = 1 sourcelist = filter(lambda s, i=idict: s not in i, sourcelist) memo_dict[key] = sourcelist return sourcelist def get_implicit_deps(self): """Return the executor's implicit dependencies, i.e. the nodes of the commands to be executed.""" result = [] build_env = self.get_build_env() for act in self.get_action_list(): deps = act.get_implicit_deps(self.get_all_targets(), self.get_all_sources(), build_env) result.extend(deps) return result _batch_executors = {} def GetBatchExecutor(key): return _batch_executors[key] def AddBatchExecutor(key, executor): assert key not in _batch_executors _batch_executors[key] = executor nullenv = None def get_NullEnvironment(): """Use singleton pattern for Null Environments.""" global nullenv import SCons.Util class NullEnvironment(SCons.Util.Null): import SCons.CacheDir _CacheDir_path = None _CacheDir = SCons.CacheDir.CacheDir(None) def get_CacheDir(self): return self._CacheDir if not nullenv: nullenv = NullEnvironment() return nullenv class Null: """A null Executor, with a null build Environment, that does nothing when the rest of the methods call it. This might be able to disapper when we refactor things to disassociate Builders from Nodes entirely, so we're not going to worry about unit tests for this--at least for now. """ def __init__(self, *args, **kw): if __debug__: logInstanceCreation(self, 'Executor.Null') self.batches = [Batch(kw['targets'][:], [])] def get_build_env(self): return get_NullEnvironment() def get_build_scanner_path(self): return None def cleanup(self): pass def prepare(self): pass def get_unignored_sources(self, *args, **kw): return tuple(()) def get_action_targets(self): return [] def get_action_list(self): return [] def get_all_targets(self): return self.batches[0].targets def get_all_sources(self): return self.batches[0].targets[0].sources def get_all_children(self): return self.get_all_sources() def get_all_prerequisites(self): return [] def get_action_side_effects(self): return [] def __call__(self, *args, **kw): return 0 def get_contents(self): return '' def _morph(self): """Morph this Null executor to a real Executor object.""" batches = self.batches self.__class__ = Executor self.__init__([]) self.batches = batches # The following methods require morphing this Null Executor to a # real Executor object. def add_pre_action(self, action): self._morph() self.add_pre_action(action) def add_post_action(self, action): self._morph() self.add_post_action(action) def set_action_list(self, action): self._morph() self.set_action_list(action) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/__init__.py0000644000175000017500000000314313606712377021476 0ustar kurtkurt"""SCons The main package for the SCons software construction utility. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/__init__.py 4369 2009/09/19 16:58:54 scons" __version__ = "1.2.0.d20090919" __build__ = "r4369[MODIFIED]" __buildsys__ = "scons-dev" __date__ = "2009/09/19 16:58:54" __developer__ = "scons" # make sure compatibility is always in place import SCons.compat # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/0000755000175000017500000000000013606712377020301 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/ifort.py0000644000175000017500000000644513606712377022007 0ustar kurtkurt"""SCons.Tool.ifort Tool-specific initialization for newer versions of the Intel Fortran Compiler for Linux/Windows (and possibly Mac OS X). There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/ifort.py 4369 2009/09/19 15:58:29 scons" import string import SCons.Defaults from SCons.Scanner.Fortran import FortranScan from FortranCommon import add_all_to_env def generate(env): """Add Builders and construction variables for ifort to an Environment.""" # ifort supports Fortran 90 and Fortran 95 # Additionally, ifort recognizes more file extensions. fscan = FortranScan("FORTRANPATH") SCons.Tool.SourceFileScanner.add_scanner('.i', fscan) SCons.Tool.SourceFileScanner.add_scanner('.i90', fscan) if 'FORTRANFILESUFFIXES' not in env: env['FORTRANFILESUFFIXES'] = ['.i'] else: env['FORTRANFILESUFFIXES'].append('.i') if 'F90FILESUFFIXES' not in env: env['F90FILESUFFIXES'] = ['.i90'] else: env['F90FILESUFFIXES'].append('.i90') add_all_to_env(env) fc = 'ifort' for dialect in ['F77', 'F90', 'FORTRAN', 'F95']: env['%s' % dialect] = fc env['SH%s' % dialect] = '$%s' % dialect if env['PLATFORM'] == 'posix': env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS -fPIC' % dialect) if env['PLATFORM'] == 'win32': # On Windows, the ifort compiler specifies the object on the # command line with -object:, not -o. Massage the necessary # command-line construction variables. for dialect in ['F77', 'F90', 'FORTRAN', 'F95']: for var in ['%sCOM' % dialect, '%sPPCOM' % dialect, 'SH%sCOM' % dialect, 'SH%sPPCOM' % dialect]: env[var] = string.replace(env[var], '-o $TARGET', '-object:$TARGET') env['FORTRANMODDIRPREFIX'] = "/module:" else: env['FORTRANMODDIRPREFIX'] = "-module " def exists(env): return env.Detect('ifort') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/textfile.py0000644000175000017500000001362113606712377022502 0ustar kurtkurt# -*- python -*- # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __doc__ = """ Textfile/Substfile builder for SCons. Create file 'target' which typically is a textfile. The 'source' may be any combination of strings, Nodes, or lists of same. A 'linesep' will be put between any part written and defaults to os.linesep. The only difference between the Textfile builder and the Substfile builder is that strings are converted to Value() nodes for the former and File() nodes for the latter. To insert files in the former or strings in the latter, wrap them in a File() or Value(), respectively. The values of SUBST_DICT first have any construction variables expanded (its keys are not expanded). If a value of SUBST_DICT is a python callable function, it is called and the result is expanded as the value. Values are substituted in a "random" order; if any substitution could be further expanded by another subsitition, it is unpredictible whether the expansion will occur. """ __revision__ = "src/engine/SCons/Tool/textfile.py 4369 2009/09/19 15:58:29 scons" import SCons import os import re from SCons.Node import Node from SCons.Node.Python import Value from SCons.Util import is_String, is_Sequence, is_Dict def _do_subst(node, subs): """ Fetch the node contents and replace all instances of the keys with their values. For example, if subs is {'%VERSION%': '1.2345', '%BASE%': 'MyProg', '%prefix%': '/bin'}, then all instances of %VERSION% in the file will be replaced with 1.2345 and so forth. """ contents = node.get_text_contents() if not subs: return contents for (k,v) in subs: contents = re.sub(k, v, contents) return contents def _action(target, source, env): # prepare the line separator linesep = env['LINESEPARATOR'] if linesep is None: linesep = os.linesep elif is_String(linesep): pass elif isinstance(linesep, Value): linesep = linesep.get_text_contents() else: raise SCons.Errors.UserError( 'unexpected type/class for LINESEPARATOR: %s' % repr(linesep), None) # create a dictionary to use for the substitutions if 'SUBST_DICT' not in env: subs = None # no substitutions else: d = env['SUBST_DICT'] if is_Dict(d): d = d.items() elif is_Sequence(d): pass else: raise SCons.Errors.UserError('SUBST_DICT must be dict or sequence') subs = [] for (k,v) in d: if callable(v): v = v() if is_String(v): v = env.subst(v) else: v = str(v) subs.append((k,v)) # write the file try: fd = open(target[0].get_path(), "wb") except (OSError,IOError) as e: raise SCons.Errors.UserError("Can't write target file %s" % target[0]) # separate lines by 'linesep' only if linesep is not empty lsep = None for s in source: if lsep: fd.write(lsep) fd.write(_do_subst(s, subs)) lsep = linesep fd.close() def _strfunc(target, source, env): return "Creating '%s'" % target[0] def _convert_list_R(newlist, sources): for elem in sources: if is_Sequence(elem): _convert_list_R(newlist, elem) elif isinstance(elem, Node): newlist.append(elem) else: newlist.append(Value(elem)) def _convert_list(target, source, env): if len(target) != 1: raise SCons.Errors.UserError("Only one target file allowed") newlist = [] _convert_list_R(newlist, source) return target, newlist _common_varlist = ['SUBST_DICT', 'LINESEPARATOR'] _text_varlist = _common_varlist + ['TEXTFILEPREFIX', 'TEXTFILESUFFIX'] _text_builder = SCons.Builder.Builder( action = SCons.Action.Action(_action, _strfunc, varlist = _text_varlist), source_factory = Value, emitter = _convert_list, prefix = '$TEXTFILEPREFIX', suffix = '$TEXTFILESUFFIX', ) _subst_varlist = _common_varlist + ['SUBSTFILEPREFIX', 'TEXTFILESUFFIX'] _subst_builder = SCons.Builder.Builder( action = SCons.Action.Action(_action, _strfunc, varlist = _subst_varlist), source_factory = SCons.Node.FS.File, emitter = _convert_list, prefix = '$SUBSTFILEPREFIX', suffix = '$SUBSTFILESUFFIX', src_suffix = ['.in'], ) def generate(env): env['LINESEPARATOR'] = os.linesep env['BUILDERS']['Textfile'] = _text_builder env['TEXTFILEPREFIX'] = '' env['TEXTFILESUFFIX'] = '.txt' env['BUILDERS']['Substfile'] = _subst_builder env['SUBSTFILEPREFIX'] = '' env['SUBSTFILESUFFIX'] = '' def exists(env): return 1 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/icc.py0000644000175000017500000000421113606712377021407 0ustar kurtkurt"""engine.SCons.Tool.icc Tool-specific initialization for the OS/2 icc compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/icc.py 4369 2009/09/19 15:58:29 scons" import cc def generate(env): """Add Builders and construction variables for the OS/2 to an Environment.""" cc.generate(env) env['CC'] = 'icc' env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' env['CXXCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' env['CPPDEFPREFIX'] = '/D' env['CPPDEFSUFFIX'] = '' env['INCPREFIX'] = '/I' env['INCSUFFIX'] = '' env['CFILESUFFIX'] = '.c' env['CXXFILESUFFIX'] = '.cc' def exists(env): return env.Detect('icc') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sunf90.py0000644000175000017500000000417413606712377022005 0ustar kurtkurt"""SCons.Tool.sunf90 Tool-specific initialization for sunf90, the Sun Studio F90 compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sunf90.py 4369 2009/09/19 15:58:29 scons" import SCons.Util from FortranCommon import add_all_to_env compilers = ['sunf90', 'f90'] def generate(env): """Add Builders and construction variables for sun f90 compiler to an Environment.""" add_all_to_env(env) fcomp = env.Detect(compilers) or 'f90' env['FORTRAN'] = fcomp env['F90'] = fcomp env['SHFORTRAN'] = '$FORTRAN' env['SHF90'] = '$F90' env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -KPIC') env['SHF90FLAGS'] = SCons.Util.CLVar('$F90FLAGS -KPIC') def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/hpc++.py0000644000175000017500000000524013606712377021554 0ustar kurtkurt"""SCons.Tool.hpc++ Tool-specific initialization for c++ on HP/UX. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/hpc++.py 4369 2009/09/19 15:58:29 scons" import os.path import string import SCons.Util cplusplus = __import__('c++', globals(), locals(), []) acc = None # search for the acc compiler and linker front end try: dirs = os.listdir('/opt') except (IOError, OSError): # Not being able to read the directory because it doesn't exist # (IOError) or isn't readable (OSError) is okay. dirs = [] for dir in dirs: cc = '/opt/' + dir + '/bin/aCC' if os.path.exists(cc): acc = cc break def generate(env): """Add Builders and construction variables for g++ to an Environment.""" cplusplus.generate(env) if acc: env['CXX'] = acc or 'aCC' env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z') # determine version of aCC line = os.popen(acc + ' -V 2>&1').readline().rstrip() if string.find(line, 'aCC: HP ANSI C++') == 0: env['CXXVERSION'] = string.split(line)[-1] if env['PLATFORM'] == 'cygwin': env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') else: env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z') def exists(env): return acc # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sgic++.py0000644000175000017500000000377013606712377021735 0ustar kurtkurt"""SCons.Tool.sgic++ Tool-specific initialization for MIPSpro C++ on SGI. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sgic++.py 4369 2009/09/19 15:58:29 scons" import SCons.Util cplusplus = __import__('c++', globals(), locals(), []) def generate(env): """Add Builders and construction variables for SGI MIPS C++ to an Environment.""" cplusplus.generate(env) env['CXX'] = 'CC' env['CXXFLAGS'] = SCons.Util.CLVar('-LANG:std') env['SHCXX'] = '$CXX' env['SHOBJSUFFIX'] = '.o' env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 def exists(env): return env.Detect('CC') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/gs.py0000644000175000017500000000476113606712377021274 0ustar kurtkurt"""SCons.Tool.gs Tool-specific initialization for Ghostscript. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/gs.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Platform import SCons.Util # Ghostscript goes by different names on different platforms... platform = SCons.Platform.platform_default() if platform == 'os2': gs = 'gsos2' elif platform == 'win32': gs = 'gswin32c' else: gs = 'gs' GhostscriptAction = None def generate(env): """Add Builders and construction variables for Ghostscript to an Environment.""" global GhostscriptAction if GhostscriptAction is None: GhostscriptAction = SCons.Action.Action('$GSCOM', '$GSCOMSTR') import pdf pdf.generate(env) bld = env['BUILDERS']['PDF'] bld.add_action('.ps', GhostscriptAction) env['GS'] = gs env['GSFLAGS'] = SCons.Util.CLVar('-dNOPAUSE -dBATCH -sDEVICE=pdfwrite') env['GSCOM'] = '$GS $GSFLAGS -sOutputFile=$TARGET $SOURCES' def exists(env): if 'PS2PDF' in env: return env.Detect(env['PS2PDF']) else: return env.Detect(gs) or SCons.Util.WhereIs(gs) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/as.py0000644000175000017500000000564513606712377021270 0ustar kurtkurt"""SCons.Tool.as Tool-specific initialization for as, the generic Posix assembler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/as.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Util assemblers = ['as'] ASSuffixes = ['.s', '.asm', '.ASM'] ASPPSuffixes = ['.spp', '.SPP', '.sx'] if SCons.Util.case_sensitive_suffixes('.s', '.S'): ASPPSuffixes.extend(['.S']) else: ASSuffixes.extend(['.S']) def generate(env): """Add Builders and construction variables for as to an Environment.""" static_obj, shared_obj = SCons.Tool.createObjBuilders(env) for suffix in ASSuffixes: static_obj.add_action(suffix, SCons.Defaults.ASAction) shared_obj.add_action(suffix, SCons.Defaults.ASAction) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) for suffix in ASPPSuffixes: static_obj.add_action(suffix, SCons.Defaults.ASPPAction) shared_obj.add_action(suffix, SCons.Defaults.ASPPAction) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) env['AS'] = env.Detect(assemblers) or 'as' env['ASFLAGS'] = SCons.Util.CLVar('') env['ASCOM'] = '$AS $ASFLAGS -o $TARGET $SOURCES' env['ASPPFLAGS'] = '$ASFLAGS' env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' def exists(env): return env.Detect(assemblers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/gcc.py0000644000175000017500000000547313606712377021420 0ustar kurtkurt"""SCons.Tool.gcc Tool-specific initialization for gcc. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/gcc.py 4369 2009/09/19 15:58:29 scons" import cc import os import re import subprocess import SCons.Util compilers = ['gcc', 'cc'] def generate(env): """Add Builders and construction variables for gcc to an Environment.""" cc.generate(env) env['CC'] = env.Detect(compilers) or 'gcc' if env['PLATFORM'] in ['cygwin', 'win32']: env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') else: env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC') # determine compiler version if env['CC']: #pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'], pipe = SCons.Action._subproc(env, [env['CC'], '--version'], stdin = 'devnull', stderr = 'devnull', stdout = subprocess.PIPE) if pipe.wait() != 0: return # -dumpversion was added in GCC 3.0. As long as we're supporting # GCC versions older than that, we should use --version and a # regular expression. #line = pipe.stdout.read().strip() #if line: # env['CCVERSION'] = line line = pipe.stdout.readline() match = re.search(r'[0-9]+(\.[0-9]+)+', line) if match: env['CCVERSION'] = match.group(0) def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/mwcc.py0000644000175000017500000001537413606712377021616 0ustar kurtkurt"""SCons.Tool.mwcc Tool-specific initialization for the Metrowerks CodeWarrior compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/mwcc.py 4369 2009/09/19 15:58:29 scons" import os import os.path import string import SCons.Util def set_vars(env): """Set MWCW_VERSION, MWCW_VERSIONS, and some codewarrior environment vars MWCW_VERSIONS is set to a list of objects representing installed versions MWCW_VERSION is set to the version object that will be used for building. MWCW_VERSION can be set to a string during Environment construction to influence which version is chosen, otherwise the latest one from MWCW_VERSIONS is used. Returns true if at least one version is found, false otherwise """ desired = env.get('MWCW_VERSION', '') # return right away if the variables are already set if isinstance(desired, MWVersion): return 1 elif desired is None: return 0 versions = find_versions() version = None if desired: for v in versions: if str(v) == desired: version = v elif versions: version = versions[-1] env['MWCW_VERSIONS'] = versions env['MWCW_VERSION'] = version if version is None: return 0 env.PrependENVPath('PATH', version.clpath) env.PrependENVPath('PATH', version.dllpath) ENV = env['ENV'] ENV['CWFolder'] = version.path ENV['LM_LICENSE_FILE'] = version.license plus = lambda x: '+%s' % x ENV['MWCIncludes'] = string.join(map(plus, version.includes), os.pathsep) ENV['MWLibraries'] = string.join(map(plus, version.libs), os.pathsep) return 1 def find_versions(): """Return a list of MWVersion objects representing installed versions""" versions = [] ### This function finds CodeWarrior by reading from the registry on ### Windows. Some other method needs to be implemented for other ### platforms, maybe something that calls env.WhereIs('mwcc') if SCons.Util.can_read_reg: try: HLM = SCons.Util.HKEY_LOCAL_MACHINE product = 'SOFTWARE\\Metrowerks\\CodeWarrior\\Product Versions' product_key = SCons.Util.RegOpenKeyEx(HLM, product) i = 0 while True: name = product + '\\' + SCons.Util.RegEnumKey(product_key, i) name_key = SCons.Util.RegOpenKeyEx(HLM, name) try: version = SCons.Util.RegQueryValueEx(name_key, 'VERSION') path = SCons.Util.RegQueryValueEx(name_key, 'PATH') mwv = MWVersion(version[0], path[0], 'Win32-X86') versions.append(mwv) except SCons.Util.RegError: pass i = i + 1 except SCons.Util.RegError: pass return versions class MWVersion: def __init__(self, version, path, platform): self.version = version self.path = path self.platform = platform self.clpath = os.path.join(path, 'Other Metrowerks Tools', 'Command Line Tools') self.dllpath = os.path.join(path, 'Bin') # The Metrowerks tools don't store any configuration data so they # are totally dumb when it comes to locating standard headers, # libraries, and other files, expecting all the information # to be handed to them in environment variables. The members set # below control what information scons injects into the environment ### The paths below give a normal build environment in CodeWarrior for ### Windows, other versions of CodeWarrior might need different paths. msl = os.path.join(path, 'MSL') support = os.path.join(path, '%s Support' % platform) self.license = os.path.join(path, 'license.dat') self.includes = [msl, support] self.libs = [msl, support] def __str__(self): return self.version CSuffixes = ['.c', '.C'] CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++'] def generate(env): """Add Builders and construction variables for the mwcc to an Environment.""" import SCons.Defaults import SCons.Tool set_vars(env) static_obj, shared_obj = SCons.Tool.createObjBuilders(env) for suffix in CSuffixes: static_obj.add_action(suffix, SCons.Defaults.CAction) shared_obj.add_action(suffix, SCons.Defaults.ShCAction) for suffix in CXXSuffixes: static_obj.add_action(suffix, SCons.Defaults.CXXAction) shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction) env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -nolink -o $TARGET $SOURCES' env['CC'] = 'mwcc' env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CCCOMFLAGS' env['CXX'] = 'mwcc' env['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS' env['SHCC'] = '$CC' env['SHCCFLAGS'] = '$CCFLAGS' env['SHCFLAGS'] = '$CFLAGS' env['SHCCCOM'] = '$SHCC $SHCFLAGS $SHCCFLAGS $CCCOMFLAGS' env['SHCXX'] = '$CXX' env['SHCXXFLAGS'] = '$CXXFLAGS' env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS' env['CFILESUFFIX'] = '.c' env['CXXFILESUFFIX'] = '.cpp' env['CPPDEFPREFIX'] = '-D' env['CPPDEFSUFFIX'] = '' env['INCPREFIX'] = '-I' env['INCSUFFIX'] = '' #env['PCH'] = ? #env['PCHSTOP'] = ? def exists(env): return set_vars(env) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/MSCommon/0000755000175000017500000000000013606712377021771 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/MSCommon/sdk.py0000644000175000017500000002456213606712377023135 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py 4369 2009/09/19 15:58:29 scons" __doc__ = """Module to detect the Platform/Windows SDK PSDK 2003 R1 is the earliest version detected. """ import os import SCons.Errors import SCons.Util import common debug = common.debug # SDK Checks. This is of course a mess as everything else on MS platforms. Here # is what we do to detect the SDK: # # For Windows SDK >= 6.0: just look into the registry entries: # HKLM\Software\Microsoft\Microsoft SDKs\Windows # All the keys in there are the available versions. # # For Platform SDK before 6.0 (2003 server R1 and R2, etc...), there does not # seem to be any sane registry key, so the precise location is hardcoded. # # For versions below 2003R1, it seems the PSDK is included with Visual Studio? # # Also, per the following: # http://benjamin.smedbergs.us/blog/tag/atl/ # VC++ Professional comes with the SDK, VC++ Express does not. # Location of the SDK (checked for 6.1 only) _CURINSTALLED_SDK_HKEY_ROOT = \ r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder" class SDKDefinition: """ An abstract base class for trying to find installed SDK directories. """ def __init__(self, version, **kw): self.version = version self.__dict__.update(kw) def find_sdk_dir(self): """Try to find the MS SDK from the registry. Return None if failed or the directory does not exist. """ if not SCons.Util.can_read_reg: debug('find_sdk_dir(): can not read registry') return None hkey = self.HKEY_FMT % self.hkey_data try: sdk_dir = common.read_reg(hkey) except WindowsError as e: debug('find_sdk_dir(): no SDK registry key %s' % repr(hkey)) return None if not os.path.exists(sdk_dir): debug('find_sdk_dir(): %s not on file system' % sdk_dir) return None ftc = os.path.join(sdk_dir, self.sanity_check_file) if not os.path.exists(ftc): debug("find_sdk_dir(): sanity check %s not found" % ftc) return None return sdk_dir def get_sdk_dir(self): """Return the MSSSDK given the version string.""" try: return self._sdk_dir except AttributeError: sdk_dir = self.find_sdk_dir() self._sdk_dir = sdk_dir return sdk_dir class WindowsSDK(SDKDefinition): """ A subclass for trying to find installed Windows SDK directories. """ HKEY_FMT = r'Software\Microsoft\Microsoft SDKs\Windows\v%s\InstallationFolder' def __init__(self, *args, **kw): SDKDefinition.__init__(*(self,)+args, **kw) self.hkey_data = self.version class PlatformSDK(SDKDefinition): """ A subclass for trying to find installed Platform SDK directories. """ HKEY_FMT = r'Software\Microsoft\MicrosoftSDK\InstalledSDKS\%s\Install Dir' def __init__(self, *args, **kw): SDKDefinition.__init__(*(self,)+args, **kw) self.hkey_data = self.uuid # The list of support SDKs which we know how to detect. # # The first SDK found in the list is the one used by default if there # are multiple SDKs installed. Barring good reasons to the contrary, # this means we should list SDKs with from most recent to oldest. # # If you update this list, update the documentation in Tool/mssdk.xml. SupportedSDKList = [ WindowsSDK('6.1', sanity_check_file=r'bin\SetEnv.Cmd', include_subdir='include', lib_subdir={ 'x86' : ['lib'], 'x86_64' : [r'lib\x64'], 'ia64' : [r'lib\ia64'], }, ), WindowsSDK('6.0A', sanity_check_file=r'include\windows.h', include_subdir='include', lib_subdir={ 'x86' : ['lib'], 'x86_64' : [r'lib\x64'], 'ia64' : [r'lib\ia64'], }, ), WindowsSDK('6.0', sanity_check_file=r'bin\gacutil.exe', include_subdir='include', lib_subdir='lib', ), PlatformSDK('2003R2', sanity_check_file=r'SetEnv.Cmd', uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1" ), PlatformSDK('2003R1', sanity_check_file=r'SetEnv.Cmd', uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3", ), ] SupportedSDKMap = {} for sdk in SupportedSDKList: SupportedSDKMap[sdk.version] = sdk # Finding installed SDKs isn't cheap, because it goes not only to the # registry but also to the disk to sanity-check that there is, in fact, # an SDK installed there and that the registry entry isn't just stale. # Find this information once, when requested, and cache it. InstalledSDKList = None InstalledSDKMap = None def get_installed_sdks(): global InstalledSDKList global InstalledSDKMap if InstalledSDKList is None: InstalledSDKList = [] InstalledSDKMap = {} for sdk in SupportedSDKList: debug('trying to find SDK %s' % sdk.version) if sdk.get_sdk_dir(): debug('found SDK %s' % sdk.version) InstalledSDKList.append(sdk) InstalledSDKMap[sdk.version] = sdk return InstalledSDKList # We may be asked to update multiple construction environments with # SDK information. When doing this, we check on-disk for whether # the SDK has 'mfc' and 'atl' subdirectories. Since going to disk # is expensive, cache results by directory. SDKEnvironmentUpdates = {} def set_sdk_by_directory(env, sdk_dir): global SDKEnvironmentUpdates try: env_tuple_list = SDKEnvironmentUpdates[sdk_dir] except KeyError: env_tuple_list = [] SDKEnvironmentUpdates[sdk_dir] = env_tuple_list include_path = os.path.join(sdk_dir, 'include') mfc_path = os.path.join(include_path, 'mfc') atl_path = os.path.join(include_path, 'atl') if os.path.exists(mfc_path): env_tuple_list.append(('INCLUDE', mfc_path)) if os.path.exists(atl_path): env_tuple_list.append(('INCLUDE', atl_path)) env_tuple_list.append(('INCLUDE', include_path)) env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib'))) env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib'))) env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin'))) for variable, directory in env_tuple_list: env.PrependENVPath(variable, directory) # TODO(sgk): currently unused; remove? def get_cur_sdk_dir_from_reg(): """Try to find the platform sdk directory from the registry. Return None if failed or the directory does not exist""" if not SCons.Util.can_read_reg: debug('SCons cannot read registry') return None try: val = common.read_reg(_CURINSTALLED_SDK_HKEY_ROOT) debug("Found current sdk dir in registry: %s" % val) except WindowsError as e: debug("Did not find current sdk in registry") return None if not os.path.exists(val): debug("Current sdk dir %s not on fs" % val) return None return val def get_sdk_by_version(mssdk): if mssdk not in SupportedSDKMap: msg = "SDK version %s is not supported" % repr(mssdk) raise SCons.Errors.UserError(msg) get_installed_sdks() return InstalledSDKMap.get(mssdk) def get_default_sdk(): """Set up the default Platform/Windows SDK.""" get_installed_sdks() if not InstalledSDKList: return None return InstalledSDKList[0] def mssdk_setup_env(env): debug('msvs_setup_env()') if 'MSSDK_DIR' in env: sdk_dir = env['MSSDK_DIR'] if sdk_dir is None: return sdk_dir = env.subst(sdk_dir) elif 'MSSDK_VERSION' in env: sdk_version = env['MSSDK_VERSION'] if sdk_version is None: msg = "SDK version %s is not installed" % repr(mssdk) raise SCons.Errors.UserError(msg) sdk_version = env.subst(sdk_version) mssdk = get_sdk_by_version(sdk_version) sdk_dir = mssdk.get_sdk_dir() elif 'MSVS_VERSION' in env: msvs_version = env['MSVS_VERSION'] debug('Getting MSVS_VERSION from env:%s'%msvs_version) if msvs_version is None: return msvs_version = env.subst(msvs_version) import vs msvs = vs.get_vs_by_version(msvs_version) debug('msvs is :%s'%msvs) if not msvs: return sdk_version = msvs.sdk_version if not sdk_version: return mssdk = get_sdk_by_version(sdk_version) if not mssdk: mssdk = get_default_sdk() if not mssdk: return sdk_dir = mssdk.get_sdk_dir() else: mssdk = get_default_sdk() if not mssdk: return sdk_dir = mssdk.get_sdk_dir() set_sdk_by_directory(env, sdk_dir) #print "No MSVS_VERSION: this is likely to be a bug" def mssdk_exists(version=None): sdks = get_installed_sdks() if version is None: return len(sdks) > 0 return version in sdks # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/MSCommon/__init__.py0000644000175000017500000000376313606712377024113 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py 4369 2009/09/19 15:58:29 scons" __doc__ = """ Common functions for Microsoft Visual Studio and Visual C/C++. """ import copy import os import re import subprocess import SCons.Errors import SCons.Platform.win32 import SCons.Util from SCons.Tool.MSCommon.sdk import mssdk_exists, \ mssdk_setup_env from SCons.Tool.MSCommon.vc import msvc_exists, \ msvc_setup_env from SCons.Tool.MSCommon.vs import get_default_version, \ get_vs_by_version, \ merge_default_version, \ msvs_exists, \ query_versions # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/MSCommon/common.py0000644000175000017500000001463113606712377023640 0ustar kurtkurtfrom __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/MSCommon/common.py 4369 2009/09/19 15:58:29 scons" __doc__ = """ Common helper functions for working with the Microsoft tool chain. """ import copy import os import subprocess import re import SCons.Util logfile = os.environ.get('SCONS_MSCOMMON_DEBUG') if logfile == '-': def debug(x): print(x) elif logfile: try: import logging except ImportError: debug = lambda x: open(logfile, 'a').write(x + '\n') else: logging.basicConfig(filename=logfile, level=logging.DEBUG) debug = logging.debug else: debug = lambda x: None _is_win64 = None def is_win64(): """Return true if running on windows 64 bits. Works whether python itself runs in 64 bits or 32 bits.""" # Unfortunately, python does not provide a useful way to determine # if the underlying Windows OS is 32-bit or 64-bit. Worse, whether # the Python itself is 32-bit or 64-bit affects what it returns, # so nothing in sys.* or os.* help. So we go to the registry to # look directly for a clue from Windows, caching the result to # avoid repeated registry calls. global _is_win64 if _is_win64 is None: _is_win64 = has_reg(r"Software\Wow6432Node") return _is_win64 def read_reg(value): return SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, value)[0] def has_reg(value): """Return True if the given key exists in HKEY_LOCAL_MACHINE, False otherwise.""" try: SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, value) ret = True except WindowsError: ret = False return ret # Functions for fetching environment variable settings from batch files. def normalize_env(env, keys): """Given a dictionary representing a shell environment, add the variables from os.environ needed for the processing of .bat files; the keys are controlled by the keys argument. It also makes sure the environment values are correctly encoded. Note: the environment is copied""" normenv = {} if env: for k in env.keys(): normenv[k] = copy.deepcopy(env[k]).encode('mbcs') for k in keys: if k in os.environ: normenv[k] = os.environ[k].encode('mbcs') return normenv def get_output(vcbat, args = None, env = None): """Parse the output of given bat file, with given args.""" if args: debug("Calling '%s %s'" % (vcbat, args)) popen = subprocess.Popen('"%s" %s & set' % (vcbat, args), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) else: debug("Calling '%s'" % vcbat) popen = subprocess.Popen('"%s" & set' % vcbat, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) # Use the .stdout and .stderr attributes directly because the # .communicate() method uses the threading module on Windows # and won't work under Pythons not built with threading. stdout = popen.stdout.read() if popen.wait() != 0: raise IOError(popen.stderr.read().decode("mbcs")) output = stdout.decode("mbcs") return output def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")): # dkeep is a dict associating key: path_list, where key is one item from # keep, and pat_list the associated list of paths # TODO(1.5): replace with the following list comprehension: #dkeep = dict([(i, []) for i in keep]) dkeep = dict(map(lambda i: (i, []), keep)) # rdk will keep the regex to match the .bat file output line starts rdk = {} for i in keep: rdk[i] = re.compile('%s=(.*)' % i, re.I) def add_env(rmatch, key, dkeep=dkeep): plist = rmatch.group(1).split(os.pathsep) for p in plist: # Do not add empty paths (when a var ends with ;) if p: p = p.encode('mbcs') # XXX: For some reason, VC98 .bat file adds "" around the PATH # values, and it screws up the environment later, so we strip # it. p = p.strip('"') dkeep[key].append(p) for line in output.splitlines(): for k,v in rdk.items(): m = v.match(line) if m: add_env(m, k) return dkeep # TODO(sgk): unused def output_to_dict(output): """Given an output string, parse it to find env variables. Return a dict where keys are variables names, and values their content""" envlinem = re.compile(r'^([a-zA-z0-9]+)=([\S\s]*)$') parsedenv = {} for line in output.splitlines(): m = envlinem.match(line) if m: parsedenv[m.group(1)] = m.group(2) return parsedenv # TODO(sgk): unused def get_new(l1, l2): """Given two list l1 and l2, return the items in l2 which are not in l1. Order is maintained.""" # We don't try to be smart: lists are small, and this is not the bottleneck # is any case new = [] for i in l2: if i not in l1: new.append(i) return new # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/MSCommon/netframework.py0000644000175000017500000000543113606712377025052 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/MSCommon/netframework.py 4369 2009/09/19 15:58:29 scons" __doc__ = """ """ import os import re import string from common import read_reg, debug # Original value recorded by dcournapeau _FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot' # On SGK's system _FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\Microsoft SDKs\.NETFramework\v2.0\InstallationFolder' def find_framework_root(): # XXX: find it from environment (FrameworkDir) try: froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT) debug("Found framework install root in registry: %s" % froot) except WindowsError as e: debug("Could not read reg key %s" % _FRAMEWORKDIR_HKEY_ROOT) return None if not os.path.exists(froot): debug("%s not found on fs" % froot) return None return froot def query_versions(): froot = find_framework_root() if froot: contents = os.listdir(froot) l = re.compile('v[0-9]+.*') versions = filter(lambda e, l=l: l.match(e), contents) def versrt(a,b): # since version numbers aren't really floats... aa = a[1:] bb = b[1:] aal = string.split(aa, '.') bbl = string.split(bb, '.') # sequence comparison in python is lexicographical # which is exactly what we want. # Note we sort backwards so the highest version is first. return cmp(bbl,aal) versions.sort(versrt) else: versions = [] return versions # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/MSCommon/vs.py0000644000175000017500000004346613606712377023010 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/MSCommon/vs.py 4369 2009/09/19 15:58:29 scons" __doc__ = """Module to detect Visual Studio and/or Visual C/C++ """ import os import SCons.Errors import SCons.Util from common import debug, \ get_output, \ is_win64, \ normalize_env, \ parse_output, \ read_reg import SCons.Tool.MSCommon.vc class VisualStudio: """ An abstract base class for trying to find installed versions of Visual Studio. """ def __init__(self, version, **kw): self.version = version kw['vc_version'] = kw.get('vc_version', version) kw['sdk_version'] = kw.get('sdk_version', version) self.__dict__.update(kw) self._cache = {} # def find_batch_file(self): vs_dir = self.get_vs_dir() if not vs_dir: debug('find_executable(): no vs_dir') return None batch_file = os.path.join(vs_dir, self.batch_file_path) batch_file = os.path.normpath(batch_file) if not os.path.isfile(batch_file): debug('find_batch_file(): %s not on file system' % batch_file) return None return batch_file def find_vs_dir_by_vc(self): SCons.Tool.MSCommon.vc.get_installed_vcs() ivc = SCons.Tool.MSCommon.vc.InstalledVCMap.get(self.vc_version) if not ivc: debug('find_vs_dir(): no installed VC %s' % self.vc_version) return None return ivc.get_vc_dir()[:-len(ivc.vc_subdir)] def find_vs_dir_by_reg(self): root = 'Software\\' if is_win64(): root = root + 'Wow6432Node\\' for key in self.hkeys: if key=='use_dir': return self.find_vs_dir_by_vc() key = root + key try: comps = read_reg(key) except WindowsError as e: debug('find_vs_dir_by_reg(): no VS registry key %s' % repr(key)) else: debug('find_vs_dir_by_reg(): found VS in registry: %s' % comps) return comps return None def find_vs_dir(self): """ Can use registry or location of VC to find vs dir First try to find by registry, and if that fails find via VC dir """ if True: vs_dir=self.find_vs_dir_by_reg() return vs_dir else: return self.find_vs_dir_by_vc() def find_executable(self): vs_dir = self.get_vs_dir() if not vs_dir: debug('find_executable(): no vs_dir (%s)'%vs_dir) return None executable = os.path.join(vs_dir, self.executable_path) executable = os.path.normpath(executable) if not os.path.isfile(executable): debug('find_executable(): %s not on file system' % executable) return None return executable # def get_batch_file(self): try: return self._cache['batch_file'] except KeyError: batch_file = self.find_batch_file() self._cache['batch_file'] = batch_file return batch_file def get_executable(self): try: debug('get_executable using cache:%s'%self._cache['executable']) return self._cache['executable'] except KeyError: executable = self.find_executable() self._cache['executable'] = executable debug('get_executable not in cache:%s'%executable) return executable def get_vs_dir(self): try: return self._cache['vs_dir'] except KeyError: vs_dir = self.find_vs_dir() self._cache['vs_dir'] = vs_dir return vs_dir def get_supported_arch(self): try: return self._cache['supported_arch'] except KeyError: # RDEVE: for the time being use hardcoded lists # supported_arch = self.find_supported_arch() self._cache['supported_arch'] = self.supported_arch return self.supported_arch def reset(self): self._cache = {} # The list of supported Visual Studio versions we know how to detect. # # How to look for .bat file ? # - VS 2008 Express (x86): # * from registry key productdir, gives the full path to vsvarsall.bat. In # HKEY_LOCAL_MACHINE): # Software\Microsoft\VCEpress\9.0\Setup\VC\productdir # * from environmnent variable VS90COMNTOOLS: the path is then ..\..\VC # relatively to the path given by the variable. # # - VS 2008 Express (WoW6432: 32 bits on windows x64): # Software\Wow6432Node\Microsoft\VCEpress\9.0\Setup\VC\productdir # # - VS 2005 Express (x86): # * from registry key productdir, gives the full path to vsvarsall.bat. In # HKEY_LOCAL_MACHINE): # Software\Microsoft\VCEpress\8.0\Setup\VC\productdir # * from environmnent variable VS80COMNTOOLS: the path is then ..\..\VC # relatively to the path given by the variable. # # - VS 2005 Express (WoW6432: 32 bits on windows x64): does not seem to have a # productdir ? # # - VS 2003 .Net (pro edition ? x86): # * from registry key productdir. The path is then ..\Common7\Tools\ # relatively to the key. The key is in HKEY_LOCAL_MACHINE): # Software\Microsoft\VisualStudio\7.1\Setup\VC\productdir # * from environmnent variable VS71COMNTOOLS: the path is the full path to # vsvars32.bat # # - VS 98 (VS 6): # * from registry key productdir. The path is then Bin # relatively to the key. The key is in HKEY_LOCAL_MACHINE): # Software\Microsoft\VisualStudio\6.0\Setup\VC98\productdir # # The first version found in the list is the one used by default if # there are multiple versions installed. Barring good reasons to # the contrary, this means we should list versions from most recent # to oldest. Pro versions get listed before Express versions on the # assumption that, by default, you'd rather use the version you paid # good money for in preference to whatever Microsoft makes available # for free. # # If you update this list, update the documentation in Tool/msvs.xml. SupportedVSList = [ # Visual Studio 2010 # TODO: find the settings, perhaps from someone with a CTP copy? #VisualStudio('TBD', # hkey_root=r'TBD', # common_tools_var='TBD', # executable_path=r'TBD', # default_dirname='TBD', #), # Visual Studio 2008 # The batch file we look for is in the VC directory, # so the devenv.com executable is up in ..\..\Common7\IDE. VisualStudio('9.0', sdk_version='6.1', hkeys=[r'Microsoft\VisualStudio\9.0\Setup\VS\ProductDir'], common_tools_var='VS90COMNTOOLS', executable_path=r'Common7\IDE\devenv.com', batch_file_path=r'Common7\Tools\vsvars32.bat', default_dirname='Microsoft Visual Studio 9', supported_arch=['x86', 'amd64'], ), # Visual C++ 2008 Express Edition # The batch file we look for is in the VC directory, # so the VCExpress.exe executable is up in ..\..\Common7\IDE. VisualStudio('9.0Exp', vc_version='9.0', sdk_version='6.1', hkeys=[r'Microsoft\VCExpress\9.0\Setup\VS\ProductDir'], common_tools_var='VS90COMNTOOLS', executable_path=r'Common7\IDE\VCExpress.exe', batch_file_path=r'Common7\Tools\vsvars32.bat', default_dirname='Microsoft Visual Studio 9', supported_arch=['x86'], ), # Visual Studio 2005 # The batch file we look for is in the VC directory, # so the devenv.com executable is up in ..\..\Common7\IDE. VisualStudio('8.0', sdk_version='6.0A', hkeys=[r'Microsoft\VisualStudio\8.0\Setup\VS\ProductDir'], common_tools_var='VS80COMNTOOLS', executable_path=r'Common7\IDE\devenv.com', batch_file_path=r'Common7\Tools\vsvars32.bat', default_dirname='Microsoft Visual Studio 8', supported_arch=['x86', 'amd64'], ), # Visual C++ 2005 Express Edition # The batch file we look for is in the VC directory, # so the VCExpress.exe executable is up in ..\..\Common7\IDE. VisualStudio('8.0Exp', vc_version='8.0', sdk_version='6.0A', hkeys=[r'Microsoft\VCExpress\8.0\Setup\VS\ProductDir'], common_tools_var='VS80COMNTOOLS', executable_path=r'Common7\IDE\VCExpress.exe', batch_file_path=r'Common7\Tools\vsvars32.bat', default_dirname='Microsoft Visual Studio 8', supported_arch=['x86'], ), # Visual Studio .NET 2003 # The batch file we look for is in the Common7\Tools directory, # so the devenv.com executable is next door in ..\IDE. VisualStudio('7.1', sdk_version='6.0', hkeys=[r'Microsoft\VisualStudio\7.1\Setup\VS\ProductDir'], common_tools_var='VS71COMNTOOLS', executable_path=r'Common7\IDE\devenv.com', batch_file_path=r'Common7\Tools\vsvars32.bat', default_dirname='Microsoft Visual Studio .NET 2003', supported_arch=['x86'], ), # Visual Studio .NET # The batch file we look for is in the Common7\Tools directory, # so the devenv.com executable is next door in ..\IDE. VisualStudio('7.0', sdk_version='2003R2', hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'], common_tools_var='VS70COMNTOOLS', executable_path=r'IDE\devenv.com', batch_file_path=r'Common7\Tools\vsvars32.bat', default_dirname='Microsoft Visual Studio .NET', supported_arch=['x86'], ), # Visual Studio 6.0 VisualStudio('6.0', sdk_version='2003R1', hkeys=[r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio\ProductDir', 'use_dir'], common_tools_var='VS60COMNTOOLS', executable_path=r'Common\MSDev98\Bin\MSDEV.COM', batch_file_path=r'Common7\Tools\vsvars32.bat', default_dirname='Microsoft Visual Studio', supported_arch=['x86'], ), ] SupportedVSMap = {} for vs in SupportedVSList: SupportedVSMap[vs.version] = vs # Finding installed versions of Visual Studio isn't cheap, because it # goes not only to the registry but also to the disk to sanity-check # that there is, in fact, a Visual Studio directory there and that the # registry entry isn't just stale. Find this information once, when # requested, and cache it. InstalledVSList = None InstalledVSMap = None def get_installed_visual_studios(): global InstalledVSList global InstalledVSMap if InstalledVSList is None: InstalledVSList = [] InstalledVSMap = {} for vs in SupportedVSList: debug('trying to find VS %s' % vs.version) if vs.get_executable(): debug('found VS %s' % vs.version) InstalledVSList.append(vs) InstalledVSMap[vs.version] = vs return InstalledVSList def reset_installed_visual_studios(): global InstalledVSList global InstalledVSMap InstalledVSList = None InstalledVSMap = None for vs in SupportedVSList: vs.reset() # Need to clear installed VC's as well as they are used in finding # installed VS's SCons.Tool.MSCommon.vc.reset_installed_vcs() # We may be asked to update multiple construction environments with # SDK information. When doing this, we check on-disk for whether # the SDK has 'mfc' and 'atl' subdirectories. Since going to disk # is expensive, cache results by directory. #SDKEnvironmentUpdates = {} # #def set_sdk_by_directory(env, sdk_dir): # global SDKEnvironmentUpdates # try: # env_tuple_list = SDKEnvironmentUpdates[sdk_dir] # except KeyError: # env_tuple_list = [] # SDKEnvironmentUpdates[sdk_dir] = env_tuple_list # # include_path = os.path.join(sdk_dir, 'include') # mfc_path = os.path.join(include_path, 'mfc') # atl_path = os.path.join(include_path, 'atl') # # if os.path.exists(mfc_path): # env_tuple_list.append(('INCLUDE', mfc_path)) # if os.path.exists(atl_path): # env_tuple_list.append(('INCLUDE', atl_path)) # env_tuple_list.append(('INCLUDE', include_path)) # # env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib'))) # env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib'))) # env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin'))) # # for variable, directory in env_tuple_list: # env.PrependENVPath(variable, directory) def msvs_exists(): return (len(get_installed_visual_studios()) > 0) def get_vs_by_version(msvs): global InstalledVSMap global SupportedVSMap if msvs not in SupportedVSMap: msg = "Visual Studio version %s is not supported" % repr(msvs) raise SCons.Errors.UserError(msg) get_installed_visual_studios() vs = InstalledVSMap.get(msvs) debug('InstalledVSMap:%s'%InstalledVSMap) # Some check like this would let us provide a useful error message # if they try to set a Visual Studio version that's not installed. # However, we also want to be able to run tests (like the unit # tests) on systems that don't, or won't ever, have it installed. # It might be worth resurrecting this, with some configurable # setting that the tests can use to bypass the check. #if not vs: # msg = "Visual Studio version %s is not installed" % repr(msvs) # raise SCons.Errors.UserError, msg return vs def get_default_version(env): """Returns the default version string to use for MSVS. If no version was requested by the user through the MSVS environment variable, query all the available the visual studios through query_versions, and take the highest one. Return ------ version: str the default version. """ if 'MSVS' not in env or not SCons.Util.is_Dict(env['MSVS']): # TODO(1.5): #versions = [vs.version for vs in get_installed_visual_studios()] versions = map(lambda vs: vs.version, get_installed_visual_studios()) env['MSVS'] = {'VERSIONS' : versions} else: versions = env['MSVS'].get('VERSIONS', []) if 'MSVS_VERSION' not in env: if versions: env['MSVS_VERSION'] = versions[0] #use highest version by default else: env['MSVS_VERSION'] = SupportedVSList[0].version env['MSVS']['VERSION'] = env['MSVS_VERSION'] return env['MSVS_VERSION'] def get_default_arch(env): """Return the default arch to use for MSVS if no version was requested by the user through the MSVS_ARCH environment variable, select x86 Return ------ arch: str """ arch = env.get('MSVS_ARCH', 'x86') msvs = InstalledVSMap.get(env['MSVS_VERSION']) if not msvs: arch = 'x86' elif not arch in msvs.get_supported_arch(): fmt = "Visual Studio version %s does not support architecture %s" raise SCons.Errors.UserError(fmt % (env['MSVS_VERSION'], arch)) return arch def merge_default_version(env): version = get_default_version(env) arch = get_default_arch(env) msvs = get_vs_by_version(version) if msvs is None: return batfilename = msvs.get_batch_file() # XXX: I think this is broken. This will silently set a bogus tool instead # of failing, but there is no other way with the current scons tool # framework if batfilename is not None: vars = ('LIB', 'LIBPATH', 'PATH', 'INCLUDE') msvs_list = get_installed_visual_studios() # TODO(1.5): #vscommonvarnames = [ vs.common_tools_var for vs in msvs_list ] vscommonvarnames = map(lambda vs: vs.common_tools_var, msvs_list) nenv = normalize_env(env['ENV'], vscommonvarnames + ['COMSPEC']) output = get_output(batfilename, arch, env=nenv) vars = parse_output(output, vars) for k, v in vars.items(): env.PrependENVPath(k, v, delete_existing=1) def query_versions(): """Query the system to get available versions of VS. A version is considered when a batfile is found.""" msvs_list = get_installed_visual_studios() # TODO(1.5) #versions = [ msvs.version for msvs in msvs_list ] versions = map(lambda msvs: msvs.version, msvs_list) return versions # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/MSCommon/vc.py0000644000175000017500000002742413606712377022764 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/MSCommon/vc.py 4369 2009/09/19 15:58:29 scons" __doc__ = """Module for Visual C/C++ detection and configuration. """ import os import SCons.Warnings import common debug = common.debug class VisualC: """ An base class for finding installed versions of Visual C/C++. """ def __init__(self, version, **kw): self.version = version self.__dict__.update(kw) self._cache = {} def vcbin_arch(self): if common.is_win64(): result = { 'x86_64' : ['amd64', r'BIN\x86_amd64'], 'ia64' : [r'BIN\ia64'], }.get(target_arch, []) else: result = { 'x86_64' : ['x86_amd64'], 'ia64' : ['x86_ia64'], }.get(target_arch, []) # TODO(1.5) #return ';'.join(result) return string.join(result, ';') # Support for searching for an appropriate .bat file. # The map is indexed by (target_architecture, host_architecture). # Entries where the host_architecture is None specify the # cross-platform "default" .bat file if there isn't sn entry # specific to the current host architecture. batch_file_map = { ('x86_64', 'x86_64') : [ r'bin\amd64\vcvarsamd64.bat', r'bin\x86_amd64\vcvarsx86_amd64.bat', ], ('x86_64', 'x86') : [ r'bin\x86_amd64\vcvarsx86_amd64.bat', ], ('ia64', 'ia64') : [ r'bin\ia64\vcvarsia64.bat', r'bin\x86_ia64\vcvarsx86_ia64.bat', ], ('ia64', None) : [ r'bin\x86_ia64\vcvarsx86_ia64.bat', ], ('x86', None) : [ r'bin\vcvars32.bat', ], } def find_batch_file(self, target_architecture, host_architecture): key = (target_architecture, host_architecture) potential_batch_files = self.batch_file_map.get(key) if not potential_batch_files: key = (target_architecture, None) potential_batch_files = self.batch_file_map.get(key) if potential_batch_files: product_dir = self.get_vc_dir() for batch_file in potential_batch_files: bf = os.path.join(product_dir, batch_file) if os.path.isfile(bf): return bf return None def find_vc_dir(self): root = 'Software\\' if common.is_win64(): root = root + 'Wow6432Node\\' for key in self.hkeys: key = root + key try: comps = common.read_reg(key) except WindowsError as e: debug('find_vc_dir(): no VC registry key %s' % repr(key)) else: debug('find_vc_dir(): found VC in registry: %s' % comps) if os.path.exists(comps): return comps else: debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\ % comps) return None return None # def get_batch_file(self, target_architecture, host_architecture): try: return self._cache['batch_file'] except KeyError: batch_file = self.find_batch_file(target_architecture, host_architecture) self._cache['batch_file'] = batch_file return batch_file def get_vc_dir(self): try: return self._cache['vc_dir'] except KeyError: vc_dir = self.find_vc_dir() self._cache['vc_dir'] = vc_dir return vc_dir def reset(self): self._cache={} # The list of supported Visual C/C++ versions we know how to detect. # # The first VC found in the list is the one used by default if there # are multiple VC installed. Barring good reasons to the contrary, # this means we should list VC with from most recent to oldest. # # If you update this list, update the documentation in Tool/vc.xml. SupportedVCList = [ VisualC('9.0', hkeys=[ r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir', r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir', ], default_install=r'Microsoft Visual Studio 9.0\VC', common_tools_var='VS90COMNTOOLS', vc_subdir=r'\VC', batch_file_base='vcvars', supported_arch=['x86', 'x86_64', 'ia64'], atlmc_include_subdir = [r'ATLMFC\INCLUDE'], atlmfc_lib_subdir = { 'x86' : r'ATLMFC\LIB', 'x86_64' : r'ATLMFC\LIB\amd64', 'ia64' : r'ATLMFC\LIB\ia64', }, crt_lib_subdir = { 'x86_64' : r'LIB\amd64', 'ia64' : r'LIB\ia64', }, ), VisualC('8.0', hkeys=[ r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir', r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir', ], default_install=r'%s\Microsoft Visual Studio 8\VC', common_tools_var='VS80COMNTOOLS', vc_subdir=r'\VC', batch_file_base='vcvars', supported_arch=['x86', 'x86_64', 'ia64'], atlmc_include_subdir = [r'ATLMFC\INCLUDE'], atlmfc_lib_subdir = { 'x86' : r'ATLMFC\LIB', 'x86_64' : r'ATLMFC\LIB\amd64', 'ia64' : r'ATLMFC\LIB\ia64', }, crt_lib_subdir = { 'x86_64' : r'LIB\amd64', 'ia64' : r'LIB\ia64', }, ), VisualC('7.1', hkeys=[ r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir', ], default_install=r'%s\Microsoft Visual Studio 7.1.NET 2003\VC7', common_tools_var='VS71COMNTOOLS', vc_subdir=r'\VC7', batch_file_base='vcvars', supported_arch=['x86'], atlmc_include_subdir = [r'ATLMFC\INCLUDE'], atlmfc_lib_subdir = { 'x86' : r'ATLMFC\LIB', }, ), VisualC('7.0', hkeys=[ r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir', ], default_install=r'%s\Microsoft Visual Studio .NET\VC7', common_tools_var='VS70COMNTOOLS', vc_subdir=r'\VC7', batch_file_base='vcvars', supported_arch=['x86'], atlmc_include_subdir = [r'ATLMFC\INCLUDE'], atlmfc_lib_subdir = { 'x86' : r'ATLMFC\LIB', }, ), VisualC('6.0', hkeys=[ r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir', ], default_install=r'%s\Microsoft Visual Studio\VC98', common_tools_var='VS60COMNTOOLS', vc_subdir=r'\VC98', batch_file_base='vcvars', supported_arch=['x86'], atlmc_include_subdir = [r'ATL\INCLUDE', r'MFC\INCLUDE'], atlmfc_lib_subdir = { 'x86' : r'MFC\LIB', }, ), ] SupportedVCMap = {} for vc in SupportedVCList: SupportedVCMap[vc.version] = vc # Finding installed versions of Visual C/C++ isn't cheap, because it goes # not only to the registry but also to the disk to sanity-check that there # is, in fact, something installed there and that the registry entry isn't # just stale. Find this information once, when requested, and cache it. InstalledVCList = None InstalledVCMap = None def get_installed_vcs(): global InstalledVCList global InstalledVCMap if InstalledVCList is None: InstalledVCList = [] InstalledVCMap = {} for vc in SupportedVCList: debug('trying to find VC %s' % vc.version) if vc.get_vc_dir(): debug('found VC %s' % vc.version) InstalledVCList.append(vc) InstalledVCMap[vc.version] = vc return InstalledVCList def set_vc_by_version(env, msvc): if msvc not in SupportedVCMap: msg = "VC version %s is not supported" % repr(msvc) raise SCons.Errors.UserError(msg) get_installed_vcs() vc = InstalledVCMap.get(msvc) if not vc: msg = "VC version %s is not installed" % repr(msvc) raise SCons.Errors.UserError(msg) set_vc_by_directory(env, vc.get_vc_dir()) # New stuff def script_env(script): stdout = common.get_output(script) return common.parse_output(stdout) def msvc_setup_env(env): debug('msvc_setup_env()') installed_vcs = get_installed_vcs() debug('InstalledVCMap:%s'%InstalledVCMap) msvc_version = env.get('MSVC_VERSION') if not msvc_version: if not installed_vcs: msg = 'No installed VCs' debug('msv %s\n' % repr(msg)) SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg) return msvc = installed_vcs[0] msvc_version = msvc.version env['MSVC_VERSION'] = msvc_version debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version)) else: msvc = InstalledVCMap.get(msvc_version) debug('msvc_setup_env: using specified MSVC version %s\n' % repr(msvc_version)) if not msvc: msg = 'VC version %s not installed' % msvc_version debug('msv %s\n' % repr(msg)) SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg) return host_platform = env.get('HOST_ARCH') if not host_platform: #host_platform = get_default_host_platform() host_platform = 'x86' target_platform = env.get('TARGET_ARCH') if not target_platform: target_platform = host_platform use_script = env.get('MSVC_USE_SCRIPT', True) if SCons.Util.is_String(use_script): debug('use_script 1 %s\n' % repr(use_script)) d = script_env(use_script) elif use_script: script = msvc.get_batch_file(target_platform, host_platform) debug('use_script 2 %s target_platform:%s host_platform:%s\n' % (repr(script),target_platform,host_platform)) d = script_env(script) else: debug('msvc.get_default_env()\n') d = msvc.get_default_env() for k, v in d.items(): env.PrependENVPath(k, v, delete_existing=True) def msvc_exists(version=None): vcs = get_installed_vcs() if version is None: return len(vcs) > 0 return version in InstalledVCMap def reset_installed_vcs(): global InstalledVCList global InstalledVCMap InstalledVCList = None InstalledVCMap = None for vc in SupportedVCList: vc.reset() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/MSCommon/arch.py0000644000175000017500000000373313606712377023266 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/MSCommon/arch.py 4369 2009/09/19 15:58:29 scons" __doc__ = """Module to define supported Windows chip architectures. """ import os class ArchDefinition: """ A class for defining architecture-specific settings and logic. """ def __init__(self, arch, synonyms=[]): self.arch = arch self.synonyms = synonyms SupportedArchitectureList = [ ArchitectureDefinition( 'x86', ['i386', 'i486', 'i586', 'i686'], ), ArchitectureDefinition( 'x86_64', ['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'], ), ArchitectureDefinition( 'ia64', ['IA64'], ), ] SupportedArchitectureMap = {} for a in SupportedArchitectureList: SupportedArchitectureMap[a.arch] = a for s in a.synonyms: SupportedArchitectureMap[s] = a pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/mslib.py0000644000175000017500000000427513606712377021771 0ustar kurtkurt"""SCons.Tool.mslib Tool-specific initialization for lib (MicroSoft library archiver). There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/mslib.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Tool.msvs import SCons.Tool.msvc import SCons.Util from MSCommon import msvs_exists, merge_default_version def generate(env): """Add Builders and construction variables for lib to an Environment.""" SCons.Tool.createStaticLibBuilder(env) # Set-up ms tools paths for default version merge_default_version(env) env['AR'] = 'lib' env['ARFLAGS'] = SCons.Util.CLVar('/nologo') env['ARCOM'] = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES')}" env['LIBPREFIX'] = '' env['LIBSUFFIX'] = '.lib' def exists(env): return msvs_exists() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/aixlink.py0000644000175000017500000000500613606712377022313 0ustar kurtkurt"""SCons.Tool.aixlink Tool-specific initialization for the IBM Visual Age linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/aixlink.py 4369 2009/09/19 15:58:29 scons" import os import os.path import SCons.Util import aixcc import link cplusplus = __import__('c++', globals(), locals(), []) def smart_linkflags(source, target, env, for_signature): if cplusplus.iscplusplus(source): build_dir = env.subst('$BUILDDIR', target=target, source=source) if build_dir: return '-qtempinc=' + os.path.join(build_dir, 'tempinc') return '' def generate(env): """ Add Builders and construction variables for Visual Age linker to an Environment. """ link.generate(env) env['SMARTLINKFLAGS'] = smart_linkflags env['LINKFLAGS'] = SCons.Util.CLVar('$SMARTLINKFLAGS') env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -qmkshrobj -qsuppress=1501-218') env['SHLIBSUFFIX'] = '.a' def exists(env): path, _cc, _shcc, version = aixcc.get_xlc(env) if path and _cc: xlc = os.path.join(path, _cc) if os.path.exists(xlc): return xlc return None # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sunf95.py0000644000175000017500000000416213606712377022007 0ustar kurtkurt"""SCons.Tool.sunf95 Tool-specific initialization for sunf95, the Sun Studio F95 compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sunf95.py 4369 2009/09/19 15:58:29 scons" import SCons.Util from FortranCommon import add_all_to_env compilers = ['sunf95', 'f95'] def generate(env): """Add Builders and construction variables for sunf95 to an Environment.""" add_all_to_env(env) fcomp = env.Detect(compilers) or 'f95' env['FORTRAN'] = fcomp env['F95'] = fcomp env['SHFORTRAN'] = '$FORTRAN' env['SHF95'] = '$F95' env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -KPIC') env['SHF95FLAGS'] = SCons.Util.CLVar('$F95FLAGS -KPIC') def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/mingw.py0000644000175000017500000001340413606712377021776 0ustar kurtkurt"""SCons.Tool.gcc Tool-specific initialization for MinGW (http://www.mingw.org/) There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/mingw.py 4369 2009/09/19 15:58:29 scons" import os import os.path import string import SCons.Action import SCons.Builder import SCons.Defaults import SCons.Tool import SCons.Util # This is what we search for to find mingw: key_program = 'mingw32-gcc' def find(env): # First search in the SCons path and then the OS path: return env.WhereIs(key_program) or SCons.Util.WhereIs(key_program) def shlib_generator(target, source, env, for_signature): cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS']) dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') if dll: cmd.extend(['-o', dll]) cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') if implib: cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature)) def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX') insert_def = env.subst("$WINDOWS_INSERT_DEF") if not insert_def in ['', '0', 0] and def_target: \ cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature)) return [cmd] def shlib_emitter(target, source, env): dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') no_import_lib = env.get('no_import_lib', 0) if not dll: raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")) if not no_import_lib and \ not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'): # Append an import library to the list of targets. target.append(env.ReplaceIxes(dll, 'SHLIBPREFIX', 'SHLIBSUFFIX', 'LIBPREFIX', 'LIBSUFFIX')) # Append a def file target if there isn't already a def file target # or a def file source. There is no option to disable def file # target emitting, because I can't figure out why someone would ever # want to turn it off. def_source = env.FindIxes(source, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX') def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX') if not def_source and not def_target: target.append(env.ReplaceIxes(dll, 'SHLIBPREFIX', 'SHLIBSUFFIX', 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')) return (target, source) shlib_action = SCons.Action.Action(shlib_generator, generator=1) res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') res_builder = SCons.Builder.Builder(action=res_action, suffix='.o', source_scanner=SCons.Tool.SourceFileScanner) SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan) def generate(env): mingw = find(env) if mingw: dir = os.path.dirname(mingw) env.PrependENVPath('PATH', dir ) # Most of mingw is the same as gcc and friends... gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas', 'm4'] for tool in gnu_tools: SCons.Tool.Tool(tool)(env) #... but a few things differ: env['CC'] = 'gcc' env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') env['CXX'] = 'g++' env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') env['SHLINKCOM'] = shlib_action env['LDMODULECOM'] = shlib_action env.Append(SHLIBEMITTER = [shlib_emitter]) env['AS'] = 'as' env['WIN32DEFPREFIX'] = '' env['WIN32DEFSUFFIX'] = '.def' env['WINDOWSDEFPREFIX'] = '${WIN32DEFPREFIX}' env['WINDOWSDEFSUFFIX'] = '${WIN32DEFSUFFIX}' env['SHOBJSUFFIX'] = '.o' env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 env['RC'] = 'windres' env['RCFLAGS'] = SCons.Util.CLVar('') env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' env['RCINCPREFIX'] = '--include-dir ' env['RCINCSUFFIX'] = '' env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET' env['BUILDERS']['RES'] = res_builder # Some setting from the platform also have to be overridden: env['OBJSUFFIX'] = '.o' env['LIBPREFIX'] = 'lib' env['LIBSUFFIX'] = '.a' def exists(env): return find(env) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/default.py0000644000175000017500000000333413606712377022302 0ustar kurtkurt"""SCons.Tool.default Initialization with a default tool list. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/default.py 4369 2009/09/19 15:58:29 scons" import SCons.Tool def generate(env): """Add default tools.""" for t in SCons.Tool.tool_list(env['PLATFORM'], env): SCons.Tool.Tool(t)(env) def exists(env): return 1 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/f77.py0000644000175000017500000000400013606712377021250 0ustar kurtkurt"""engine.SCons.Tool.f77 Tool-specific initialization for the generic Posix f77 Fortran compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/f77.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Scanner.Fortran import SCons.Tool import SCons.Util from SCons.Tool.FortranCommon import add_all_to_env, add_f77_to_env compilers = ['f77'] def generate(env): add_all_to_env(env) add_f77_to_env(env) fcomp = env.Detect(compilers) or 'f77' env['F77'] = fcomp env['SHF77'] = fcomp env['FORTRAN'] = fcomp env['SHFORTRAN'] = fcomp def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/__init__.py0000644000175000017500000006344613606712377022427 0ustar kurtkurt"""SCons.Tool SCons tool selection. This looks for modules that define a callable object that can modify a construction environment as appropriate for a given tool (or tool chain). Note that because this subsystem just *selects* a callable that can modify a construction environment, it's possible for people to define their own "tool specification" in an arbitrary callable function. No one needs to use or tie in to this subsystem in order to roll their own tool definition. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/__init__.py 4369 2009/09/19 15:58:29 scons" import imp import sys import SCons.Builder import SCons.Errors import SCons.Node.FS import SCons.Scanner import SCons.Scanner.C import SCons.Scanner.D import SCons.Scanner.LaTeX import SCons.Scanner.Prog DefaultToolpath=[] CScanner = SCons.Scanner.C.CScanner() DScanner = SCons.Scanner.D.DScanner() LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner() PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner() ProgramScanner = SCons.Scanner.Prog.ProgramScanner() SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner') CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", ".h", ".H", ".hxx", ".hpp", ".hh", ".F", ".fpp", ".FPP", ".m", ".mm", ".S", ".spp", ".SPP"] DSuffixes = ['.d'] IDLSuffixes = [".idl", ".IDL"] LaTeXSuffixes = [".tex", ".ltx", ".latex"] for suffix in CSuffixes: SourceFileScanner.add_scanner(suffix, CScanner) for suffix in DSuffixes: SourceFileScanner.add_scanner(suffix, DScanner) # FIXME: what should be done here? Two scanners scan the same extensions, # but look for different files, e.g., "picture.eps" vs. "picture.pdf". # The builders for DVI and PDF explicitly reference their scanners # I think that means this is not needed??? for suffix in LaTeXSuffixes: SourceFileScanner.add_scanner(suffix, LaTeXScanner) SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner) class Tool: def __init__(self, name, toolpath=[], **kw): self.name = name self.toolpath = toolpath + DefaultToolpath # remember these so we can merge them into the call self.init_kw = kw module = self._tool_module() self.generate = module.generate self.exists = module.exists if hasattr(module, 'options'): self.options = module.options def _tool_module(self): # TODO: Interchange zipimport with normal initilization for better error reporting oldpythonpath = sys.path sys.path = self.toolpath + sys.path try: try: file, path, desc = imp.find_module(self.name, self.toolpath) try: return imp.load_module(self.name, file, path, desc) finally: if file: file.close() except ImportError as e: if str(e)!="No module named %s"%self.name: raise SCons.Errors.EnvironmentError(e) try: import zipimport except ImportError: pass else: for aPath in self.toolpath: try: importer = zipimport.zipimporter(aPath) return importer.load_module(self.name) except ImportError as e: pass finally: sys.path = oldpythonpath full_name = 'SCons.Tool.' + self.name try: return sys.modules[full_name] except KeyError: try: smpath = sys.modules['SCons.Tool'].__path__ try: file, path, desc = imp.find_module(self.name, smpath) module = imp.load_module(full_name, file, path, desc) setattr(SCons.Tool, self.name, module) if file: file.close() return module except ImportError as e: if str(e)!="No module named %s"%self.name: raise SCons.Errors.EnvironmentError(e) try: import zipimport importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] ) module = importer.load_module(full_name) setattr(SCons.Tool, self.name, module) return module except ImportError as e: m = "No tool named '%s': %s" % (self.name, e) raise SCons.Errors.EnvironmentError(m) except ImportError as e: m = "No tool named '%s': %s" % (self.name, e) raise SCons.Errors.EnvironmentError(m) def __call__(self, env, *args, **kw): if self.init_kw is not None: # Merge call kws into init kws; # but don't bash self.init_kw. if kw is not None: call_kw = kw kw = self.init_kw.copy() kw.update(call_kw) else: kw = self.init_kw env.Append(TOOLS = [ self.name ]) if hasattr(self, 'options'): import SCons.Variables if 'options' not in env: from SCons.Script import ARGUMENTS env['options']=SCons.Variables.Variables(args=ARGUMENTS) opts=env['options'] self.options(opts) opts.Update(env) self.generate(*( env, ) + args, **kw) def __str__(self): return self.name ########################################################################## # Create common executable program / library / object builders def createProgBuilder(env): """This is a utility function that creates the Program Builder in an Environment if it is not there already. If it is already there, we return the existing one. """ try: program = env['BUILDERS']['Program'] except KeyError: import SCons.Defaults program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction, emitter = '$PROGEMITTER', prefix = '$PROGPREFIX', suffix = '$PROGSUFFIX', src_suffix = '$OBJSUFFIX', src_builder = 'Object', target_scanner = ProgramScanner) env['BUILDERS']['Program'] = program return program def createStaticLibBuilder(env): """This is a utility function that creates the StaticLibrary Builder in an Environment if it is not there already. If it is already there, we return the existing one. """ try: static_lib = env['BUILDERS']['StaticLibrary'] except KeyError: action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ] if env.Detect('ranlib'): ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR") action_list.append(ranlib_action) static_lib = SCons.Builder.Builder(action = action_list, emitter = '$LIBEMITTER', prefix = '$LIBPREFIX', suffix = '$LIBSUFFIX', src_suffix = '$OBJSUFFIX', src_builder = 'StaticObject') env['BUILDERS']['StaticLibrary'] = static_lib env['BUILDERS']['Library'] = static_lib return static_lib def createSharedLibBuilder(env): """This is a utility function that creates the SharedLibrary Builder in an Environment if it is not there already. If it is already there, we return the existing one. """ try: shared_lib = env['BUILDERS']['SharedLibrary'] except KeyError: import SCons.Defaults action_list = [ SCons.Defaults.SharedCheck, SCons.Defaults.ShLinkAction ] shared_lib = SCons.Builder.Builder(action = action_list, emitter = "$SHLIBEMITTER", prefix = '$SHLIBPREFIX', suffix = '$SHLIBSUFFIX', target_scanner = ProgramScanner, src_suffix = '$SHOBJSUFFIX', src_builder = 'SharedObject') env['BUILDERS']['SharedLibrary'] = shared_lib return shared_lib def createLoadableModuleBuilder(env): """This is a utility function that creates the LoadableModule Builder in an Environment if it is not there already. If it is already there, we return the existing one. """ try: ld_module = env['BUILDERS']['LoadableModule'] except KeyError: import SCons.Defaults action_list = [ SCons.Defaults.SharedCheck, SCons.Defaults.LdModuleLinkAction ] ld_module = SCons.Builder.Builder(action = action_list, emitter = "$LDMODULEEMITTER", prefix = '$LDMODULEPREFIX', suffix = '$LDMODULESUFFIX', target_scanner = ProgramScanner, src_suffix = '$SHOBJSUFFIX', src_builder = 'SharedObject') env['BUILDERS']['LoadableModule'] = ld_module return ld_module def createObjBuilders(env): """This is a utility function that creates the StaticObject and SharedObject Builders in an Environment if they are not there already. If they are there already, we return the existing ones. This is a separate function because soooo many Tools use this functionality. The return is a 2-tuple of (StaticObject, SharedObject) """ try: static_obj = env['BUILDERS']['StaticObject'] except KeyError: static_obj = SCons.Builder.Builder(action = {}, emitter = {}, prefix = '$OBJPREFIX', suffix = '$OBJSUFFIX', src_builder = ['CFile', 'CXXFile'], source_scanner = SourceFileScanner, single_source = 1) env['BUILDERS']['StaticObject'] = static_obj env['BUILDERS']['Object'] = static_obj try: shared_obj = env['BUILDERS']['SharedObject'] except KeyError: shared_obj = SCons.Builder.Builder(action = {}, emitter = {}, prefix = '$SHOBJPREFIX', suffix = '$SHOBJSUFFIX', src_builder = ['CFile', 'CXXFile'], source_scanner = SourceFileScanner, single_source = 1) env['BUILDERS']['SharedObject'] = shared_obj return (static_obj, shared_obj) def createCFileBuilders(env): """This is a utility function that creates the CFile/CXXFile Builders in an Environment if they are not there already. If they are there already, we return the existing ones. This is a separate function because soooo many Tools use this functionality. The return is a 2-tuple of (CFile, CXXFile) """ try: c_file = env['BUILDERS']['CFile'] except KeyError: c_file = SCons.Builder.Builder(action = {}, emitter = {}, suffix = {None:'$CFILESUFFIX'}) env['BUILDERS']['CFile'] = c_file env.SetDefault(CFILESUFFIX = '.c') try: cxx_file = env['BUILDERS']['CXXFile'] except KeyError: cxx_file = SCons.Builder.Builder(action = {}, emitter = {}, suffix = {None:'$CXXFILESUFFIX'}) env['BUILDERS']['CXXFile'] = cxx_file env.SetDefault(CXXFILESUFFIX = '.cc') return (c_file, cxx_file) ########################################################################## # Create common Java builders def CreateJarBuilder(env): try: java_jar = env['BUILDERS']['Jar'] except KeyError: fs = SCons.Node.FS.get_default_fs() jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR') java_jar = SCons.Builder.Builder(action = jar_com, suffix = '$JARSUFFIX', src_suffix = '$JAVACLASSSUFIX', src_builder = 'JavaClassFile', source_factory = fs.Entry) env['BUILDERS']['Jar'] = java_jar return java_jar def CreateJavaHBuilder(env): try: java_javah = env['BUILDERS']['JavaH'] except KeyError: fs = SCons.Node.FS.get_default_fs() java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR') java_javah = SCons.Builder.Builder(action = java_javah_com, src_suffix = '$JAVACLASSSUFFIX', target_factory = fs.Entry, source_factory = fs.File, src_builder = 'JavaClassFile') env['BUILDERS']['JavaH'] = java_javah return java_javah def CreateJavaClassFileBuilder(env): try: java_class_file = env['BUILDERS']['JavaClassFile'] except KeyError: fs = SCons.Node.FS.get_default_fs() javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') java_class_file = SCons.Builder.Builder(action = javac_com, emitter = {}, #suffix = '$JAVACLASSSUFFIX', src_suffix = '$JAVASUFFIX', src_builder = ['JavaFile'], target_factory = fs.Entry, source_factory = fs.File) env['BUILDERS']['JavaClassFile'] = java_class_file return java_class_file def CreateJavaClassDirBuilder(env): try: java_class_dir = env['BUILDERS']['JavaClassDir'] except KeyError: fs = SCons.Node.FS.get_default_fs() javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') java_class_dir = SCons.Builder.Builder(action = javac_com, emitter = {}, target_factory = fs.Dir, source_factory = fs.Dir) env['BUILDERS']['JavaClassDir'] = java_class_dir return java_class_dir def CreateJavaFileBuilder(env): try: java_file = env['BUILDERS']['JavaFile'] except KeyError: java_file = SCons.Builder.Builder(action = {}, emitter = {}, suffix = {None:'$JAVASUFFIX'}) env['BUILDERS']['JavaFile'] = java_file env['JAVASUFFIX'] = '.java' return java_file class ToolInitializerMethod: """ This is added to a construction environment in place of a method(s) normally called for a Builder (env.Object, env.StaticObject, etc.). When called, it has its associated ToolInitializer object search the specified list of tools and apply the first one that exists to the construction environment. It then calls whatever builder was (presumably) added to the construction environment in place of this particular instance. """ def __init__(self, name, initializer): """ Note: we store the tool name as __name__ so it can be used by the class that attaches this to a construction environment. """ self.__name__ = name self.initializer = initializer def get_builder(self, env): """ Returns the appropriate real Builder for this method name after having the associated ToolInitializer object apply the appropriate Tool module. """ builder = getattr(env, self.__name__) self.initializer.apply_tools(env) builder = getattr(env, self.__name__) if builder is self: # There was no Builder added, which means no valid Tool # for this name was found (or possibly there's a mismatch # between the name we were called by and the Builder name # added by the Tool module). return None self.initializer.remove_methods(env) return builder def __call__(self, env, *args, **kw): """ """ builder = self.get_builder(env) if builder is None: return [], [] return builder(*args, **kw) class ToolInitializer: """ A class for delayed initialization of Tools modules. Instances of this class associate a list of Tool modules with a list of Builder method names that will be added by those Tool modules. As part of instantiating this object for a particular construction environment, we also add the appropriate ToolInitializerMethod objects for the various Builder methods that we want to use to delay Tool searches until necessary. """ def __init__(self, env, tools, names): if not SCons.Util.is_List(tools): tools = [tools] if not SCons.Util.is_List(names): names = [names] self.env = env self.tools = tools self.names = names self.methods = {} for name in names: method = ToolInitializerMethod(name, self) self.methods[name] = method env.AddMethod(method) def remove_methods(self, env): """ Removes the methods that were added by the tool initialization so we no longer copy and re-bind them when the construction environment gets cloned. """ for method in self.methods.values(): env.RemoveMethod(method) def apply_tools(self, env): """ Searches the list of associated Tool modules for one that exists, and applies that to the construction environment. """ for t in self.tools: tool = SCons.Tool.Tool(t) if tool.exists(env): env.Tool(tool) return # If we fall through here, there was no tool module found. # This is where we can put an informative error message # about the inability to find the tool. We'll start doing # this as we cut over more pre-defined Builder+Tools to use # the ToolInitializer class. def Initializers(env): ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs']) def Install(self, *args, **kw): return self._InternalInstall(*args, **kw) def InstallAs(self, *args, **kw): return self._InternalInstallAs(*args, **kw) env.AddMethod(Install) env.AddMethod(InstallAs) def FindTool(tools, env): for tool in tools: t = Tool(tool) if t.exists(env): return tool return None def FindAllTools(tools, env): def ToolExists(tool, env=env): return Tool(tool).exists(env) return filter (ToolExists, tools) def tool_list(platform, env): other_plat_tools=[] # XXX this logic about what tool to prefer on which platform # should be moved into either the platform files or # the tool files themselves. # The search orders here are described in the man page. If you # change these search orders, update the man page as well. if str(platform) == 'win32': "prefer Microsoft tools on Windows" linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ] c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ] cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ] assemblers = ['masm', 'nasm', 'gas', '386asm' ] fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran'] ars = ['mslib', 'ar', 'tlib'] other_plat_tools=['msvs','midl'] elif str(platform) == 'os2': "prefer IBM tools on OS/2" linkers = ['ilink', 'gnulink', ]#'mslink'] c_compilers = ['icc', 'gcc',]# 'msvc', 'cc'] cxx_compilers = ['icc', 'g++',]# 'msvc', 'c++'] assemblers = ['nasm',]# 'masm', 'gas'] fortran_compilers = ['ifl', 'g77'] ars = ['ar',]# 'mslib'] elif str(platform) == 'irix': "prefer MIPSPro on IRIX" linkers = ['sgilink', 'gnulink'] c_compilers = ['sgicc', 'gcc', 'cc'] cxx_compilers = ['sgic++', 'g++', 'c++'] assemblers = ['as', 'gas'] fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] ars = ['sgiar'] elif str(platform) == 'sunos': "prefer Forte tools on SunOS" linkers = ['sunlink', 'gnulink'] c_compilers = ['suncc', 'gcc', 'cc'] cxx_compilers = ['sunc++', 'g++', 'c++'] assemblers = ['as', 'gas'] fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77', 'gfortran', 'g77', 'fortran'] ars = ['sunar'] elif str(platform) == 'hpux': "prefer aCC tools on HP-UX" linkers = ['hplink', 'gnulink'] c_compilers = ['hpcc', 'gcc', 'cc'] cxx_compilers = ['hpc++', 'g++', 'c++'] assemblers = ['as', 'gas'] fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] ars = ['ar'] elif str(platform) == 'aix': "prefer AIX Visual Age tools on AIX" linkers = ['aixlink', 'gnulink'] c_compilers = ['aixcc', 'gcc', 'cc'] cxx_compilers = ['aixc++', 'g++', 'c++'] assemblers = ['as', 'gas'] fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran'] ars = ['ar'] elif str(platform) == 'darwin': "prefer GNU tools on Mac OS X, except for some linkers and IBM tools" linkers = ['applelink', 'gnulink'] c_compilers = ['gcc', 'cc'] cxx_compilers = ['g++', 'c++'] assemblers = ['as'] fortran_compilers = ['gfortran', 'f95', 'f90', 'g77'] ars = ['ar'] else: "prefer GNU tools on all other platforms" linkers = ['gnulink', 'mslink', 'ilink'] c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++'] assemblers = ['gas', 'nasm', 'masm'] fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] ars = ['ar', 'mslib'] c_compiler = FindTool(c_compilers, env) or c_compilers[0] # XXX this logic about what tool provides what should somehow be # moved into the tool files themselves. if c_compiler and c_compiler == 'mingw': # MinGW contains a linker, C compiler, C++ compiler, # Fortran compiler, archiver and assembler: cxx_compiler = None linker = None assembler = None fortran_compiler = None ar = None else: # Don't use g++ if the C compiler has built-in C++ support: if c_compiler in ('msvc', 'intelc', 'icc'): cxx_compiler = None else: cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0] linker = FindTool(linkers, env) or linkers[0] assembler = FindTool(assemblers, env) or assemblers[0] fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0] ar = FindTool(ars, env) or ars[0] other_tools = FindAllTools(['BitKeeper', 'CVS', 'dmd', 'filesystem', 'dvipdf', 'dvips', 'gs', 'jar', 'javac', 'javah', 'latex', 'lex', 'm4', #'midl', 'msvs', 'pdflatex', 'pdftex', 'Perforce', 'RCS', 'rmic', 'rpcgen', 'SCCS', # 'Subversion', 'swig', 'tar', 'tex', 'yacc', 'zip', 'rpm', 'wix']+other_plat_tools, env) tools = ([linker, c_compiler, cxx_compiler, fortran_compiler, assembler, ar] + other_tools) return filter(lambda x: x, tools) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/gfortran.py0000644000175000017500000000436613606712377022506 0ustar kurtkurt"""SCons.Tool.gfortran Tool-specific initialization for gfortran, the GNU Fortran 95/Fortran 2003 compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/gfortran.py 4369 2009/09/19 15:58:29 scons" import SCons.Util import fortran def generate(env): """Add Builders and construction variables for gfortran to an Environment.""" fortran.generate(env) for dialect in ['F77', 'F90', 'FORTRAN', 'F95']: env['%s' % dialect] = 'gfortran' env['SH%s' % dialect] = '$%s' % dialect if env['PLATFORM'] in ['cygwin', 'win32']: env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS' % dialect) else: env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS -fPIC' % dialect) env['INC%sPREFIX' % dialect] = "-I" env['INC%sSUFFIX' % dialect] = "" def exists(env): return env.Detect('gfortran') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/dvi.py0000644000175000017500000000451413606712377021441 0ustar kurtkurt"""SCons.Tool.dvi Common DVI Builder definition for various other Tool modules that use it. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/dvi.py 4369 2009/09/19 15:58:29 scons" import SCons.Builder import SCons.Tool DVIBuilder = None def generate(env): try: env['BUILDERS']['DVI'] except KeyError: global DVIBuilder if DVIBuilder is None: # The suffix is hard-coded to '.dvi', not configurable via a # construction variable like $DVISUFFIX, because the output # file name is hard-coded within TeX. DVIBuilder = SCons.Builder.Builder(action = {}, source_scanner = SCons.Tool.LaTeXScanner, suffix = '.dvi', emitter = {}, source_ext_match = None) env['BUILDERS']['DVI'] = DVIBuilder def exists(env): # This only puts a skeleton Builder in place, so if someone # references this Tool directly, it's always "available." return 1 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/CVS.py0000644000175000017500000000530713606712377021313 0ustar kurtkurt"""SCons.Tool.CVS.py Tool-specific initialization for CVS. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/CVS.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Builder import SCons.Util def generate(env): """Add a Builder factory function and construction variables for CVS to an Environment.""" def CVSFactory(repos, module='', env=env): """ """ # fail if repos is not an absolute path name? if module != '': # Don't use os.path.join() because the name we fetch might # be across a network and must use POSIX slashes as separators. module = module + '/' env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS -d ${TARGET.dir} $CVSMODULE${TARGET.posix}' act = SCons.Action.Action('$CVSCOM', '$CVSCOMSTR') return SCons.Builder.Builder(action = act, env = env, CVSREPOSITORY = repos, CVSMODULE = module) #setattr(env, 'CVS', CVSFactory) env.CVS = CVSFactory env['CVS'] = 'cvs' env['CVSFLAGS'] = SCons.Util.CLVar('-d $CVSREPOSITORY') env['CVSCOFLAGS'] = SCons.Util.CLVar('') env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS ${TARGET.posix}' def exists(env): return env.Detect('cvs') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/fortran.py0000644000175000017500000000401013606712377022321 0ustar kurtkurt"""SCons.Tool.fortran Tool-specific initialization for a generic Posix f77/f90 Fortran compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/fortran.py 4369 2009/09/19 15:58:29 scons" import re import string import SCons.Action import SCons.Defaults import SCons.Scanner.Fortran import SCons.Tool import SCons.Util from SCons.Tool.FortranCommon import add_all_to_env, add_fortran_to_env compilers = ['f95', 'f90', 'f77'] def generate(env): add_all_to_env(env) add_fortran_to_env(env) fc = env.Detect(compilers) or 'f77' env['SHFORTRAN'] = fc env['FORTRAN'] = fc def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/hpcc.py0000644000175000017500000000347713606712377021603 0ustar kurtkurt"""SCons.Tool.hpcc Tool-specific initialization for HP aCC and cc. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/hpcc.py 4369 2009/09/19 15:58:29 scons" import SCons.Util import cc def generate(env): """Add Builders and construction variables for aCC & cc to an Environment.""" cc.generate(env) env['CXX'] = 'aCC' env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS +Z') def exists(env): return env.Detect('aCC') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/latex.py0000644000175000017500000000530013606712377021766 0ustar kurtkurt"""SCons.Tool.latex Tool-specific initialization for LaTeX. Generates .dvi files from .latex or .ltx files There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/latex.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Defaults import SCons.Scanner.LaTeX import SCons.Util import SCons.Tool import SCons.Tool.tex def LaTeXAuxFunction(target = None, source= None, env=None): result = SCons.Tool.tex.InternalLaTeXAuxAction( SCons.Tool.tex.LaTeXAction, target, source, env ) if result != 0: print(env['LATEX']," returned an error, check the log file") return result LaTeXAuxAction = SCons.Action.Action(LaTeXAuxFunction, strfunction=SCons.Tool.tex.TeXLaTeXStrFunction) def generate(env): """Add Builders and construction variables for LaTeX to an Environment.""" env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) import dvi dvi.generate(env) import pdf pdf.generate(env) bld = env['BUILDERS']['DVI'] bld.add_action('.ltx', LaTeXAuxAction) bld.add_action('.latex', LaTeXAuxAction) bld.add_emitter('.ltx', SCons.Tool.tex.tex_eps_emitter) bld.add_emitter('.latex', SCons.Tool.tex.tex_eps_emitter) SCons.Tool.tex.generate_common(env) def exists(env): return env.Detect('latex') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/tlib.py0000644000175000017500000000352413606712377021611 0ustar kurtkurt"""SCons.Tool.tlib XXX """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/tlib.py 4369 2009/09/19 15:58:29 scons" import SCons.Tool import SCons.Tool.bcc32 import SCons.Util def generate(env): SCons.Tool.bcc32.findIt('tlib', env) """Add Builders and construction variables for ar to an Environment.""" SCons.Tool.createStaticLibBuilder(env) env['AR'] = 'tlib' env['ARFLAGS'] = SCons.Util.CLVar('') env['ARCOM'] = '$AR $TARGET $ARFLAGS /a $SOURCES' env['LIBPREFIX'] = '' env['LIBSUFFIX'] = '.lib' def exists(env): return SCons.Tool.bcc32.findIt('tlib', env) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/qt.py0000644000175000017500000003174013606712377021304 0ustar kurtkurt """SCons.Tool.qt Tool-specific initialization for Qt. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/qt.py 4369 2009/09/19 15:58:29 scons" import os.path import re import SCons.Action import SCons.Builder import SCons.Defaults import SCons.Scanner import SCons.Tool import SCons.Util class ToolQtWarning(SCons.Warnings.Warning): pass class GeneratedMocFileNotIncluded(ToolQtWarning): pass class QtdirNotFound(ToolQtWarning): pass SCons.Warnings.enableWarningClass(ToolQtWarning) header_extensions = [".h", ".hxx", ".hpp", ".hh"] if SCons.Util.case_sensitive_suffixes('.h', '.H'): header_extensions.append('.H') cplusplus = __import__('c++', globals(), locals(), []) cxx_suffixes = cplusplus.CXXSuffixes def checkMocIncluded(target, source, env): moc = target[0] cpp = source[0] # looks like cpp.includes is cleared before the build stage :-( # not really sure about the path transformations (moc.cwd? cpp.cwd?) :-/ path = SCons.Defaults.CScan.path(env, moc.cwd) includes = SCons.Defaults.CScan(cpp, env, path) if not moc in includes: SCons.Warnings.warn( GeneratedMocFileNotIncluded, "Generated moc file '%s' is not included by '%s'" % (str(moc), str(cpp))) def find_file(filename, paths, node_factory): for dir in paths: node = node_factory(filename, dir) if node.rexists(): return node return None class _Automoc: """ Callable class, which works as an emitter for Programs, SharedLibraries and StaticLibraries. """ def __init__(self, objBuilderName): self.objBuilderName = objBuilderName def __call__(self, target, source, env): """ Smart autoscan function. Gets the list of objects for the Program or Lib. Adds objects and builders for the special qt files. """ try: if int(env.subst('$QT_AUTOSCAN')) == 0: return target, source except ValueError: pass try: debug = int(env.subst('$QT_DEBUG')) except ValueError: debug = 0 # some shortcuts used in the scanner splitext = SCons.Util.splitext objBuilder = getattr(env, self.objBuilderName) # some regular expressions: # Q_OBJECT detection q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]') # cxx and c comment 'eater' #comment = re.compile(r'(//.*)|(/\*(([^*])|(\*[^/]))*\*/)') # CW: something must be wrong with the regexp. See also bug #998222 # CURRENTLY THERE IS NO TEST CASE FOR THAT # The following is kind of hacky to get builders working properly (FIXME) objBuilderEnv = objBuilder.env objBuilder.env = env mocBuilderEnv = env.Moc.env env.Moc.env = env # make a deep copy for the result; MocH objects will be appended out_sources = source[:] for obj in source: if not obj.has_builder(): # binary obj file provided if debug: print("scons: qt: '%s' seems to be a binary. Discarded." % str(obj)) continue cpp = obj.sources[0] if not splitext(str(cpp))[1] in cxx_suffixes: if debug: print("scons: qt: '%s' is no cxx file. Discarded." % str(cpp)) # c or fortran source continue #cpp_contents = comment.sub('', cpp.get_text_contents()) cpp_contents = cpp.get_text_contents() h=None for h_ext in header_extensions: # try to find the header file in the corresponding source # directory hname = splitext(cpp.name)[0] + h_ext h = find_file(hname, (cpp.get_dir(),), env.File) if h: if debug: print("scons: qt: Scanning '%s' (header of '%s')" % (str(h), str(cpp))) #h_contents = comment.sub('', h.get_text_contents()) h_contents = h.get_text_contents() break if not h and debug: print("scons: qt: no header for '%s'." % (str(cpp))) if h and q_object_search.search(h_contents): # h file with the Q_OBJECT macro found -> add moc_cpp moc_cpp = env.Moc(h) moc_o = objBuilder(moc_cpp) out_sources.append(moc_o) #moc_cpp.target_scanner = SCons.Defaults.CScan if debug: print("scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(moc_cpp))) if cpp and q_object_search.search(cpp_contents): # cpp file with Q_OBJECT macro found -> add moc # (to be included in cpp) moc = env.Moc(cpp) env.Ignore(moc, moc) if debug: print("scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))) #moc.source_scanner = SCons.Defaults.CScan # restore the original env attributes (FIXME) objBuilder.env = objBuilderEnv env.Moc.env = mocBuilderEnv return (target, out_sources) AutomocShared = _Automoc('SharedObject') AutomocStatic = _Automoc('StaticObject') def _detect(env): """Not really safe, but fast method to detect the QT library""" QTDIR = None if not QTDIR: QTDIR = env.get('QTDIR',None) if not QTDIR: QTDIR = os.environ.get('QTDIR',None) if not QTDIR: moc = env.WhereIs('moc') if moc: QTDIR = os.path.dirname(os.path.dirname(moc)) SCons.Warnings.warn( QtdirNotFound, "Could not detect qt, using moc executable as a hint (QTDIR=%s)" % QTDIR) else: QTDIR = None SCons.Warnings.warn( QtdirNotFound, "Could not detect qt, using empty QTDIR") return QTDIR def uicEmitter(target, source, env): adjustixes = SCons.Util.adjustixes bs = SCons.Util.splitext(str(source[0].name))[0] bs = os.path.join(str(target[0].get_dir()),bs) # first target (header) is automatically added by builder if len(target) < 2: # second target is implementation target.append(adjustixes(bs, env.subst('$QT_UICIMPLPREFIX'), env.subst('$QT_UICIMPLSUFFIX'))) if len(target) < 3: # third target is moc file target.append(adjustixes(bs, env.subst('$QT_MOCHPREFIX'), env.subst('$QT_MOCHSUFFIX'))) return target, source def uicScannerFunc(node, env, path): lookout = [] lookout.extend(env['CPPPATH']) lookout.append(str(node.rfile().dir)) includes = re.findall("(.*?)", node.get_text_contents()) result = [] for incFile in includes: dep = env.FindFile(incFile,lookout) if dep: result.append(dep) return result uicScanner = SCons.Scanner.Base(uicScannerFunc, name = "UicScanner", node_class = SCons.Node.FS.File, node_factory = SCons.Node.FS.File, recursive = 0) def generate(env): """Add Builders and construction variables for qt to an Environment.""" CLVar = SCons.Util.CLVar Action = SCons.Action.Action Builder = SCons.Builder.Builder env.SetDefault(QTDIR = _detect(env), QT_BINPATH = os.path.join('$QTDIR', 'bin'), QT_CPPPATH = os.path.join('$QTDIR', 'include'), QT_LIBPATH = os.path.join('$QTDIR', 'lib'), QT_MOC = os.path.join('$QT_BINPATH','moc'), QT_UIC = os.path.join('$QT_BINPATH','uic'), QT_LIB = 'qt', # may be set to qt-mt QT_AUTOSCAN = 1, # scan for moc'able sources # Some QT specific flags. I don't expect someone wants to # manipulate those ... QT_UICIMPLFLAGS = CLVar(''), QT_UICDECLFLAGS = CLVar(''), QT_MOCFROMHFLAGS = CLVar(''), QT_MOCFROMCXXFLAGS = CLVar('-i'), # suffixes/prefixes for the headers / sources to generate QT_UICDECLPREFIX = '', QT_UICDECLSUFFIX = '.h', QT_UICIMPLPREFIX = 'uic_', QT_UICIMPLSUFFIX = '$CXXFILESUFFIX', QT_MOCHPREFIX = 'moc_', QT_MOCHSUFFIX = '$CXXFILESUFFIX', QT_MOCCXXPREFIX = '', QT_MOCCXXSUFFIX = '.moc', QT_UISUFFIX = '.ui', # Commands for the qt support ... # command to generate header, implementation and moc-file # from a .ui file QT_UICCOM = [ CLVar('$QT_UIC $QT_UICDECLFLAGS -o ${TARGETS[0]} $SOURCE'), CLVar('$QT_UIC $QT_UICIMPLFLAGS -impl ${TARGETS[0].file} ' '-o ${TARGETS[1]} $SOURCE'), CLVar('$QT_MOC $QT_MOCFROMHFLAGS -o ${TARGETS[2]} ${TARGETS[0]}')], # command to generate meta object information for a class # declarated in a header QT_MOCFROMHCOM = ( '$QT_MOC $QT_MOCFROMHFLAGS -o ${TARGETS[0]} $SOURCE'), # command to generate meta object information for a class # declarated in a cpp file QT_MOCFROMCXXCOM = [ CLVar('$QT_MOC $QT_MOCFROMCXXFLAGS -o ${TARGETS[0]} $SOURCE'), Action(checkMocIncluded,None)]) # ... and the corresponding builders uicBld = Builder(action=SCons.Action.Action('$QT_UICCOM', '$QT_UICCOMSTR'), emitter=uicEmitter, src_suffix='$QT_UISUFFIX', suffix='$QT_UICDECLSUFFIX', prefix='$QT_UICDECLPREFIX', source_scanner=uicScanner) mocBld = Builder(action={}, prefix={}, suffix={}) for h in header_extensions: act = SCons.Action.Action('$QT_MOCFROMHCOM', '$QT_MOCFROMHCOMSTR') mocBld.add_action(h, act) mocBld.prefix[h] = '$QT_MOCHPREFIX' mocBld.suffix[h] = '$QT_MOCHSUFFIX' for cxx in cxx_suffixes: act = SCons.Action.Action('$QT_MOCFROMCXXCOM', '$QT_MOCFROMCXXCOMSTR') mocBld.add_action(cxx, act) mocBld.prefix[cxx] = '$QT_MOCCXXPREFIX' mocBld.suffix[cxx] = '$QT_MOCCXXSUFFIX' # register the builders env['BUILDERS']['Uic'] = uicBld env['BUILDERS']['Moc'] = mocBld static_obj, shared_obj = SCons.Tool.createObjBuilders(env) static_obj.add_src_builder('Uic') shared_obj.add_src_builder('Uic') # We use the emitters of Program / StaticLibrary / SharedLibrary # to scan for moc'able files # We can't refer to the builders directly, we have to fetch them # as Environment attributes because that sets them up to be called # correctly later by our emitter. env.AppendUnique(PROGEMITTER =[AutomocStatic], SHLIBEMITTER=[AutomocShared], LIBEMITTER =[AutomocStatic], # Of course, we need to link against the qt libraries CPPPATH=["$QT_CPPPATH"], LIBPATH=["$QT_LIBPATH"], LIBS=['$QT_LIB']) def exists(env): return _detect(env) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/javac.py0000644000175000017500000002070713606712377021745 0ustar kurtkurt"""SCons.Tool.javac Tool-specific initialization for javac. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/javac.py 4369 2009/09/19 15:58:29 scons" import os import os.path import string import SCons.Action import SCons.Builder from SCons.Node.FS import _my_normcase from SCons.Tool.JavaCommon import parse_java_file import SCons.Util def classname(path): """Turn a string (path name) into a Java class name.""" return string.replace(os.path.normpath(path), os.sep, '.') def emit_java_classes(target, source, env): """Create and return lists of source java files and their corresponding target class files. """ java_suffix = env.get('JAVASUFFIX', '.java') class_suffix = env.get('JAVACLASSSUFFIX', '.class') target[0].must_be_same(SCons.Node.FS.Dir) classdir = target[0] s = source[0].rentry().disambiguate() if isinstance(s, SCons.Node.FS.File): sourcedir = s.dir.rdir() elif isinstance(s, SCons.Node.FS.Dir): sourcedir = s.rdir() else: raise SCons.Errors.UserError("Java source must be File or Dir, not '%s'" % s.__class__) slist = [] js = _my_normcase(java_suffix) find_java = lambda n, js=js, ljs=len(js): _my_normcase(n[-ljs:]) == js for entry in source: entry = entry.rentry().disambiguate() if isinstance(entry, SCons.Node.FS.File): slist.append(entry) elif isinstance(entry, SCons.Node.FS.Dir): result = SCons.Util.OrderedDict() def visit(arg, dirname, names, fj=find_java, dirnode=entry.rdir()): java_files = sorted(filter(fj, names)) # The on-disk entries come back in arbitrary order. Sort # them so our target and source lists are determinate. mydir = dirnode.Dir(dirname) java_paths = map(lambda f, d=mydir: d.File(f), java_files) for jp in java_paths: arg[jp] = True os.path.walk(entry.rdir().get_abspath(), visit, result) entry.walk(visit, result) slist.extend(result.keys()) else: raise SCons.Errors.UserError("Java source must be File or Dir, not '%s'" % entry.__class__) version = env.get('JAVAVERSION', '1.4') full_tlist = [] for f in slist: tlist = [] source_file_based = True pkg_dir = None if not f.is_derived(): pkg_dir, classes = parse_java_file(f.rfile().get_abspath(), version) if classes: source_file_based = False if pkg_dir: d = target[0].Dir(pkg_dir) p = pkg_dir + os.sep else: d = target[0] p = '' for c in classes: t = d.File(c + class_suffix) t.attributes.java_classdir = classdir t.attributes.java_sourcedir = sourcedir t.attributes.java_classname = classname(p + c) tlist.append(t) if source_file_based: base = f.name[:-len(java_suffix)] if pkg_dir: t = target[0].Dir(pkg_dir).File(base + class_suffix) else: t = target[0].File(base + class_suffix) t.attributes.java_classdir = classdir t.attributes.java_sourcedir = f.dir t.attributes.java_classname = classname(base) tlist.append(t) for t in tlist: t.set_specific_source([f]) full_tlist.extend(tlist) return full_tlist, slist JavaAction = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') JavaBuilder = SCons.Builder.Builder(action = JavaAction, emitter = emit_java_classes, target_factory = SCons.Node.FS.Entry, source_factory = SCons.Node.FS.Entry) class pathopt: """ Callable object for generating javac-style path options from a construction variable (e.g. -classpath, -sourcepath). """ def __init__(self, opt, var, default=None): self.opt = opt self.var = var self.default = default def __call__(self, target, source, env, for_signature): path = env[self.var] if path and not SCons.Util.is_List(path): path = [path] if self.default: path = path + [ env[self.default] ] if path: return [self.opt, string.join(path, os.pathsep)] #return self.opt + " " + string.join(path, os.pathsep) else: return [] #return "" def Java(env, target, source, *args, **kw): """ A pseudo-Builder wrapper around the separate JavaClass{File,Dir} Builders. """ if not SCons.Util.is_List(target): target = [target] if not SCons.Util.is_List(source): source = [source] # Pad the target list with repetitions of the last element in the # list so we have a target for every source element. target = target + ([target[-1]] * (len(source) - len(target))) java_suffix = env.subst('$JAVASUFFIX') result = [] for t, s in zip(target, source): if isinstance(s, SCons.Node.FS.Base): if isinstance(s, SCons.Node.FS.File): b = env.JavaClassFile else: b = env.JavaClassDir else: if os.path.isfile(s): b = env.JavaClassFile elif os.path.isdir(s): b = env.JavaClassDir elif s[-len(java_suffix):] == java_suffix: b = env.JavaClassFile else: b = env.JavaClassDir result.extend(b(*(t, s) + args, **kw)) return result def generate(env): """Add Builders and construction variables for javac to an Environment.""" java_file = SCons.Tool.CreateJavaFileBuilder(env) java_class = SCons.Tool.CreateJavaClassFileBuilder(env) java_class_dir = SCons.Tool.CreateJavaClassDirBuilder(env) java_class.add_emitter(None, emit_java_classes) java_class.add_emitter(env.subst('$JAVASUFFIX'), emit_java_classes) java_class_dir.emitter = emit_java_classes env.AddMethod(Java) env['JAVAC'] = 'javac' env['JAVACFLAGS'] = SCons.Util.CLVar('') env['JAVABOOTCLASSPATH'] = [] env['JAVACLASSPATH'] = [] env['JAVASOURCEPATH'] = [] env['_javapathopt'] = pathopt env['_JAVABOOTCLASSPATH'] = '${_javapathopt("-bootclasspath", "JAVABOOTCLASSPATH")} ' env['_JAVACLASSPATH'] = '${_javapathopt("-classpath", "JAVACLASSPATH")} ' env['_JAVASOURCEPATH'] = '${_javapathopt("-sourcepath", "JAVASOURCEPATH", "_JAVASOURCEPATHDEFAULT")} ' env['_JAVASOURCEPATHDEFAULT'] = '${TARGET.attributes.java_sourcedir}' env['_JAVACCOM'] = '$JAVAC $JAVACFLAGS $_JAVABOOTCLASSPATH $_JAVACLASSPATH -d ${TARGET.attributes.java_classdir} $_JAVASOURCEPATH $SOURCES' env['JAVACCOM'] = "${TEMPFILE('$_JAVACCOM')}" env['JAVACLASSSUFFIX'] = '.class' env['JAVASUFFIX'] = '.java' def exists(env): return 1 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/ifl.py0000644000175000017500000000536213606712377021433 0ustar kurtkurt"""SCons.Tool.ifl Tool-specific initialization for the Intel Fortran compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/ifl.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults from SCons.Scanner.Fortran import FortranScan from FortranCommon import add_all_to_env def generate(env): """Add Builders and construction variables for ifl to an Environment.""" fscan = FortranScan("FORTRANPATH") SCons.Tool.SourceFileScanner.add_scanner('.i', fscan) SCons.Tool.SourceFileScanner.add_scanner('.i90', fscan) if 'FORTRANFILESUFFIXES' not in env: env['FORTRANFILESUFFIXES'] = ['.i'] else: env['FORTRANFILESUFFIXES'].append('.i') if 'F90FILESUFFIXES' not in env: env['F90FILESUFFIXES'] = ['.i90'] else: env['F90FILESUFFIXES'].append('.i90') add_all_to_env(env) env['FORTRAN'] = 'ifl' env['SHFORTRAN'] = '$FORTRAN' env['FORTRANCOM'] = '$FORTRAN $FORTRANFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' env['FORTRANPPCOM'] = '$FORTRAN $FORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' env['SHFORTRANCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' env['SHFORTRANPPCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' def exists(env): return env.Detect('ifl') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/tar.py0000644000175000017500000000472613606712377021452 0ustar kurtkurt"""SCons.Tool.tar Tool-specific initialization for tar. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/tar.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Builder import SCons.Defaults import SCons.Node.FS import SCons.Util tars = ['tar', 'gtar'] TarAction = SCons.Action.Action('$TARCOM', '$TARCOMSTR') TarBuilder = SCons.Builder.Builder(action = TarAction, source_factory = SCons.Node.FS.Entry, source_scanner = SCons.Defaults.DirScanner, suffix = '$TARSUFFIX', multi = 1) def generate(env): """Add Builders and construction variables for tar to an Environment.""" try: bld = env['BUILDERS']['Tar'] except KeyError: bld = TarBuilder env['BUILDERS']['Tar'] = bld env['TAR'] = env.Detect(tars) or 'gtar' env['TARFLAGS'] = SCons.Util.CLVar('-c') env['TARCOM'] = '$TAR $TARFLAGS -f $TARGET $SOURCES' env['TARSUFFIX'] = '.tar' def exists(env): return env.Detect(tars) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/0000755000175000017500000000000013606712377022225 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/ipk.py0000644000175000017500000001425113606712377023365 0ustar kurtkurt"""SCons.Tool.Packaging.ipk """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/ipk.py 4369 2009/09/19 15:58:29 scons" import SCons.Builder import SCons.Node.FS import os from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot def package(env, target, source, PACKAGEROOT, NAME, VERSION, DESCRIPTION, SUMMARY, X_IPK_PRIORITY, X_IPK_SECTION, SOURCE_URL, X_IPK_MAINTAINER, X_IPK_DEPENDS, **kw): """ this function prepares the packageroot directory for packaging with the ipkg builder. """ SCons.Tool.Tool('ipkg').generate(env) # setup the Ipkg builder bld = env['BUILDERS']['Ipkg'] target, source = stripinstallbuilder(target, source, env) target, source = putintopackageroot(target, source, env, PACKAGEROOT) # This should be overridable from the construction environment, # which it is by using ARCHITECTURE=. # Guessing based on what os.uname() returns at least allows it # to work for both i386 and x86_64 Linux systems. archmap = { 'i686' : 'i386', 'i586' : 'i386', 'i486' : 'i386', } buildarchitecture = os.uname()[4] buildarchitecture = archmap.get(buildarchitecture, buildarchitecture) if 'ARCHITECTURE' in kw: buildarchitecture = kw['ARCHITECTURE'] # setup the kw to contain the mandatory arguments to this fucntion. # do this before calling any builder or setup function loc=locals() del loc['kw'] kw.update(loc) del kw['source'], kw['target'], kw['env'] # generate the specfile specfile = gen_ipk_dir(PACKAGEROOT, source, env, kw) # override the default target. if str(target[0])=="%s-%s"%(NAME, VERSION): target=[ "%s_%s_%s.ipk"%(NAME, VERSION, buildarchitecture) ] # now apply the Ipkg builder return bld(*[env, target, specfile], **kw) def gen_ipk_dir(proot, source, env, kw): # make sure the packageroot is a Dir object. if SCons.Util.is_String(proot): proot=env.Dir(proot) # create the specfile builder s_bld=SCons.Builder.Builder( action = build_specfiles, ) # create the specfile targets spec_target=[] control=proot.Dir('CONTROL') spec_target.append(control.File('control')) spec_target.append(control.File('conffiles')) spec_target.append(control.File('postrm')) spec_target.append(control.File('prerm')) spec_target.append(control.File('postinst')) spec_target.append(control.File('preinst')) # apply the builder to the specfile targets s_bld(*[env, spec_target, source], **kw) # the packageroot directory does now contain the specfiles. return proot def build_specfiles(source, target, env): """ filter the targets for the needed files and use the variables in env to create the specfile. """ # # At first we care for the CONTROL/control file, which is the main file for ipk. # # For this we need to open multiple files in random order, so we store into # a dict so they can be easily accessed. # # opened_files={} def open_file(needle, haystack): try: return opened_files[needle] except KeyError: file=filter(lambda x: x.get_path().rfind(needle)!=-1, haystack)[0] opened_files[needle]=open(file.abspath, 'w') return opened_files[needle] control_file=open_file('control', target) if 'X_IPK_DESCRIPTION' not in env: env['X_IPK_DESCRIPTION']="%s\n %s"%(env['SUMMARY'], env['DESCRIPTION'].replace('\n', '\n ')) content = """ Package: $NAME Version: $VERSION Priority: $X_IPK_PRIORITY Section: $X_IPK_SECTION Source: $SOURCE_URL Architecture: $ARCHITECTURE Maintainer: $X_IPK_MAINTAINER Depends: $X_IPK_DEPENDS Description: $X_IPK_DESCRIPTION """ control_file.write(env.subst(content)) # # now handle the various other files, which purpose it is to set post-, # pre-scripts and mark files as config files. # # We do so by filtering the source files for files which are marked with # the "config" tag and afterwards we do the same for x_ipk_postrm, # x_ipk_prerm, x_ipk_postinst and x_ipk_preinst tags. # # The first one will write the name of the file into the file # CONTROL/configfiles, the latter add the content of the x_ipk_* variable # into the same named file. # for f in [x for x in source if 'PACKAGING_CONFIG' in dir(x)]: config=open_file('conffiles') config.write(f.PACKAGING_INSTALL_LOCATION) config.write('\n') for str in 'POSTRM PRERM POSTINST PREINST'.split(): name="PACKAGING_X_IPK_%s"%str for f in [x for x in source if name in dir(x)]: file=open_file(name) file.write(env[str]) # # close all opened files for f in opened_files.values(): f.close() # call a user specified function if 'CHANGE_SPECFILE' in env: content += env['CHANGE_SPECFILE'](target) return 0 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/src_zip.py0000644000175000017500000000326213606712377024253 0ustar kurtkurt"""SCons.Tool.Packaging.zip The zip SRC packager. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/src_zip.py 4369 2009/09/19 15:58:29 scons" from SCons.Tool.packaging import putintopackageroot def package(env, target, source, PACKAGEROOT, **kw): bld = env['BUILDERS']['Zip'] bld.set_suffix('.zip') target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) return bld(env, target, source) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/targz.py0000644000175000017500000000340013606712377023723 0ustar kurtkurt"""SCons.Tool.Packaging.targz The targz SRC packager. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/targz.py 4369 2009/09/19 15:58:29 scons" from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot def package(env, target, source, PACKAGEROOT, **kw): bld = env['BUILDERS']['Tar'] bld.set_suffix('.tar.gz') target, source = stripinstallbuilder(target, source, env) target, source = putintopackageroot(target, source, env, PACKAGEROOT) return bld(env, target, source, TARFLAGS='-zc') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/__init__.py0000644000175000017500000002510313606712377024337 0ustar kurtkurt"""SCons.Tool.Packaging SCons Packaging Tool. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/__init__.py 4369 2009/09/19 15:58:29 scons" import SCons.Environment from SCons.Variables import * from SCons.Errors import * from SCons.Util import is_List, make_path_relative from SCons.Warnings import warn, Warning import os, imp import SCons.Defaults __all__ = [ 'src_targz', 'src_tarbz2', 'src_zip', 'tarbz2', 'targz', 'zip', 'rpm', 'msi', 'ipk' ] # # Utility and Builder function # def Tag(env, target, source, *more_tags, **kw_tags): """ Tag a file with the given arguments, just sets the accordingly named attribute on the file object. TODO: FIXME """ if not target: target=source first_tag=None else: first_tag=source if first_tag: kw_tags[first_tag[0]] = '' if len(kw_tags) == 0 and len(more_tags) == 0: raise UserError("No tags given.") # XXX: sanity checks for x in more_tags: kw_tags[x] = '' if not SCons.Util.is_List(target): target=[target] else: # hmm, sometimes the target list, is a list of a list # make sure it is flattened prior to processing. # TODO: perhaps some bug ?!? target=env.Flatten(target) for t in target: for (k,v) in kw_tags.items(): # all file tags have to start with PACKAGING_, so we can later # differentiate between "normal" object attributes and the # packaging attributes. As the user should not be bothered with # that, the prefix will be added here if missing. #if not k.startswith('PACKAGING_'): if k[:10] != 'PACKAGING_': k='PACKAGING_'+k setattr(t, k, v) def Package(env, target=None, source=None, **kw): """ Entry point for the package tool. """ # check if we need to find the source files ourself if not source: source = env.FindInstalledFiles() if len(source)==0: raise UserError("No source for Package() given") # decide which types of packages shall be built. Can be defined through # four mechanisms: command line argument, keyword argument, # environment argument and default selection( zip or tar.gz ) in that # order. try: kw['PACKAGETYPE']=env['PACKAGETYPE'] except KeyError: pass if not kw.get('PACKAGETYPE'): from SCons.Script import GetOption kw['PACKAGETYPE'] = GetOption('package_type') if kw['PACKAGETYPE'] == None: if 'Tar' in env['BUILDERS']: kw['PACKAGETYPE']='targz' elif 'Zip' in env['BUILDERS']: kw['PACKAGETYPE']='zip' else: raise UserError("No type for Package() given") PACKAGETYPE=kw['PACKAGETYPE'] if not is_List(PACKAGETYPE): PACKAGETYPE=string.split(PACKAGETYPE, ',') # load the needed packagers. def load_packager(type): try: file,path,desc=imp.find_module(type, __path__) return imp.load_module(type, file, path, desc) except ImportError as e: raise EnvironmentError("packager %s not available: %s"%(type,str(e))) packagers=map(load_packager, PACKAGETYPE) # set up targets and the PACKAGEROOT try: # fill up the target list with a default target name until the PACKAGETYPE # list is of the same size as the target list. if not target: target = [] size_diff = len(PACKAGETYPE)-len(target) default_name = "%(NAME)s-%(VERSION)s" if size_diff>0: default_target = default_name%kw target.extend( [default_target]*size_diff ) if 'PACKAGEROOT' not in kw: kw['PACKAGEROOT'] = default_name%kw except KeyError as e: raise SCons.Errors.UserError( "Missing Packagetag '%s'"%e.args[0] ) # setup the source files source=env.arg2nodes(source, env.fs.Entry) # call the packager to setup the dependencies. targets=[] try: for packager in packagers: t=[target.pop(0)] t=packager.package(*[env,t,source], **kw) targets.extend(t) assert( len(target) == 0 ) except KeyError as e: raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ % (e.args[0],packager.__name__) ) except TypeError as e: # this exception means that a needed argument for the packager is # missing. As our packagers get their "tags" as named function # arguments we need to find out which one is missing. from inspect import getargspec args,varargs,varkw,defaults=getargspec(packager.package) if defaults!=None: args=args[:-len(defaults)] # throw away arguments with default values args.remove('env') args.remove('target') args.remove('source') # now remove any args for which we have a value in kw. #args=[x for x in args if not kw.has_key(x)] args=filter(lambda x, kw=kw: x not in kw, args) if len(args)==0: raise # must be a different error, so reraise elif len(args)==1: raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ % (args[0],packager.__name__) ) else: raise SCons.Errors.UserError( "Missing Packagetags '%s' for %s packager"\ % (", ".join(args),packager.__name__) ) target=env.arg2nodes(target, env.fs.Entry) targets.extend(env.Alias( 'package', targets )) return targets # # SCons tool initialization functions # added = None def generate(env): from SCons.Script import AddOption global added if not added: added = 1 AddOption('--package-type', dest='package_type', default=None, type="string", action="store", help='The type of package to create.') try: env['BUILDERS']['Package'] env['BUILDERS']['Tag'] except KeyError: env['BUILDERS']['Package'] = Package env['BUILDERS']['Tag'] = Tag def exists(env): return 1 # XXX def options(opts): opts.AddVariables( EnumVariable( 'PACKAGETYPE', 'the type of package to create.', None, allowed_values=map( str, __all__ ), ignorecase=2 ) ) # # Internal utility functions # def copy_attr(f1, f2): """ copies the special packaging file attributes from f1 to f2. """ #pattrs = [x for x in dir(f1) if not hasattr(f2, x) and\ # x.startswith('PACKAGING_')] copyit = lambda x, f2=f2: not hasattr(f2, x) and x[:10] == 'PACKAGING_' pattrs = filter(copyit, dir(f1)) for attr in pattrs: setattr(f2, attr, getattr(f1, attr)) def putintopackageroot(target, source, env, pkgroot, honor_install_location=1): """ Uses the CopyAs builder to copy all source files to the directory given in pkgroot. If honor_install_location is set and the copied source file has an PACKAGING_INSTALL_LOCATION attribute, the PACKAGING_INSTALL_LOCATION is used as the new name of the source file under pkgroot. The source file will not be copied if it is already under the the pkgroot directory. All attributes of the source file will be copied to the new file. """ # make sure the packageroot is a Dir object. if SCons.Util.is_String(pkgroot): pkgroot=env.Dir(pkgroot) if not SCons.Util.is_List(source): source=[source] new_source = [] for file in source: if SCons.Util.is_String(file): file = env.File(file) if file.is_under(pkgroot): new_source.append(file) else: if hasattr(file, 'PACKAGING_INSTALL_LOCATION') and\ honor_install_location: new_name=make_path_relative(file.PACKAGING_INSTALL_LOCATION) else: new_name=make_path_relative(file.get_path()) new_file=pkgroot.File(new_name) new_file=env.CopyAs(new_file, file)[0] copy_attr(file, new_file) new_source.append(new_file) return (target, new_source) def stripinstallbuilder(target, source, env): """ strips the install builder action from the source list and stores the final installation location as the "PACKAGING_INSTALL_LOCATION" of the source of the source file. This effectively removes the final installed files from the source list while remembering the installation location. It also warns about files which have no install builder attached. """ def has_no_install_location(file): return not (file.has_builder() and\ hasattr(file.builder, 'name') and\ (file.builder.name=="InstallBuilder" or\ file.builder.name=="InstallAsBuilder")) if len(filter(has_no_install_location, source)): warn(Warning, "there are files to package which have no\ InstallBuilder attached, this might lead to irreproducible packages") n_source=[] for s in source: if has_no_install_location(s): n_source.append(s) else: for ss in s.sources: n_source.append(ss) copy_attr(s, ss) setattr(ss, 'PACKAGING_INSTALL_LOCATION', s.get_path()) return (target, n_source) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/src_targz.py0000644000175000017500000000331213606712377024574 0ustar kurtkurt"""SCons.Tool.Packaging.targz The targz SRC packager. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/src_targz.py 4369 2009/09/19 15:58:29 scons" from SCons.Tool.packaging import putintopackageroot def package(env, target, source, PACKAGEROOT, **kw): bld = env['BUILDERS']['Tar'] bld.set_suffix('.tar.gz') target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) return bld(env, target, source, TARFLAGS='-zc') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/src_tarbz2.py0000644000175000017500000000331713606712377024656 0ustar kurtkurt"""SCons.Tool.Packaging.tarbz2 The tarbz2 SRC packager. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/src_tarbz2.py 4369 2009/09/19 15:58:29 scons" from SCons.Tool.packaging import putintopackageroot def package(env, target, source, PACKAGEROOT, **kw): bld = env['BUILDERS']['Tar'] bld.set_suffix('.tar.bz2') target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0) return bld(env, target, source, TARFLAGS='-jc') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/rpm.py0000644000175000017500000003237213606712377023404 0ustar kurtkurt"""SCons.Tool.Packaging.rpm The rpm packager. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/rpm.py 4369 2009/09/19 15:58:29 scons" import os import string import SCons.Builder from SCons.Environment import OverrideEnvironment from SCons.Tool.packaging import stripinstallbuilder, src_targz from SCons.Errors import UserError def package(env, target, source, PACKAGEROOT, NAME, VERSION, PACKAGEVERSION, DESCRIPTION, SUMMARY, X_RPM_GROUP, LICENSE, **kw): # initialize the rpm tool SCons.Tool.Tool('rpm').generate(env) bld = env['BUILDERS']['Rpm'] # Generate a UserError whenever the target name has been set explicitly, # since rpm does not allow for controlling it. This is detected by # checking if the target has been set to the default by the Package() # Environment function. if str(target[0])!="%s-%s"%(NAME, VERSION): raise UserError( "Setting target is not supported for rpm." ) else: # This should be overridable from the construction environment, # which it is by using ARCHITECTURE=. # Guessing based on what os.uname() returns at least allows it # to work for both i386 and x86_64 Linux systems. archmap = { 'i686' : 'i386', 'i586' : 'i386', 'i486' : 'i386', } buildarchitecture = os.uname()[4] buildarchitecture = archmap.get(buildarchitecture, buildarchitecture) if 'ARCHITECTURE' in kw: buildarchitecture = kw['ARCHITECTURE'] fmt = '%s-%s-%s.%s.rpm' srcrpm = fmt % (NAME, VERSION, PACKAGEVERSION, 'src') binrpm = fmt % (NAME, VERSION, PACKAGEVERSION, buildarchitecture) target = [ srcrpm, binrpm ] # get the correct arguments into the kw hash loc=locals() del loc['kw'] kw.update(loc) del kw['source'], kw['target'], kw['env'] # if no "SOURCE_URL" tag is given add a default one. if 'SOURCE_URL' not in kw: #kw['SOURCE_URL']=(str(target[0])+".tar.gz").replace('.rpm', '') kw['SOURCE_URL']=string.replace(str(target[0])+".tar.gz", '.rpm', '') # mangle the source and target list for the rpmbuild env = OverrideEnvironment(env, kw) target, source = stripinstallbuilder(target, source, env) target, source = addspecfile(target, source, env) target, source = collectintargz(target, source, env) # now call the rpm builder to actually build the packet. return bld(*[env, target, source], **kw) def collectintargz(target, source, env): """ Puts all source files into a tar.gz file. """ # the rpm tool depends on a source package, until this is chagned # this hack needs to be here that tries to pack all sources in. sources = env.FindSourceFiles() # filter out the target we are building the source list for. #sources = [s for s in sources if not (s in target)] sources = filter(lambda s, t=target: not (s in t), sources) # find the .spec file for rpm and add it since it is not necessarily found # by the FindSourceFiles function. #sources.extend( [s for s in source if str(s).rfind('.spec')!=-1] ) spec_file = lambda s: string.rfind(str(s), '.spec') != -1 sources.extend( filter(spec_file, source) ) # as the source contains the url of the source package this rpm package # is built from, we extract the target name #tarball = (str(target[0])+".tar.gz").replace('.rpm', '') tarball = string.replace(str(target[0])+".tar.gz", '.rpm', '') try: #tarball = env['SOURCE_URL'].split('/')[-1] tarball = string.split(env['SOURCE_URL'], '/')[-1] except KeyError as e: raise SCons.Errors.UserError( "Missing PackageTag '%s' for RPM packager" % e.args[0] ) tarball = src_targz.package(env, source=sources, target=tarball, PACKAGEROOT=env['PACKAGEROOT'], ) return (target, tarball) def addspecfile(target, source, env): specfile = "%s-%s" % (env['NAME'], env['VERSION']) bld = SCons.Builder.Builder(action = build_specfile, suffix = '.spec', target_factory = SCons.Node.FS.File) source.extend(bld(env, specfile, source)) return (target,source) def build_specfile(target, source, env): """ Builds a RPM specfile from a dictionary with string metadata and by analyzing a tree of nodes. """ file = open(target[0].abspath, 'w') str = "" try: file.write( build_specfile_header(env) ) file.write( build_specfile_sections(env) ) file.write( build_specfile_filesection(env, source) ) file.close() # call a user specified function if 'CHANGE_SPECFILE' in env: env['CHANGE_SPECFILE'](target, source) except KeyError as e: raise SCons.Errors.UserError( '"%s" package field for RPM is missing.' % e.args[0] ) # # mandatory and optional package tag section # def build_specfile_sections(spec): """ Builds the sections of a rpm specfile. """ str = "" mandatory_sections = { 'DESCRIPTION' : '\n%%description\n%s\n\n', } str = str + SimpleTagCompiler(mandatory_sections).compile( spec ) optional_sections = { 'DESCRIPTION_' : '%%description -l %s\n%s\n\n', 'CHANGELOG' : '%%changelog\n%s\n\n', 'X_RPM_PREINSTALL' : '%%pre\n%s\n\n', 'X_RPM_POSTINSTALL' : '%%post\n%s\n\n', 'X_RPM_PREUNINSTALL' : '%%preun\n%s\n\n', 'X_RPM_POSTUNINSTALL' : '%%postun\n%s\n\n', 'X_RPM_VERIFY' : '%%verify\n%s\n\n', # These are for internal use but could possibly be overriden 'X_RPM_PREP' : '%%prep\n%s\n\n', 'X_RPM_BUILD' : '%%build\n%s\n\n', 'X_RPM_INSTALL' : '%%install\n%s\n\n', 'X_RPM_CLEAN' : '%%clean\n%s\n\n', } # Default prep, build, install and clean rules # TODO: optimize those build steps, to not compile the project a second time if 'X_RPM_PREP' not in spec: spec['X_RPM_PREP'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"' + '\n%setup -q' if 'X_RPM_BUILD' not in spec: spec['X_RPM_BUILD'] = 'mkdir "$RPM_BUILD_ROOT"' if 'X_RPM_INSTALL' not in spec: spec['X_RPM_INSTALL'] = 'scons --install-sandbox="$RPM_BUILD_ROOT" "$RPM_BUILD_ROOT"' if 'X_RPM_CLEAN' not in spec: spec['X_RPM_CLEAN'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"' str = str + SimpleTagCompiler(optional_sections, mandatory=0).compile( spec ) return str def build_specfile_header(spec): """ Builds all section but the %file of a rpm specfile """ str = "" # first the mandatory sections mandatory_header_fields = { 'NAME' : '%%define name %s\nName: %%{name}\n', 'VERSION' : '%%define version %s\nVersion: %%{version}\n', 'PACKAGEVERSION' : '%%define release %s\nRelease: %%{release}\n', 'X_RPM_GROUP' : 'Group: %s\n', 'SUMMARY' : 'Summary: %s\n', 'LICENSE' : 'License: %s\n', } str = str + SimpleTagCompiler(mandatory_header_fields).compile( spec ) # now the optional tags optional_header_fields = { 'VENDOR' : 'Vendor: %s\n', 'X_RPM_URL' : 'Url: %s\n', 'SOURCE_URL' : 'Source: %s\n', 'SUMMARY_' : 'Summary(%s): %s\n', 'X_RPM_DISTRIBUTION' : 'Distribution: %s\n', 'X_RPM_ICON' : 'Icon: %s\n', 'X_RPM_PACKAGER' : 'Packager: %s\n', 'X_RPM_GROUP_' : 'Group(%s): %s\n', 'X_RPM_REQUIRES' : 'Requires: %s\n', 'X_RPM_PROVIDES' : 'Provides: %s\n', 'X_RPM_CONFLICTS' : 'Conflicts: %s\n', 'X_RPM_BUILDREQUIRES' : 'BuildRequires: %s\n', 'X_RPM_SERIAL' : 'Serial: %s\n', 'X_RPM_EPOCH' : 'Epoch: %s\n', 'X_RPM_AUTOREQPROV' : 'AutoReqProv: %s\n', 'X_RPM_EXCLUDEARCH' : 'ExcludeArch: %s\n', 'X_RPM_EXCLUSIVEARCH' : 'ExclusiveArch: %s\n', 'X_RPM_PREFIX' : 'Prefix: %s\n', 'X_RPM_CONFLICTS' : 'Conflicts: %s\n', # internal use 'X_RPM_BUILDROOT' : 'BuildRoot: %s\n', } # fill in default values: # Adding a BuildRequires renders the .rpm unbuildable under System, which # are not managed by rpm, since the database to resolve this dependency is # missing (take Gentoo as an example) # if not s.has_key('x_rpm_BuildRequires'): # s['x_rpm_BuildRequires'] = 'scons' if 'X_RPM_BUILDROOT' not in spec: spec['X_RPM_BUILDROOT'] = '%{_tmppath}/%{name}-%{version}-%{release}' str = str + SimpleTagCompiler(optional_header_fields, mandatory=0).compile( spec ) return str # # mandatory and optional file tags # def build_specfile_filesection(spec, files): """ builds the %file section of the specfile """ str = '%files\n' if 'X_RPM_DEFATTR' not in spec: spec['X_RPM_DEFATTR'] = '(-,root,root)' str = str + '%%defattr %s\n' % spec['X_RPM_DEFATTR'] supported_tags = { 'PACKAGING_CONFIG' : '%%config %s', 'PACKAGING_CONFIG_NOREPLACE' : '%%config(noreplace) %s', 'PACKAGING_DOC' : '%%doc %s', 'PACKAGING_UNIX_ATTR' : '%%attr %s', 'PACKAGING_LANG_' : '%%lang(%s) %s', 'PACKAGING_X_RPM_VERIFY' : '%%verify %s', 'PACKAGING_X_RPM_DIR' : '%%dir %s', 'PACKAGING_X_RPM_DOCDIR' : '%%docdir %s', 'PACKAGING_X_RPM_GHOST' : '%%ghost %s', } for file in files: # build the tagset tags = {} for k in supported_tags.keys(): try: tags[k]=getattr(file, k) except AttributeError: pass # compile the tagset str = str + SimpleTagCompiler(supported_tags, mandatory=0).compile( tags ) str = str + ' ' str = str + file.PACKAGING_INSTALL_LOCATION str = str + '\n\n' return str class SimpleTagCompiler: """ This class is a simple string substition utility: the replacement specfication is stored in the tagset dictionary, something like: { "abc" : "cdef %s ", "abc_" : "cdef %s %s" } the compile function gets a value dictionary, which may look like: { "abc" : "ghij", "abc_gh" : "ij" } The resulting string will be: "cdef ghij cdef gh ij" """ def __init__(self, tagset, mandatory=1): self.tagset = tagset self.mandatory = mandatory def compile(self, values): """ compiles the tagset and returns a str containing the result """ def is_international(tag): #return tag.endswith('_') return tag[-1:] == '_' def get_country_code(tag): return tag[-2:] def strip_country_code(tag): return tag[:-2] replacements = self.tagset.items() str = "" #domestic = [ (k,v) for k,v in replacements if not is_international(k) ] domestic = filter(lambda t, i=is_international: not i(t[0]), replacements) for key, replacement in domestic: try: str = str + replacement % values[key] except KeyError as e: if self.mandatory: raise e #international = [ (k,v) for k,v in replacements if is_international(k) ] international = filter(lambda t, i=is_international: i(t[0]), replacements) for key, replacement in international: try: #int_values_for_key = [ (get_country_code(k),v) for k,v in values.items() if strip_country_code(k) == key ] x = filter(lambda t,key=key,s=strip_country_code: s(t[0]) == key, values.items()) int_values_for_key = map(lambda t,g=get_country_code: (g(t[0]),t[1]), x) for v in int_values_for_key: str = str + replacement % v except KeyError as e: if self.mandatory: raise e return str # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/zip.py0000644000175000017500000000334713606712377023410 0ustar kurtkurt"""SCons.Tool.Packaging.zip The zip SRC packager. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/zip.py 4369 2009/09/19 15:58:29 scons" from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot def package(env, target, source, PACKAGEROOT, **kw): bld = env['BUILDERS']['Zip'] bld.set_suffix('.zip') target, source = stripinstallbuilder(target, source, env) target, source = putintopackageroot(target, source, env, PACKAGEROOT) return bld(env, target, source) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/tarbz2.py0000644000175000017500000000340313606712377024003 0ustar kurtkurt"""SCons.Tool.Packaging.tarbz2 The tarbz2 SRC packager. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/tarbz2.py 4369 2009/09/19 15:58:29 scons" from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot def package(env, target, source, PACKAGEROOT, **kw): bld = env['BUILDERS']['Tar'] bld.set_suffix('.tar.gz') target, source = putintopackageroot(target, source, env, PACKAGEROOT) target, source = stripinstallbuilder(target, source, env) return bld(env, target, source, TARFLAGS='-jc') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/packaging/msi.py0000644000175000017500000004737013606712377023402 0ustar kurtkurt"""SCons.Tool.packaging.msi The msi packager. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/packaging/msi.py 4369 2009/09/19 15:58:29 scons" import os import SCons from SCons.Action import Action from SCons.Builder import Builder from xml.dom.minidom import * from xml.sax.saxutils import escape from SCons.Tool.packaging import stripinstallbuilder # # Utility functions # def convert_to_id(s, id_set): """ Some parts of .wxs need an Id attribute (for example: The File and Directory directives. The charset is limited to A-Z, a-z, digits, underscores, periods. Each Id must begin with a letter or with a underscore. Google for "CNDL0015" for information about this. Requirements: * the string created must only contain chars from the target charset. * the string created must have a minimal editing distance from the original string. * the string created must be unique for the whole .wxs file. Observation: * There are 62 chars in the charset. Idea: * filter out forbidden characters. Check for a collision with the help of the id_set. Add the number of the number of the collision at the end of the created string. Furthermore care for a correct start of the string. """ charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz0123456789_.' if s[0] in '0123456789.': s += '_'+s id = filter( lambda c : c in charset, s ) # did we already generate an id for this file? try: return id_set[id][s] except KeyError: # no we did not so initialize with the id if id not in id_set: id_set[id] = { s : id } # there is a collision, generate an id which is unique by appending # the collision number else: id_set[id][s] = id + str(len(id_set[id])) return id_set[id][s] def is_dos_short_file_name(file): """ examine if the given file is in the 8.3 form. """ fname, ext = os.path.splitext(file) proper_ext = len(ext) == 0 or (2 <= len(ext) <= 4) # the ext contains the dot proper_fname = file.isupper() and len(fname) <= 8 return proper_ext and proper_fname def gen_dos_short_file_name(file, filename_set): """ see http://support.microsoft.com/default.aspx?scid=kb;en-us;Q142982 These are no complete 8.3 dos short names. The ~ char is missing and replaced with one character from the filename. WiX warns about such filenames, since a collision might occur. Google for "CNDL1014" for more information. """ # guard this to not confuse the generation if is_dos_short_file_name(file): return file fname, ext = os.path.splitext(file) # ext contains the dot # first try if it suffices to convert to upper file = file.upper() if is_dos_short_file_name(file): return file # strip forbidden characters. forbidden = '."/[]:;=, ' fname = filter( lambda c : c not in forbidden, fname ) # check if we already generated a filename with the same number: # thisis1.txt, thisis2.txt etc. duplicate, num = not None, 1 while duplicate: shortname = "%s%s" % (fname[:8-len(str(num))].upper(),\ str(num)) if len(ext) >= 2: shortname = "%s%s" % (shortname, ext[:4].upper()) duplicate, num = shortname in filename_set, num+1 assert( is_dos_short_file_name(shortname) ), 'shortname is %s, longname is %s' % (shortname, file) filename_set.append(shortname) return shortname def create_feature_dict(files): """ X_MSI_FEATURE and doc FileTag's can be used to collect files in a hierarchy. This function collects the files into this hierarchy. """ dict = {} def add_to_dict( feature, file ): if not SCons.Util.is_List( feature ): feature = [ feature ] for f in feature: if f not in dict: dict[ f ] = [ file ] else: dict[ f ].append( file ) for file in files: if hasattr( file, 'PACKAGING_X_MSI_FEATURE' ): add_to_dict(file.PACKAGING_X_MSI_FEATURE, file) elif hasattr( file, 'PACKAGING_DOC' ): add_to_dict( 'PACKAGING_DOC', file ) else: add_to_dict( 'default', file ) return dict def generate_guids(root): """ generates globally unique identifiers for parts of the xml which need them. Component tags have a special requirement. Their UUID is only allowed to change if the list of their contained resources has changed. This allows for clean removal and proper updates. To handle this requirement, the uuid is generated with an md5 hashing the whole subtree of a xml node. """ from hashlib import md5 # specify which tags need a guid and in which attribute this should be stored. needs_id = { 'Product' : 'Id', 'Package' : 'Id', 'Component' : 'Guid', } # find all XMl nodes matching the key, retrieve their attribute, hash their # subtree, convert hash to string and add as a attribute to the xml node. for (key,value) in needs_id.items(): node_list = root.getElementsByTagName(key) attribute = value for node in node_list: hash = md5(node.toxml()).hexdigest() hash_str = '%s-%s-%s-%s-%s' % ( hash[:8], hash[8:12], hash[12:16], hash[16:20], hash[20:] ) node.attributes[attribute] = hash_str def string_wxsfile(target, source, env): return "building WiX file %s"%( target[0].path ) def build_wxsfile(target, source, env): """ compiles a .wxs file from the keywords given in env['msi_spec'] and by analyzing the tree of source nodes and their tags. """ file = open(target[0].abspath, 'w') try: # Create a document with the Wix root tag doc = Document() root = doc.createElement( 'Wix' ) root.attributes['xmlns']='http://schemas.microsoft.com/wix/2003/01/wi' doc.appendChild( root ) filename_set = [] # this is to circumvent duplicates in the shortnames id_set = {} # this is to circumvent duplicates in the ids # Create the content build_wxsfile_header_section(root, env) build_wxsfile_file_section(root, source, env['NAME'], env['VERSION'], env['VENDOR'], filename_set, id_set) generate_guids(root) build_wxsfile_features_section(root, source, env['NAME'], env['VERSION'], env['SUMMARY'], id_set) build_wxsfile_default_gui(root) build_license_file(target[0].get_dir(), env) # write the xml to a file file.write( doc.toprettyxml() ) # call a user specified function if 'CHANGE_SPECFILE' in env: env['CHANGE_SPECFILE'](target, source) except KeyError as e: raise SCons.Errors.UserError( '"%s" package field for MSI is missing.' % e.args[0] ) # # setup function # def create_default_directory_layout(root, NAME, VERSION, VENDOR, filename_set): """ Create the wix default target directory layout and return the innermost directory. We assume that the XML tree delivered in the root argument already contains the Product tag. Everything is put under the PFiles directory property defined by WiX. After that a directory with the 'VENDOR' tag is placed and then a directory with the name of the project and its VERSION. This leads to the following TARGET Directory Layout: C:\\\\ Example: C:\Programme\Company\Product-1.2\ """ doc = Document() d1 = doc.createElement( 'Directory' ) d1.attributes['Id'] = 'TARGETDIR' d1.attributes['Name'] = 'SourceDir' d2 = doc.createElement( 'Directory' ) d2.attributes['Id'] = 'ProgramFilesFolder' d2.attributes['Name'] = 'PFiles' d3 = doc.createElement( 'Directory' ) d3.attributes['Id'] = 'VENDOR_folder' d3.attributes['Name'] = escape( gen_dos_short_file_name( VENDOR, filename_set ) ) d3.attributes['LongName'] = escape( VENDOR ) d4 = doc.createElement( 'Directory' ) project_folder = "%s-%s" % ( NAME, VERSION ) d4.attributes['Id'] = 'MY_DEFAULT_FOLDER' d4.attributes['Name'] = escape( gen_dos_short_file_name( project_folder, filename_set ) ) d4.attributes['LongName'] = escape( project_folder ) d1.childNodes.append( d2 ) d2.childNodes.append( d3 ) d3.childNodes.append( d4 ) root.getElementsByTagName('Product')[0].childNodes.append( d1 ) return d4 # # mandatory and optional file tags # def build_wxsfile_file_section(root, files, NAME, VERSION, VENDOR, filename_set, id_set): """ builds the Component sections of the wxs file with their included files. Files need to be specified in 8.3 format and in the long name format, long filenames will be converted automatically. Features are specficied with the 'X_MSI_FEATURE' or 'DOC' FileTag. """ root = create_default_directory_layout( root, NAME, VERSION, VENDOR, filename_set ) components = create_feature_dict( files ) factory = Document() def get_directory( node, dir ): """ returns the node under the given node representing the directory. Returns the component node if dir is None or empty. """ if dir == '' or not dir: return node Directory = node dir_parts = dir.split(os.path.sep) # to make sure that our directory ids are unique, the parent folders are # consecutively added to upper_dir upper_dir = '' # walk down the xml tree finding parts of the directory dir_parts = filter( lambda d: d != '', dir_parts ) for d in dir_parts[:]: already_created = filter( lambda c: c.nodeName == 'Directory' and c.attributes['LongName'].value == escape(d), Directory.childNodes ) if already_created != []: Directory = already_created[0] dir_parts.remove(d) upper_dir += d else: break for d in dir_parts: nDirectory = factory.createElement( 'Directory' ) nDirectory.attributes['LongName'] = escape( d ) nDirectory.attributes['Name'] = escape( gen_dos_short_file_name( d, filename_set ) ) upper_dir += d nDirectory.attributes['Id'] = convert_to_id( upper_dir, id_set ) Directory.childNodes.append( nDirectory ) Directory = nDirectory return Directory for file in files: drive, path = os.path.splitdrive( file.PACKAGING_INSTALL_LOCATION ) filename = os.path.basename( path ) dirname = os.path.dirname( path ) h = { # tagname : default value 'PACKAGING_X_MSI_VITAL' : 'yes', 'PACKAGING_X_MSI_FILEID' : convert_to_id(filename, id_set), 'PACKAGING_X_MSI_LONGNAME' : filename, 'PACKAGING_X_MSI_SHORTNAME' : gen_dos_short_file_name(filename, filename_set), 'PACKAGING_X_MSI_SOURCE' : file.get_path(), } # fill in the default tags given above. for k,v in [ (k, v) for (k,v) in h.items() if not hasattr(file, k) ]: setattr( file, k, v ) File = factory.createElement( 'File' ) File.attributes['LongName'] = escape( file.PACKAGING_X_MSI_LONGNAME ) File.attributes['Name'] = escape( file.PACKAGING_X_MSI_SHORTNAME ) File.attributes['Source'] = escape( file.PACKAGING_X_MSI_SOURCE ) File.attributes['Id'] = escape( file.PACKAGING_X_MSI_FILEID ) File.attributes['Vital'] = escape( file.PACKAGING_X_MSI_VITAL ) # create the Tag under which this file should appear Component = factory.createElement('Component') Component.attributes['DiskId'] = '1' Component.attributes['Id'] = convert_to_id( filename, id_set ) # hang the component node under the root node and the file node # under the component node. Directory = get_directory( root, dirname ) Directory.childNodes.append( Component ) Component.childNodes.append( File ) # # additional functions # def build_wxsfile_features_section(root, files, NAME, VERSION, SUMMARY, id_set): """ This function creates the tag based on the supplied xml tree. This is achieved by finding all s and adding them to a default target. It should be called after the tree has been built completly. We assume that a MY_DEFAULT_FOLDER Property is defined in the wxs file tree. Furthermore a top-level with the name and VERSION of the software will be created. An PACKAGING_X_MSI_FEATURE can either be a string, where the feature DESCRIPTION will be the same as its title or a Tuple, where the first part will be its title and the second its DESCRIPTION. """ factory = Document() Feature = factory.createElement('Feature') Feature.attributes['Id'] = 'complete' Feature.attributes['ConfigurableDirectory'] = 'MY_DEFAULT_FOLDER' Feature.attributes['Level'] = '1' Feature.attributes['Title'] = escape( '%s %s' % (NAME, VERSION) ) Feature.attributes['Description'] = escape( SUMMARY ) Feature.attributes['Display'] = 'expand' for (feature, files) in create_feature_dict(files).items(): SubFeature = factory.createElement('Feature') SubFeature.attributes['Level'] = '1' if SCons.Util.is_Tuple(feature): SubFeature.attributes['Id'] = convert_to_id( feature[0], id_set ) SubFeature.attributes['Title'] = escape(feature[0]) SubFeature.attributes['Description'] = escape(feature[1]) else: SubFeature.attributes['Id'] = convert_to_id( feature, id_set ) if feature=='default': SubFeature.attributes['Description'] = 'Main Part' SubFeature.attributes['Title'] = 'Main Part' elif feature=='PACKAGING_DOC': SubFeature.attributes['Description'] = 'Documentation' SubFeature.attributes['Title'] = 'Documentation' else: SubFeature.attributes['Description'] = escape(feature) SubFeature.attributes['Title'] = escape(feature) # build the componentrefs. As one of the design decision is that every # file is also a component we walk the list of files and create a # reference. for f in files: ComponentRef = factory.createElement('ComponentRef') ComponentRef.attributes['Id'] = convert_to_id( os.path.basename(f.get_path()), id_set ) SubFeature.childNodes.append(ComponentRef) Feature.childNodes.append(SubFeature) root.getElementsByTagName('Product')[0].childNodes.append(Feature) def build_wxsfile_default_gui(root): """ this function adds a default GUI to the wxs file """ factory = Document() Product = root.getElementsByTagName('Product')[0] UIRef = factory.createElement('UIRef') UIRef.attributes['Id'] = 'WixUI_Mondo' Product.childNodes.append(UIRef) UIRef = factory.createElement('UIRef') UIRef.attributes['Id'] = 'WixUI_ErrorProgressText' Product.childNodes.append(UIRef) def build_license_file(directory, spec): """ creates a License.rtf file with the content of "X_MSI_LICENSE_TEXT" in the given directory """ name, text = '', '' try: name = spec['LICENSE'] text = spec['X_MSI_LICENSE_TEXT'] except KeyError: pass # ignore this as X_MSI_LICENSE_TEXT is optional if name!='' or text!='': file = open( os.path.join(directory.get_path(), 'License.rtf'), 'w' ) file.write('{\\rtf') if text!='': file.write(text.replace('\n', '\\par ')) else: file.write(name+'\\par\\par') file.write('}') file.close() # # mandatory and optional package tags # def build_wxsfile_header_section(root, spec): """ Adds the xml file node which define the package meta-data. """ # Create the needed DOM nodes and add them at the correct position in the tree. factory = Document() Product = factory.createElement( 'Product' ) Package = factory.createElement( 'Package' ) root.childNodes.append( Product ) Product.childNodes.append( Package ) # set "mandatory" default values if 'X_MSI_LANGUAGE' not in spec: spec['X_MSI_LANGUAGE'] = '1033' # select english # mandatory sections, will throw a KeyError if the tag is not available Product.attributes['Name'] = escape( spec['NAME'] ) Product.attributes['Version'] = escape( spec['VERSION'] ) Product.attributes['Manufacturer'] = escape( spec['VENDOR'] ) Product.attributes['Language'] = escape( spec['X_MSI_LANGUAGE'] ) Package.attributes['Description'] = escape( spec['SUMMARY'] ) # now the optional tags, for which we avoid the KeyErrror exception if 'DESCRIPTION' in spec: Package.attributes['Comments'] = escape( spec['DESCRIPTION'] ) if 'X_MSI_UPGRADE_CODE' in spec: Package.attributes['X_MSI_UPGRADE_CODE'] = escape( spec['X_MSI_UPGRADE_CODE'] ) # We hardcode the media tag as our current model cannot handle it. Media = factory.createElement('Media') Media.attributes['Id'] = '1' Media.attributes['Cabinet'] = 'default.cab' Media.attributes['EmbedCab'] = 'yes' root.getElementsByTagName('Product')[0].childNodes.append(Media) # this builder is the entry-point for .wxs file compiler. wxs_builder = Builder( action = Action( build_wxsfile, string_wxsfile ), ensure_suffix = '.wxs' ) def package(env, target, source, PACKAGEROOT, NAME, VERSION, DESCRIPTION, SUMMARY, VENDOR, X_MSI_LANGUAGE, **kw): # make sure that the Wix Builder is in the environment SCons.Tool.Tool('wix').generate(env) # get put the keywords for the specfile compiler. These are the arguments # given to the package function and all optional ones stored in kw, minus # the the source, target and env one. loc = locals() del loc['kw'] kw.update(loc) del kw['source'], kw['target'], kw['env'] # strip the install builder from the source files target, source = stripinstallbuilder(target, source, env) # put the arguments into the env and call the specfile builder. env['msi_spec'] = kw specfile = wxs_builder(*[env, target, source], **kw) # now call the WiX Tool with the built specfile added as a source. msifile = env.WiX(target, specfile) # return the target and source tuple. return (msifile, source+[specfile]) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/mssdk.py0000644000175000017500000000347113606712377022001 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/mssdk.py 4369 2009/09/19 15:58:29 scons" """engine.SCons.Tool.mssdk Tool-specific initialization for Microsoft SDKs, both Platform SDKs and Windows SDKs. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from MSCommon import mssdk_exists, \ mssdk_setup_env def generate(env): """Add construction variables for an MS SDK to an Environment.""" mssdk_setup_env(env) def exists(env): return mssdk_exists() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/386asm.py0000644000175000017500000000424313606712377021677 0ustar kurtkurt"""SCons.Tool.386asm Tool specification for the 386ASM assembler for the Phar Lap ETS embedded operating system. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/386asm.py 4369 2009/09/19 15:58:29 scons" from SCons.Tool.PharLapCommon import addPharLapPaths import SCons.Util as_module = __import__('as', globals(), locals(), []) def generate(env): """Add Builders and construction variables for ar to an Environment.""" as_module.generate(env) env['AS'] = '386asm' env['ASFLAGS'] = SCons.Util.CLVar('') env['ASPPFLAGS'] = '$ASFLAGS' env['ASCOM'] = '$AS $ASFLAGS $SOURCES -o $TARGET' env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES -o $TARGET' addPharLapPaths(env) def exists(env): return env.Detect('386asm') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/wix.py0000644000175000017500000000677113606712377021475 0ustar kurtkurt"""SCons.Tool.wix Tool-specific initialization for wix, the Windows Installer XML Tool. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/wix.py 4369 2009/09/19 15:58:29 scons" import SCons.Builder import SCons.Action import os import string def generate(env): """Add Builders and construction variables for WiX to an Environment.""" if not exists(env): return env['WIXCANDLEFLAGS'] = ['-nologo'] env['WIXCANDLEINCLUDE'] = [] env['WIXCANDLECOM'] = '$WIXCANDLE $WIXCANDLEFLAGS -I $WIXCANDLEINCLUDE -o ${TARGET} ${SOURCE}' env['WIXLIGHTFLAGS'].append( '-nologo' ) env['WIXLIGHTCOM'] = "$WIXLIGHT $WIXLIGHTFLAGS -out ${TARGET} ${SOURCES}" object_builder = SCons.Builder.Builder( action = '$WIXCANDLECOM', suffix = '.wxiobj', src_suffix = '.wxs') linker_builder = SCons.Builder.Builder( action = '$WIXLIGHTCOM', src_suffix = '.wxiobj', src_builder = object_builder) env['BUILDERS']['WiX'] = linker_builder def exists(env): env['WIXCANDLE'] = 'candle.exe' env['WIXLIGHT'] = 'light.exe' # try to find the candle.exe and light.exe tools and # add the install directory to light libpath. #for path in os.environ['PATH'].split(os.pathsep): for path in string.split(os.environ['PATH'], os.pathsep): if not path: continue # workaround for some weird python win32 bug. if path[0] == '"' and path[-1:]=='"': path = path[1:-1] # normalize the path path = os.path.normpath(path) # search for the tools in the PATH environment variable try: if env['WIXCANDLE'] in os.listdir(path) and\ env['WIXLIGHT'] in os.listdir(path): env.PrependENVPath('PATH', path) env['WIXLIGHTFLAGS'] = [ os.path.join( path, 'wixui.wixlib' ), '-loc', os.path.join( path, 'WixUI_en-us.wxl' ) ] return 1 except OSError: pass # ignore this, could be a stale PATH entry. return None # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/rpcgen.py0000644000175000017500000000547413606712377022143 0ustar kurtkurt"""SCons.Tool.rpcgen Tool-specific initialization for RPCGEN tools. Three normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/rpcgen.py 4369 2009/09/19 15:58:29 scons" from SCons.Builder import Builder import SCons.Util cmd = "cd ${SOURCE.dir} && $RPCGEN -%s $RPCGENFLAGS %s -o ${TARGET.abspath} ${SOURCE.file}" rpcgen_client = cmd % ('l', '$RPCGENCLIENTFLAGS') rpcgen_header = cmd % ('h', '$RPCGENHEADERFLAGS') rpcgen_service = cmd % ('m', '$RPCGENSERVICEFLAGS') rpcgen_xdr = cmd % ('c', '$RPCGENXDRFLAGS') def generate(env): "Add RPCGEN Builders and construction variables for an Environment." client = Builder(action=rpcgen_client, suffix='_clnt.c', src_suffix='.x') header = Builder(action=rpcgen_header, suffix='.h', src_suffix='.x') service = Builder(action=rpcgen_service, suffix='_svc.c', src_suffix='.x') xdr = Builder(action=rpcgen_xdr, suffix='_xdr.c', src_suffix='.x') env.Append(BUILDERS={'RPCGenClient' : client, 'RPCGenHeader' : header, 'RPCGenService' : service, 'RPCGenXDR' : xdr}) env['RPCGEN'] = 'rpcgen' env['RPCGENFLAGS'] = SCons.Util.CLVar('') env['RPCGENCLIENTFLAGS'] = SCons.Util.CLVar('') env['RPCGENHEADERFLAGS'] = SCons.Util.CLVar('') env['RPCGENSERVICEFLAGS'] = SCons.Util.CLVar('') env['RPCGENXDRFLAGS'] = SCons.Util.CLVar('') def exists(env): return env.Detect('rpcgen') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/FortranCommon.py0000644000175000017500000002320413606712377023440 0ustar kurtkurt"""SCons.Tool.FortranCommon Stuff for processing Fortran, common to all fortran dialects. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/FortranCommon.py 4369 2009/09/19 15:58:29 scons" import re import string import os.path import SCons.Action import SCons.Defaults import SCons.Scanner.Fortran import SCons.Tool import SCons.Util def isfortran(env, source): """Return 1 if any of code in source has fortran files in it, 0 otherwise.""" try: fsuffixes = env['FORTRANSUFFIXES'] except KeyError: # If no FORTRANSUFFIXES, no fortran tool, so there is no need to look # for fortran sources. return 0 if not source: # Source might be None for unusual cases like SConf. return 0 for s in source: if s.sources: ext = os.path.splitext(str(s.sources[0]))[1] if ext in fsuffixes: return 1 return 0 def _fortranEmitter(target, source, env): node = source[0].rfile() if not node.exists() and not node.is_derived(): print("Could not locate " + str(node.name)) return ([], []) mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" cre = re.compile(mod_regex,re.M) # Retrieve all USE'd module names modules = cre.findall(node.get_text_contents()) # Remove unique items from the list modules = SCons.Util.unique(modules) # Convert module name to a .mod filename suffix = env.subst('$FORTRANMODSUFFIX', target=target, source=source) moddir = env.subst('$FORTRANMODDIR', target=target, source=source) modules = map(lambda x, s=suffix: string.lower(x) + s, modules) for m in modules: target.append(env.fs.File(m, moddir)) return (target, source) def FortranEmitter(target, source, env): target, source = _fortranEmitter(target, source, env) return SCons.Defaults.StaticObjectEmitter(target, source, env) def ShFortranEmitter(target, source, env): target, source = _fortranEmitter(target, source, env) return SCons.Defaults.SharedObjectEmitter(target, source, env) def ComputeFortranSuffixes(suffixes, ppsuffixes): """suffixes are fortran source files, and ppsuffixes the ones to be pre-processed. Both should be sequences, not strings.""" assert len(suffixes) > 0 s = suffixes[0] sup = string.upper(s) upper_suffixes = map(string.upper, suffixes) if SCons.Util.case_sensitive_suffixes(s, sup): ppsuffixes.extend(upper_suffixes) else: suffixes.extend(upper_suffixes) def CreateDialectActions(dialect): """Create dialect specific actions.""" CompAction = SCons.Action.Action('$%sCOM ' % dialect, '$%sCOMSTR' % dialect) CompPPAction = SCons.Action.Action('$%sPPCOM ' % dialect, '$%sPPCOMSTR' % dialect) ShCompAction = SCons.Action.Action('$SH%sCOM ' % dialect, '$SH%sCOMSTR' % dialect) ShCompPPAction = SCons.Action.Action('$SH%sPPCOM ' % dialect, '$SH%sPPCOMSTR' % dialect) return CompAction, CompPPAction, ShCompAction, ShCompPPAction def DialectAddToEnv(env, dialect, suffixes, ppsuffixes, support_module = 0): """Add dialect specific construction variables.""" ComputeFortranSuffixes(suffixes, ppsuffixes) fscan = SCons.Scanner.Fortran.FortranScan("%sPATH" % dialect) for suffix in suffixes + ppsuffixes: SCons.Tool.SourceFileScanner.add_scanner(suffix, fscan) env.AppendUnique(FORTRANSUFFIXES = suffixes + ppsuffixes) compaction, compppaction, shcompaction, shcompppaction = \ CreateDialectActions(dialect) static_obj, shared_obj = SCons.Tool.createObjBuilders(env) for suffix in suffixes: static_obj.add_action(suffix, compaction) shared_obj.add_action(suffix, shcompaction) static_obj.add_emitter(suffix, FortranEmitter) shared_obj.add_emitter(suffix, ShFortranEmitter) for suffix in ppsuffixes: static_obj.add_action(suffix, compppaction) shared_obj.add_action(suffix, shcompppaction) static_obj.add_emitter(suffix, FortranEmitter) shared_obj.add_emitter(suffix, ShFortranEmitter) if '%sFLAGS' % dialect not in env: env['%sFLAGS' % dialect] = SCons.Util.CLVar('') if 'SH%sFLAGS' % dialect not in env: env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS' % dialect) # If a tool does not define fortran prefix/suffix for include path, use C ones if 'INC%sPREFIX' % dialect not in env: env['INC%sPREFIX' % dialect] = '$INCPREFIX' if 'INC%sSUFFIX' % dialect not in env: env['INC%sSUFFIX' % dialect] = '$INCSUFFIX' env['_%sINCFLAGS' % dialect] = '$( ${_concat(INC%sPREFIX, %sPATH, INC%sSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' % (dialect, dialect, dialect) if support_module == 1: env['%sCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect) env['%sPPCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect) env['SH%sCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect) env['SH%sPPCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect) else: env['%sCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect) env['%sPPCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect) env['SH%sCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect) env['SH%sPPCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect) def add_fortran_to_env(env): """Add Builders and construction variables for Fortran to an Environment.""" try: FortranSuffixes = env['FORTRANFILESUFFIXES'] except KeyError: FortranSuffixes = ['.f', '.for', '.ftn'] #print "Adding %s to fortran suffixes" % FortranSuffixes try: FortranPPSuffixes = env['FORTRANPPFILESUFFIXES'] except KeyError: FortranPPSuffixes = ['.fpp', '.FPP'] DialectAddToEnv(env, "FORTRAN", FortranSuffixes, FortranPPSuffixes, support_module = 1) env['FORTRANMODPREFIX'] = '' # like $LIBPREFIX env['FORTRANMODSUFFIX'] = '.mod' # like $LIBSUFFIX env['FORTRANMODDIR'] = '' # where the compiler should place .mod files env['FORTRANMODDIRPREFIX'] = '' # some prefix to $FORTRANMODDIR - similar to $INCPREFIX env['FORTRANMODDIRSUFFIX'] = '' # some suffix to $FORTRANMODDIR - similar to $INCSUFFIX env['_FORTRANMODFLAG'] = '$( ${_concat(FORTRANMODDIRPREFIX, FORTRANMODDIR, FORTRANMODDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' def add_f77_to_env(env): """Add Builders and construction variables for f77 to an Environment.""" try: F77Suffixes = env['F77FILESUFFIXES'] except KeyError: F77Suffixes = ['.f77'] #print "Adding %s to f77 suffixes" % F77Suffixes try: F77PPSuffixes = env['F77PPFILESUFFIXES'] except KeyError: F77PPSuffixes = [] DialectAddToEnv(env, "F77", F77Suffixes, F77PPSuffixes) def add_f90_to_env(env): """Add Builders and construction variables for f90 to an Environment.""" try: F90Suffixes = env['F90FILESUFFIXES'] except KeyError: F90Suffixes = ['.f90'] #print "Adding %s to f90 suffixes" % F90Suffixes try: F90PPSuffixes = env['F90PPFILESUFFIXES'] except KeyError: F90PPSuffixes = [] DialectAddToEnv(env, "F90", F90Suffixes, F90PPSuffixes, support_module = 1) def add_f95_to_env(env): """Add Builders and construction variables for f95 to an Environment.""" try: F95Suffixes = env['F95FILESUFFIXES'] except KeyError: F95Suffixes = ['.f95'] #print "Adding %s to f95 suffixes" % F95Suffixes try: F95PPSuffixes = env['F95PPFILESUFFIXES'] except KeyError: F95PPSuffixes = [] DialectAddToEnv(env, "F95", F95Suffixes, F95PPSuffixes, support_module = 1) def add_all_to_env(env): """Add builders and construction variables for all supported fortran dialects.""" add_fortran_to_env(env) add_f77_to_env(env) add_f90_to_env(env) add_f95_to_env(env) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/RCS.py0000644000175000017500000000421613606712377021305 0ustar kurtkurt"""SCons.Tool.RCS.py Tool-specific initialization for RCS. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/RCS.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Builder import SCons.Util def generate(env): """Add a Builder factory function and construction variables for RCS to an Environment.""" def RCSFactory(env=env): """ """ act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR') return SCons.Builder.Builder(action = act, env = env) #setattr(env, 'RCS', RCSFactory) env.RCS = RCSFactory env['RCS'] = 'rcs' env['RCS_CO'] = 'co' env['RCS_COFLAGS'] = SCons.Util.CLVar('') env['RCS_COCOM'] = '$RCS_CO $RCS_COFLAGS $TARGET' def exists(env): return env.Detect('rcs') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/msvc.py0000644000175000017500000002364213606712377021632 0ustar kurtkurt"""engine.SCons.Tool.msvc Tool-specific initialization for Microsoft Visual C/C++. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/msvc.py 4369 2009/09/19 15:58:29 scons" import os.path import re import string import sys import SCons.Action import SCons.Builder import SCons.Errors import SCons.Platform.win32 import SCons.Tool import SCons.Tool.msvs import SCons.Util import SCons.Warnings import SCons.Scanner.RC from MSCommon import msvc_exists, msvc_setup_env CSuffixes = ['.c', '.C'] CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++'] def validate_vars(env): """Validate the PCH and PCHSTOP construction variables.""" if 'PCH' in env and env['PCH']: if 'PCHSTOP' not in env: raise SCons.Errors.UserError("The PCHSTOP construction must be defined if PCH is defined.") if not SCons.Util.is_String(env['PCHSTOP']): raise SCons.Errors.UserError("The PCHSTOP construction variable must be a string: %r"%env['PCHSTOP']) def pch_emitter(target, source, env): """Adds the object file target.""" validate_vars(env) pch = None obj = None for t in target: if SCons.Util.splitext(str(t))[1] == '.pch': pch = t if SCons.Util.splitext(str(t))[1] == '.obj': obj = t if not obj: obj = SCons.Util.splitext(str(pch))[0]+'.obj' target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work return (target, source) def object_emitter(target, source, env, parent_emitter): """Sets up the PCH dependencies for an object file.""" validate_vars(env) parent_emitter(target, source, env) if 'PCH' in env and env['PCH']: env.Depends(target, env['PCH']) return (target, source) def static_object_emitter(target, source, env): return object_emitter(target, source, env, SCons.Defaults.StaticObjectEmitter) def shared_object_emitter(target, source, env): return object_emitter(target, source, env, SCons.Defaults.SharedObjectEmitter) pch_action = SCons.Action.Action('$PCHCOM', '$PCHCOMSTR') pch_builder = SCons.Builder.Builder(action=pch_action, suffix='.pch', emitter=pch_emitter, source_scanner=SCons.Tool.SourceFileScanner) # Logic to build .rc files into .res files (resource files) res_scanner = SCons.Scanner.RC.RCScan() res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') res_builder = SCons.Builder.Builder(action=res_action, src_suffix='.rc', suffix='.res', src_builder=[], source_scanner=res_scanner) def msvc_batch_key(action, env, target, source): """ Returns a key to identify unique batches of sources for compilation. If batching is enabled (via the $MSVC_BATCH setting), then all target+source pairs that use the same action, defined by the same environment, and have the same target and source directories, will be batched. Returning None specifies that the specified target+source should not be batched with other compilations. """ b = env.subst('$MSVC_BATCH') if b in (None, '', '0'): # We're not using batching; return no key. return None t = target[0] s = source[0] if os.path.splitext(t.name)[0] != os.path.splitext(s.name)[0]: # The base names are different, so this *must* be compiled # separately; return no key. return None return (id(action), id(env), t.dir, s.dir) def msvc_output_flag(target, source, env, for_signature): """ Returns the correct /Fo flag for batching. If batching is disabled or there's only one source file, then we return an /Fo string that specifies the target explicitly. Otherwise, we return an /Fo string that just specifies the first target's directory (where the Visual C/C++ compiler will put the .obj files). """ b = env.subst('$MSVC_BATCH') if b in (None, '', '0') or len(source) == 1: return '/Fo$TARGET' else: # The Visual C/C++ compiler requires a \ at the end of the /Fo # option to indicate an output directory. We use os.sep here so # that the test(s) for this can be run on non-Windows systems # without having a hard-coded backslash mess up command-line # argument parsing. return '/Fo${TARGET.dir}' + os.sep CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR", batch_key=msvc_batch_key, targets='$CHANGED_TARGETS') ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR", batch_key=msvc_batch_key, targets='$CHANGED_TARGETS') CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR", batch_key=msvc_batch_key, targets='$CHANGED_TARGETS') ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR", batch_key=msvc_batch_key, targets='$CHANGED_TARGETS') def generate(env): """Add Builders and construction variables for MSVC++ to an Environment.""" static_obj, shared_obj = SCons.Tool.createObjBuilders(env) # TODO(batch): shouldn't reach in to cmdgen this way; necessary # for now to bypass the checks in Builder.DictCmdGenerator.__call__() # and allow .cc and .cpp to be compiled in the same command line. static_obj.cmdgen.source_ext_match = False shared_obj.cmdgen.source_ext_match = False for suffix in CSuffixes: static_obj.add_action(suffix, CAction) shared_obj.add_action(suffix, ShCAction) static_obj.add_emitter(suffix, static_object_emitter) shared_obj.add_emitter(suffix, shared_object_emitter) for suffix in CXXSuffixes: static_obj.add_action(suffix, CXXAction) shared_obj.add_action(suffix, ShCXXAction) static_obj.add_emitter(suffix, static_object_emitter) shared_obj.add_emitter(suffix, shared_object_emitter) env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Z7") or ""}']) env['CCPCHFLAGS'] = SCons.Util.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}']) env['_MSVC_OUTPUT_FLAG'] = msvc_output_flag env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPDBFLAGS' env['CC'] = 'cl' env['CCFLAGS'] = SCons.Util.CLVar('/nologo') env['CFLAGS'] = SCons.Util.CLVar('') env['CCCOM'] = '$CC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CFLAGS $CCFLAGS $_CCCOMCOM' env['SHCC'] = '$CC' env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS') env['SHCCCOM'] = '$SHCC $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCFLAGS $SHCCFLAGS $_CCCOMCOM' env['CXX'] = '$CC' env['CXXFLAGS'] = SCons.Util.CLVar('$( /TP $)') env['CXXCOM'] = '$CXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CXXFLAGS $CCFLAGS $_CCCOMCOM' env['SHCXX'] = '$CXX' env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') env['SHCXXCOM'] = '$SHCXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM' env['CPPDEFPREFIX'] = '/D' env['CPPDEFSUFFIX'] = '' env['INCPREFIX'] = '/I' env['INCSUFFIX'] = '' # env.Append(OBJEMITTER = [static_object_emitter]) # env.Append(SHOBJEMITTER = [shared_object_emitter]) env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 env['RC'] = 'rc' env['RCFLAGS'] = SCons.Util.CLVar('') env['RCSUFFIXES']=['.rc','.rc2'] env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES' env['BUILDERS']['RES'] = res_builder env['OBJPREFIX'] = '' env['OBJSUFFIX'] = '.obj' env['SHOBJPREFIX'] = '$OBJPREFIX' env['SHOBJSUFFIX'] = '$OBJSUFFIX' # Set-up ms tools paths for default version msvc_setup_env(env) import mssdk mssdk.generate(env) env['CFILESUFFIX'] = '.c' env['CXXFILESUFFIX'] = '.cc' env['PCHPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Yd") or ""}']) env['PCHCOM'] = '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS' env['BUILDERS']['PCH'] = pch_builder if 'ENV' not in env: env['ENV'] = {} if 'SystemRoot' not in env['ENV']: # required for dlls in the winsxs folders env['ENV']['SystemRoot'] = SCons.Platform.win32.get_system_root() def exists(env): return msvc_exists('cl') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/gas.py0000644000175000017500000000354113606712377021430 0ustar kurtkurt"""SCons.Tool.gas Tool-specific initialization for as, the Gnu assembler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/gas.py 4369 2009/09/19 15:58:29 scons" as_module = __import__('as', globals(), locals(), []) assemblers = ['as', 'gas'] def generate(env): """Add Builders and construction variables for as to an Environment.""" as_module.generate(env) env['AS'] = env.Detect(assemblers) or 'as' def exists(env): return env.Detect(assemblers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/f95.py0000644000175000017500000000376313606712377021267 0ustar kurtkurt"""engine.SCons.Tool.f95 Tool-specific initialization for the generic Posix f95 Fortran compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/f95.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Util import fortran from SCons.Tool.FortranCommon import add_all_to_env, add_f95_to_env compilers = ['f95'] def generate(env): add_all_to_env(env) add_f95_to_env(env) fcomp = env.Detect(compilers) or 'f95' env['F95'] = fcomp env['SHF95'] = fcomp env['FORTRAN'] = fcomp env['SHFORTRAN'] = fcomp def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/cc.py0000644000175000017500000001026413606712377021243 0ustar kurtkurt"""SCons.Tool.cc Tool-specific initialization for generic Posix C compilers. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/cc.py 4369 2009/09/19 15:58:29 scons" import SCons.Tool import SCons.Defaults import SCons.Util CSuffixes = ['.c', '.m'] if not SCons.Util.case_sensitive_suffixes('.c', '.C'): CSuffixes.append('.C') def add_common_cc_variables(env): """ Add underlying common "C compiler" variables that are used by multiple tools (specifically, c++). """ if '_CCCOMCOM' not in env: env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS' # It's a hack to test for darwin here, but the alternative # of creating an applecc.py to contain this seems overkill. # Maybe someday the Apple platform will require more setup and # this logic will be moved. env['FRAMEWORKS'] = SCons.Util.CLVar('') env['FRAMEWORKPATH'] = SCons.Util.CLVar('') if env['PLATFORM'] == 'darwin': env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH' if 'CCFLAGS' not in env: env['CCFLAGS'] = SCons.Util.CLVar('') if 'SHCCFLAGS' not in env: env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') def generate(env): """ Add Builders and construction variables for C compilers to an Environment. """ static_obj, shared_obj = SCons.Tool.createObjBuilders(env) for suffix in CSuffixes: static_obj.add_action(suffix, SCons.Defaults.CAction) shared_obj.add_action(suffix, SCons.Defaults.ShCAction) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) #<<<<<<< .working # # env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS' # # It's a hack to test for darwin here, but the alternative of creating # # an applecc.py to contain this seems overkill. Maybe someday the Apple # # platform will require more setup and this logic will be moved. # env['FRAMEWORKS'] = SCons.Util.CLVar('') # env['FRAMEWORKPATH'] = SCons.Util.CLVar('') # if env['PLATFORM'] == 'darwin': # env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH' #======= #>>>>>>> .merge-right.r1907 add_common_cc_variables(env) env['CC'] = 'cc' env['CFLAGS'] = SCons.Util.CLVar('') env['CCCOM'] = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES' env['SHCC'] = '$CC' env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS') env['SHCCCOM'] = '$SHCC -o $TARGET -c $SHCFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES' env['CPPDEFPREFIX'] = '-D' env['CPPDEFSUFFIX'] = '' env['INCPREFIX'] = '-I' env['INCSUFFIX'] = '' env['SHOBJSUFFIX'] = '.os' env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0 env['CFILESUFFIX'] = '.c' def exists(env): return env.Detect('cc') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/gnulink.py0000644000175000017500000000423013606712377022321 0ustar kurtkurt"""SCons.Tool.gnulink Tool-specific initialization for the gnu linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/gnulink.py 4369 2009/09/19 15:58:29 scons" import SCons.Util import link linkers = ['g++', 'gcc'] def generate(env): """Add Builders and construction variables for gnulink to an Environment.""" link.generate(env) if env['PLATFORM'] == 'hpux': env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared -fPIC') # __RPATH is set to $_RPATH in the platform specification if that # platform supports it. env.Append(LINKFLAGS=['$__RPATH']) env['RPATHPREFIX'] = '-Wl,-rpath=' env['RPATHSUFFIX'] = '' env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' def exists(env): return env.Detect(linkers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/f90.py0000644000175000017500000000376113606712377021260 0ustar kurtkurt"""engine.SCons.Tool.f90 Tool-specific initialization for the generic Posix f90 Fortran compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/f90.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Scanner.Fortran import SCons.Tool import SCons.Util from SCons.Tool.FortranCommon import add_all_to_env, add_f90_to_env compilers = ['f90'] def generate(env): add_all_to_env(env) add_f90_to_env(env) fc = env.Detect(compilers) or 'f90' env['F90'] = fc env['SHF90'] = fc env['FORTRAN'] = fc env['SHFORTRAN'] = fc def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/midl.py0000644000175000017500000000604613606712377021606 0ustar kurtkurt"""SCons.Tool.midl Tool-specific initialization for midl (Microsoft IDL compiler). There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/midl.py 4369 2009/09/19 15:58:29 scons" import string import SCons.Action import SCons.Builder import SCons.Defaults import SCons.Scanner.IDL import SCons.Util from MSCommon import msvs_exists def midl_emitter(target, source, env): """Produces a list of outputs from the MIDL compiler""" base, ext = SCons.Util.splitext(str(target[0])) tlb = target[0] incl = base + '.h' interface = base + '_i.c' t = [tlb, incl, interface] midlcom = env['MIDLCOM'] if string.find(midlcom, '/proxy') != -1: proxy = base + '_p.c' t.append(proxy) if string.find(midlcom, '/dlldata') != -1: dlldata = base + '_data.c' t.append(dlldata) return (t,source) idl_scanner = SCons.Scanner.IDL.IDLScan() midl_action = SCons.Action.Action('$MIDLCOM', '$MIDLCOMSTR') midl_builder = SCons.Builder.Builder(action = midl_action, src_suffix = '.idl', suffix='.tlb', emitter = midl_emitter, source_scanner = idl_scanner) def generate(env): """Add Builders and construction variables for midl to an Environment.""" env['MIDL'] = 'MIDL.EXE' env['MIDLFLAGS'] = SCons.Util.CLVar('/nologo') env['MIDLCOM'] = '$MIDL $MIDLFLAGS /tlb ${TARGETS[0]} /h ${TARGETS[1]} /iid ${TARGETS[2]} /proxy ${TARGETS[3]} /dlldata ${TARGETS[4]} $SOURCE 2> NUL' env['BUILDERS']['TypeLibrary'] = midl_builder def exists(env): return msvs_exists() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sgiar.py0000644000175000017500000000501213606712377021756 0ustar kurtkurt"""SCons.Tool.sgiar Tool-specific initialization for SGI ar (library archive). If CC exists, static libraries should be built with it, so the prelinker has a chance to resolve C++ template instantiations. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sgiar.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Util def generate(env): """Add Builders and construction variables for ar to an Environment.""" SCons.Tool.createStaticLibBuilder(env) if env.Detect('CC'): env['AR'] = 'CC' env['ARFLAGS'] = SCons.Util.CLVar('-ar') env['ARCOM'] = '$AR $ARFLAGS -o $TARGET $SOURCES' else: env['AR'] = 'ar' env['ARFLAGS'] = SCons.Util.CLVar('r') env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES' env['SHLINK'] = '$LINK' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') env['SHLINKCOM'] = '$SHLINK $SHLINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['LIBPREFIX'] = 'lib' env['LIBSUFFIX'] = '.a' def exists(env): return env.Detect('CC') or env.Detect('ar') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/c++.py0000644000175000017500000000645613606712377021236 0ustar kurtkurt"""SCons.Tool.c++ Tool-specific initialization for generic Posix C++ compilers. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/c++.py 4369 2009/09/19 15:58:29 scons" import os.path import SCons.Tool import SCons.Defaults import SCons.Util compilers = ['CC', 'c++'] CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++', '.mm'] if SCons.Util.case_sensitive_suffixes('.c', '.C'): CXXSuffixes.append('.C') def iscplusplus(source): if not source: # Source might be None for unusual cases like SConf. return 0 for s in source: if s.sources: ext = os.path.splitext(str(s.sources[0]))[1] if ext in CXXSuffixes: return 1 return 0 def generate(env): """ Add Builders and construction variables for Visual Age C++ compilers to an Environment. """ import SCons.Tool import SCons.Tool.cc static_obj, shared_obj = SCons.Tool.createObjBuilders(env) for suffix in CXXSuffixes: static_obj.add_action(suffix, SCons.Defaults.CXXAction) shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) SCons.Tool.cc.add_common_cc_variables(env) env['CXX'] = 'c++' env['CXXFLAGS'] = SCons.Util.CLVar('') env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM $SOURCES' env['SHCXX'] = '$CXX' env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') env['SHCXXCOM'] = '$SHCXX -o $TARGET -c $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES' env['CPPDEFPREFIX'] = '-D' env['CPPDEFSUFFIX'] = '' env['INCPREFIX'] = '-I' env['INCSUFFIX'] = '' env['SHOBJSUFFIX'] = '.os' env['OBJSUFFIX'] = '.o' env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0 env['CXXFILESUFFIX'] = '.cc' def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/icl.py0000644000175000017500000000363313606712377021427 0ustar kurtkurt"""engine.SCons.Tool.icl Tool-specific initialization for the Intel C/C++ compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/icl.py 4369 2009/09/19 15:58:29 scons" import SCons.Tool.intelc # This has been completely superceded by intelc.py, which can # handle both Windows and Linux versions. def generate(*args, **kw): """Add Builders and construction variables for icl to an Environment.""" return SCons.Tool.intelc.generate(*args, **kw) def exists(*args, **kw): return SCons.Tool.intelc.exists(*args, **kw) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/ipkg.py0000644000175000017500000000513213606712377021606 0ustar kurtkurt"""SCons.Tool.ipkg Tool-specific initialization for ipkg. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. The ipkg tool calls the ipkg-build. Its only argument should be the packages fake_root. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/ipkg.py 4369 2009/09/19 15:58:29 scons" import os import string import SCons.Builder def generate(env): """Add Builders and construction variables for ipkg to an Environment.""" try: bld = env['BUILDERS']['Ipkg'] except KeyError: bld = SCons.Builder.Builder( action = '$IPKGCOM', suffix = '$IPKGSUFFIX', source_scanner = None, target_scanner = None) env['BUILDERS']['Ipkg'] = bld env['IPKG'] = 'ipkg-build' env['IPKGCOM'] = '$IPKG $IPKGFLAGS ${SOURCE}' # TODO(1.5) #env['IPKGUSER'] = os.popen('id -un').read().strip() #env['IPKGGROUP'] = os.popen('id -gn').read().strip() env['IPKGUSER'] = string.strip(os.popen('id -un').read()) env['IPKGGROUP'] = string.strip(os.popen('id -gn').read()) env['IPKGFLAGS'] = SCons.Util.CLVar('-o $IPKGUSER -g $IPKGGROUP') env['IPKGSUFFIX'] = '.ipk' def exists(env): return env.Detect('ipkg-build') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/ar.py0000644000175000017500000000422013606712377021253 0ustar kurtkurt"""SCons.Tool.ar Tool-specific initialization for ar (library archive). There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/ar.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Util def generate(env): """Add Builders and construction variables for ar to an Environment.""" SCons.Tool.createStaticLibBuilder(env) env['AR'] = 'ar' env['ARFLAGS'] = SCons.Util.CLVar('rc') env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES' env['LIBPREFIX'] = 'lib' env['LIBSUFFIX'] = '.a' if env.Detect('ranlib'): env['RANLIB'] = 'ranlib' env['RANLIBFLAGS'] = SCons.Util.CLVar('') env['RANLIBCOM'] = '$RANLIB $RANLIBFLAGS $TARGET' def exists(env): return env.Detect('ar') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/rpm.py0000644000175000017500000001067513606712377021462 0ustar kurtkurt"""SCons.Tool.rpm Tool-specific initialization for rpm. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. The rpm tool calls the rpmbuild command. The first and only argument should a tar.gz consisting of the source file and a specfile. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/rpm.py 4369 2009/09/19 15:58:29 scons" import os import re import shutil import subprocess import SCons.Builder import SCons.Node.FS import SCons.Util import SCons.Action import SCons.Defaults def get_cmd(source, env): tar_file_with_included_specfile = source if SCons.Util.is_List(source): tar_file_with_included_specfile = source[0] return "%s %s %s"%(env['RPM'], env['RPMFLAGS'], tar_file_with_included_specfile.abspath ) def build_rpm(target, source, env): # create a temporary rpm build root. tmpdir = os.path.join( os.path.dirname( target[0].abspath ), 'rpmtemp' ) if os.path.exists(tmpdir): shutil.rmtree(tmpdir) # now create the mandatory rpm directory structure. for d in ['RPMS', 'SRPMS', 'SPECS', 'BUILD']: os.makedirs( os.path.join( tmpdir, d ) ) # set the topdir as an rpmflag. env.Prepend( RPMFLAGS = '--define \'_topdir %s\'' % tmpdir ) # now call rpmbuild to create the rpm package. handle = subprocess.Popen(get_cmd(source, env), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) output = handle.stdout.read() status = handle.wait() if status: raise SCons.Errors.BuildError( node=target[0], errstr=output, filename=str(target[0]) ) else: # XXX: assume that LC_ALL=c is set while running rpmbuild output_files = re.compile( 'Wrote: (.*)' ).findall( output ) for output, input in zip( output_files, target ): rpm_output = os.path.basename(output) expected = os.path.basename(input.get_path()) assert expected == rpm_output, "got %s but expected %s" % (rpm_output, expected) shutil.copy( output, input.abspath ) # cleanup before leaving. shutil.rmtree(tmpdir) return status def string_rpm(target, source, env): try: return env['RPMCOMSTR'] except KeyError: return get_cmd(source, env) rpmAction = SCons.Action.Action(build_rpm, string_rpm) RpmBuilder = SCons.Builder.Builder(action = SCons.Action.Action('$RPMCOM', '$RPMCOMSTR'), source_scanner = SCons.Defaults.DirScanner, suffix = '$RPMSUFFIX') def generate(env): """Add Builders and construction variables for rpm to an Environment.""" try: bld = env['BUILDERS']['Rpm'] except KeyError: bld = RpmBuilder env['BUILDERS']['Rpm'] = bld env.SetDefault(RPM = 'LC_ALL=c rpmbuild') env.SetDefault(RPMFLAGS = SCons.Util.CLVar('-ta')) env.SetDefault(RPMCOM = rpmAction) env.SetDefault(RPMSUFFIX = '.rpm') def exists(env): return env.Detect('rpmbuild') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/bcc32.py0000644000175000017500000000566213606712377021560 0ustar kurtkurt"""SCons.Tool.bcc32 XXX """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/bcc32.py 4369 2009/09/19 15:58:29 scons" import os import os.path import string import SCons.Defaults import SCons.Tool import SCons.Util def findIt(program, env): # First search in the SCons path and then the OS path: borwin = env.WhereIs(program) or SCons.Util.WhereIs(program) if borwin: dir = os.path.dirname(borwin) env.PrependENVPath('PATH', dir) return borwin def generate(env): findIt('bcc32', env) """Add Builders and construction variables for bcc to an Environment.""" static_obj, shared_obj = SCons.Tool.createObjBuilders(env) for suffix in ['.c', '.cpp']: static_obj.add_action(suffix, SCons.Defaults.CAction) shared_obj.add_action(suffix, SCons.Defaults.ShCAction) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter) env['CC'] = 'bcc32' env['CCFLAGS'] = SCons.Util.CLVar('') env['CFLAGS'] = SCons.Util.CLVar('') env['CCCOM'] = '$CC -q $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES' env['SHCC'] = '$CC' env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS') env['SHCCCOM'] = '$SHCC -WD $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES' env['CPPDEFPREFIX'] = '-D' env['CPPDEFSUFFIX'] = '' env['INCPREFIX'] = '-I' env['INCSUFFIX'] = '' env['SHOBJSUFFIX'] = '.dll' env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0 env['CFILESUFFIX'] = '.cpp' def exists(env): return findIt('bcc32', env) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sgicc.py0000644000175000017500000000351013606712377021742 0ustar kurtkurt"""SCons.Tool.sgicc Tool-specific initialization for MIPSPro cc on SGI. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sgicc.py 4369 2009/09/19 15:58:29 scons" import cc def generate(env): """Add Builders and construction variables for gcc to an Environment.""" cc.generate(env) env['CXX'] = 'CC' env['SHOBJSUFFIX'] = '.o' env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 def exists(env): return env.Detect('cc') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/JavaCommon.py0000644000175000017500000003064113606712377022711 0ustar kurtkurt"""SCons.Tool.JavaCommon Stuff for processing Java. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/JavaCommon.py 4369 2009/09/19 15:58:29 scons" import os import os.path import re import string java_parsing = 1 default_java_version = '1.4' if java_parsing: # Parse Java files for class names. # # This is a really cool parser from Charles Crain # that finds appropriate class names in Java source. # A regular expression that will find, in a java file: # newlines; # double-backslashes; # a single-line comment "//"; # single or double quotes preceeded by a backslash; # single quotes, double quotes, open or close braces, semi-colons, # periods, open or close parentheses; # floating-point numbers; # any alphanumeric token (keyword, class name, specifier); # any alphanumeric token surrounded by angle brackets (generics); # the multi-line comment begin and end tokens /* and */; # array declarations "[]". _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' + r'\d*\.\d*|[A-Za-z_][\w\$\.]*|<[A-Za-z_]\w+>|' + r'/\*|\*/|\[\])') class OuterState: """The initial state for parsing a Java file for classes, interfaces, and anonymous inner classes.""" def __init__(self, version=default_java_version): if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6', '5', '6'): msg = "Java version %s not supported" % version raise NotImplementedError(msg) self.version = version self.listClasses = [] self.listOutputs = [] self.stackBrackets = [] self.brackets = 0 self.nextAnon = 1 self.localClasses = [] self.stackAnonClassBrackets = [] self.anonStacksStack = [[0]] self.package = None def trace(self): pass def __getClassState(self): try: return self.classState except AttributeError: ret = ClassState(self) self.classState = ret return ret def __getPackageState(self): try: return self.packageState except AttributeError: ret = PackageState(self) self.packageState = ret return ret def __getAnonClassState(self): try: return self.anonState except AttributeError: self.outer_state = self ret = SkipState(1, AnonClassState(self)) self.anonState = ret return ret def __getSkipState(self): try: return self.skipState except AttributeError: ret = SkipState(1, self) self.skipState = ret return ret def __getAnonStack(self): return self.anonStacksStack[-1] def openBracket(self): self.brackets = self.brackets + 1 def closeBracket(self): self.brackets = self.brackets - 1 if len(self.stackBrackets) and \ self.brackets == self.stackBrackets[-1]: self.listOutputs.append(string.join(self.listClasses, '$')) self.localClasses.pop() self.listClasses.pop() self.anonStacksStack.pop() self.stackBrackets.pop() if len(self.stackAnonClassBrackets) and \ self.brackets == self.stackAnonClassBrackets[-1]: self.__getAnonStack().pop() self.stackAnonClassBrackets.pop() def parseToken(self, token): if token[:2] == '//': return IgnoreState('\n', self) elif token == '/*': return IgnoreState('*/', self) elif token == '{': self.openBracket() elif token == '}': self.closeBracket() elif token in [ '"', "'" ]: return IgnoreState(token, self) elif token == "new": # anonymous inner class if len(self.listClasses) > 0: return self.__getAnonClassState() return self.__getSkipState() # Skip the class name elif token in ['class', 'interface', 'enum']: if len(self.listClasses) == 0: self.nextAnon = 1 self.stackBrackets.append(self.brackets) return self.__getClassState() elif token == 'package': return self.__getPackageState() elif token == '.': # Skip the attribute, it might be named "class", in which # case we don't want to treat the following token as # an inner class name... return self.__getSkipState() return self def addAnonClass(self): """Add an anonymous inner class""" if self.version in ('1.1', '1.2', '1.3', '1.4'): clazz = self.listClasses[0] self.listOutputs.append('%s$%d' % (clazz, self.nextAnon)) elif self.version in ('1.5', '1.6', '5', '6'): self.stackAnonClassBrackets.append(self.brackets) className = [] className.extend(self.listClasses) self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1 for anon in self.__getAnonStack(): className.append(str(anon)) self.listOutputs.append(string.join(className, '$')) self.nextAnon = self.nextAnon + 1 self.__getAnonStack().append(0) def setPackage(self, package): self.package = package class AnonClassState: """A state that looks for anonymous inner classes.""" def __init__(self, old_state): # outer_state is always an instance of OuterState self.outer_state = old_state.outer_state self.old_state = old_state self.brace_level = 0 def parseToken(self, token): # This is an anonymous class if and only if the next # non-whitespace token is a bracket. Everything between # braces should be parsed as normal java code. if token[:2] == '//': return IgnoreState('\n', self) elif token == '/*': return IgnoreState('*/', self) elif token == '\n': return self elif token[0] == '<' and token[-1] == '>': return self elif token == '(': self.brace_level = self.brace_level + 1 return self if self.brace_level > 0: if token == 'new': # look further for anonymous inner class return SkipState(1, AnonClassState(self)) elif token in [ '"', "'" ]: return IgnoreState(token, self) elif token == ')': self.brace_level = self.brace_level - 1 return self if token == '{': self.outer_state.addAnonClass() return self.old_state.parseToken(token) class SkipState: """A state that will skip a specified number of tokens before reverting to the previous state.""" def __init__(self, tokens_to_skip, old_state): self.tokens_to_skip = tokens_to_skip self.old_state = old_state def parseToken(self, token): self.tokens_to_skip = self.tokens_to_skip - 1 if self.tokens_to_skip < 1: return self.old_state return self class ClassState: """A state we go into when we hit a class or interface keyword.""" def __init__(self, outer_state): # outer_state is always an instance of OuterState self.outer_state = outer_state def parseToken(self, token): # the next non-whitespace token should be the name of the class if token == '\n': return self # If that's an inner class which is declared in a method, it # requires an index prepended to the class-name, e.g. # 'Foo$1Inner' (Tigris Issue 2087) if self.outer_state.localClasses and \ self.outer_state.stackBrackets[-1] > \ self.outer_state.stackBrackets[-2]+1: locals = self.outer_state.localClasses[-1] try: idx = locals[token] locals[token] = locals[token]+1 except KeyError: locals[token] = 1 token = str(locals[token]) + token self.outer_state.localClasses.append({}) self.outer_state.listClasses.append(token) self.outer_state.anonStacksStack.append([0]) return self.outer_state class IgnoreState: """A state that will ignore all tokens until it gets to a specified token.""" def __init__(self, ignore_until, old_state): self.ignore_until = ignore_until self.old_state = old_state def parseToken(self, token): if self.ignore_until == token: return self.old_state return self class PackageState: """The state we enter when we encounter the package keyword. We assume the next token will be the package name.""" def __init__(self, outer_state): # outer_state is always an instance of OuterState self.outer_state = outer_state def parseToken(self, token): self.outer_state.setPackage(token) return self.outer_state def parse_java_file(fn, version=default_java_version): return parse_java(open(fn, 'r').read(), version) def parse_java(contents, version=default_java_version, trace=None): """Parse a .java file and return a double of package directory, plus a list of .class files that compiling that .java file will produce""" package = None initial = OuterState(version) currstate = initial for token in _reToken.findall(contents): # The regex produces a bunch of groups, but only one will # have anything in it. currstate = currstate.parseToken(token) if trace: trace(token, currstate) if initial.package: package = string.replace(initial.package, '.', os.sep) return (package, initial.listOutputs) else: # Don't actually parse Java files for class names. # # We might make this a configurable option in the future if # Java-file parsing takes too long (although it shouldn't relative # to how long the Java compiler itself seems to take...). def parse_java_file(fn): """ "Parse" a .java file. This actually just splits the file name, so the assumption here is that the file name matches the public class name, and that the path to the file is the same as the package name. """ return os.path.split(file) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/ilink.py0000644000175000017500000000411613606712377021763 0ustar kurtkurt"""SCons.Tool.ilink Tool-specific initialization for the OS/2 ilink linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/ilink.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Util def generate(env): """Add Builders and construction variables for ilink to an Environment.""" SCons.Tool.createProgBuilder(env) env['LINK'] = 'ilink' env['LINKFLAGS'] = SCons.Util.CLVar('') env['LINKCOM'] = '$LINK $LINKFLAGS /O:$TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['LIBDIRPREFIX']='/LIBPATH:' env['LIBDIRSUFFIX']='' env['LIBLINKPREFIX']='' env['LIBLINKSUFFIX']='$LIBSUFFIX' def exists(env): return env.Detect('ilink') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/aixf77.py0000644000175000017500000000524613606712377021767 0ustar kurtkurt"""engine.SCons.Tool.aixf77 Tool-specific initialization for IBM Visual Age f77 Fortran compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/aixf77.py 4369 2009/09/19 15:58:29 scons" import os.path #import SCons.Platform.aix import f77 # It would be good to look for the AIX F77 package the same way we're now # looking for the C and C++ packages. This should be as easy as supplying # the correct package names in the following list and uncommenting the # SCons.Platform.aix_get_xlc() call the in the function below. packages = [] def get_xlf77(env): xlf77 = env.get('F77', 'xlf77') xlf77_r = env.get('SHF77', 'xlf77_r') #return SCons.Platform.aix.get_xlc(env, xlf77, xlf77_r, packages) return (None, xlf77, xlf77_r, None) def generate(env): """ Add Builders and construction variables for the Visual Age FORTRAN compiler to an Environment. """ path, _f77, _shf77, version = get_xlf77(env) if path: _f77 = os.path.join(path, _f77) _shf77 = os.path.join(path, _shf77) f77.generate(env) env['F77'] = _f77 env['SHF77'] = _shf77 def exists(env): path, _f77, _shf77, version = get_xlf77(env) if path and _f77: xlf77 = os.path.join(path, _f77) if os.path.exists(xlf77): return xlf77 return None # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/rmic.py0000644000175000017500000001007013606712377021603 0ustar kurtkurt"""SCons.Tool.rmic Tool-specific initialization for rmic. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/rmic.py 4369 2009/09/19 15:58:29 scons" import os.path import string import SCons.Action import SCons.Builder import SCons.Node.FS import SCons.Util def emit_rmic_classes(target, source, env): """Create and return lists of Java RMI stub and skeleton class files to be created from a set of class files. """ class_suffix = env.get('JAVACLASSSUFFIX', '.class') classdir = env.get('JAVACLASSDIR') if not classdir: try: s = source[0] except IndexError: classdir = '.' else: try: classdir = s.attributes.java_classdir except AttributeError: classdir = '.' classdir = env.Dir(classdir).rdir() if str(classdir) == '.': c_ = None else: c_ = str(classdir) + os.sep slist = [] for src in source: try: classname = src.attributes.java_classname except AttributeError: classname = str(src) if c_ and classname[:len(c_)] == c_: classname = classname[len(c_):] if class_suffix and classname[:-len(class_suffix)] == class_suffix: classname = classname[-len(class_suffix):] s = src.rfile() s.attributes.java_classdir = classdir s.attributes.java_classname = classname slist.append(s) stub_suffixes = ['_Stub'] if env.get('JAVAVERSION') == '1.4': stub_suffixes.append('_Skel') tlist = [] for s in source: for suff in stub_suffixes: fname = string.replace(s.attributes.java_classname, '.', os.sep) + \ suff + class_suffix t = target[0].File(fname) t.attributes.java_lookupdir = target[0] tlist.append(t) return tlist, source RMICAction = SCons.Action.Action('$RMICCOM', '$RMICCOMSTR') RMICBuilder = SCons.Builder.Builder(action = RMICAction, emitter = emit_rmic_classes, src_suffix = '$JAVACLASSSUFFIX', target_factory = SCons.Node.FS.Dir, source_factory = SCons.Node.FS.File) def generate(env): """Add Builders and construction variables for rmic to an Environment.""" env['BUILDERS']['RMIC'] = RMICBuilder env['RMIC'] = 'rmic' env['RMICFLAGS'] = SCons.Util.CLVar('') env['RMICCOM'] = '$RMIC $RMICFLAGS -d ${TARGET.attributes.java_lookupdir} -classpath ${SOURCE.attributes.java_classdir} ${SOURCES.attributes.java_classname}' env['JAVACLASSSUFFIX'] = '.class' def exists(env): return env.Detect('rmic') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/Subversion.py0000644000175000017500000000476613606712377023027 0ustar kurtkurt"""SCons.Tool.Subversion.py Tool-specific initialization for Subversion. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/Subversion.py 4369 2009/09/19 15:58:29 scons" import os.path import SCons.Action import SCons.Builder import SCons.Util def generate(env): """Add a Builder factory function and construction variables for Subversion to an Environment.""" def SubversionFactory(repos, module='', env=env): """ """ # fail if repos is not an absolute path name? if module != '': module = os.path.join(module, '') act = SCons.Action.Action('$SVNCOM', '$SVNCOMSTR') return SCons.Builder.Builder(action = act, env = env, SVNREPOSITORY = repos, SVNMODULE = module) #setattr(env, 'Subversion', SubversionFactory) env.Subversion = SubversionFactory env['SVN'] = 'svn' env['SVNFLAGS'] = SCons.Util.CLVar('') env['SVNCOM'] = '$SVN $SVNFLAGS cat $SVNREPOSITORY/$SVNMODULE$TARGET > $TARGET' def exists(env): return env.Detect('svn') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/hplink.py0000644000175000017500000000451613606712377022146 0ustar kurtkurt"""SCons.Tool.hplink Tool-specific initialization for the HP linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/hplink.py 4369 2009/09/19 15:58:29 scons" import os import os.path import SCons.Util import link ccLinker = None # search for the acc compiler and linker front end try: dirs = os.listdir('/opt') except (IOError, OSError): # Not being able to read the directory because it doesn't exist # (IOError) or isn't readable (OSError) is okay. dirs = [] for dir in dirs: linker = '/opt/' + dir + '/bin/aCC' if os.path.exists(linker): ccLinker = linker break def generate(env): """ Add Builders and construction variables for Visual Age linker to an Environment. """ link.generate(env) env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,+s -Wl,+vnocompatwarnings') env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -b') env['SHLIBSUFFIX'] = '.sl' def exists(env): return ccLinker # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sgilink.py0000644000175000017500000000424313606712377022316 0ustar kurtkurt"""SCons.Tool.sgilink Tool-specific initialization for the SGI MIPSPro linker on SGI. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sgilink.py 4369 2009/09/19 15:58:29 scons" import SCons.Util import link linkers = ['CC', 'cc'] def generate(env): """Add Builders and construction variables for MIPSPro to an Environment.""" link.generate(env) env['LINK'] = env.Detect(linkers) or 'cc' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') # __RPATH is set to $_RPATH in the platform specification if that # platform supports it. env.Append(LINKFLAGS=['$__RPATH']) env['RPATHPREFIX'] = '-rpath ' env['RPATHSUFFIX'] = '' env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' def exists(env): return env.Detect(linkers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/linkloc.py0000644000175000017500000000762613606712377022321 0ustar kurtkurt"""SCons.Tool.linkloc Tool specification for the LinkLoc linker for the Phar Lap ETS embedded operating system. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/linkloc.py 4369 2009/09/19 15:58:29 scons" import os.path import re import SCons.Action import SCons.Defaults import SCons.Errors import SCons.Tool import SCons.Util from SCons.Tool.MSCommon import msvs_exists, merge_default_version from SCons.Tool.PharLapCommon import addPharLapPaths _re_linker_command = re.compile(r'(\s)@\s*([^\s]+)') def repl_linker_command(m): # Replaces any linker command file directives (e.g. "@foo.lnk") with # the actual contents of the file. try: f=open(m.group(2), "r") return m.group(1) + f.read() except IOError: # the linker should return an error if it can't # find the linker command file so we will remain quiet. # However, we will replace the @ with a # so we will not continue # to find it with recursive substitution return m.group(1) + '#' + m.group(2) class LinklocGenerator: def __init__(self, cmdline): self.cmdline = cmdline def __call__(self, env, target, source, for_signature): if for_signature: # Expand the contents of any linker command files recursively subs = 1 strsub = env.subst(self.cmdline, target=target, source=source) while subs: strsub, subs = _re_linker_command.subn(repl_linker_command, strsub) return strsub else: return "${TEMPFILE('" + self.cmdline + "')}" def generate(env): """Add Builders and construction variables for ar to an Environment.""" SCons.Tool.createSharedLibBuilder(env) SCons.Tool.createProgBuilder(env) env['SUBST_CMD_FILE'] = LinklocGenerator env['SHLINK'] = '$LINK' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS') env['SHLINKCOM'] = '${SUBST_CMD_FILE("$SHLINK $SHLINKFLAGS $_LIBDIRFLAGS $_LIBFLAGS -dll $TARGET $SOURCES")}' env['SHLIBEMITTER']= None env['LINK'] = "linkloc" env['LINKFLAGS'] = SCons.Util.CLVar('') env['LINKCOM'] = '${SUBST_CMD_FILE("$LINK $LINKFLAGS $_LIBDIRFLAGS $_LIBFLAGS -exe $TARGET $SOURCES")}' env['LIBDIRPREFIX']='-libpath ' env['LIBDIRSUFFIX']='' env['LIBLINKPREFIX']='-lib ' env['LIBLINKSUFFIX']='$LIBSUFFIX' # Set-up ms tools paths for default version merge_default_version(env) addPharLapPaths(env) def exists(env): if msvs_exists(): return env.Detect('linkloc') else: return 0 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sunc++.py0000644000175000017500000001114513606712377021753 0ustar kurtkurt"""SCons.Tool.sunc++ Tool-specific initialization for C++ on SunOS / Solaris. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sunc++.py 4369 2009/09/19 15:58:29 scons" import SCons import os import re import subprocess cplusplus = __import__('c++', globals(), locals(), []) package_info = {} def get_package_info(package_name, pkginfo, pkgchk): try: return package_info[package_name] except KeyError: version = None pathname = None try: sadm_contents = open('/var/sadm/install/contents', 'r').read() except EnvironmentError: pass else: sadm_re = re.compile('^(\S*/bin/CC)[= ].* %s$' % package_name, re.M) sadm_match = sadm_re.search(sadm_contents) if sadm_match: pathname = sadm_match.group(1) try: p = subprocess.Popen([pkginfo, '-l', package_name], stdout=subprocess.PIPE, stderr=open('/dev/null', 'w')) except EnvironmentError: pass else: pkginfo_contents = p.communicate()[0] version_re = re.compile('^ *VERSION:\s*(.*)$', re.M) version_match = version_re.search(pkginfo_contents) if version_match: version = version_match.group(1) if pathname is None: try: p = subprocess.Popen([pkgchk, '-l', package_name], stdout=subprocess.PIPE, stderr=open('/dev/null', 'w')) except EnvironmentError: pass else: pkgchk_contents = p.communicate()[0] pathname_re = re.compile(r'^Pathname:\s*(.*/bin/CC)$', re.M) pathname_match = pathname_re.search(pkgchk_contents) if pathname_match: pathname = pathname_match.group(1) package_info[package_name] = (version, pathname) return package_info[package_name] # use the package installer tool lslpp to figure out where cppc and what # version of it is installed def get_cppc(env): cxx = env.subst('$CXX') if cxx: cppcPath = os.path.dirname(cxx) else: cppcPath = None cppcVersion = None pkginfo = env.subst('$PKGINFO') pkgchk = env.subst('$PKGCHK') for package in ['SPROcpl']: path, version = get_package_info(package, pkginfo, pkgchk) if path and version: cppcPath, cppcVersion = path, version break return (cppcPath, 'CC', 'CC', cppcVersion) def generate(env): """Add Builders and construction variables for SunPRO C++.""" path, cxx, shcxx, version = get_cppc(env) if path: cxx = os.path.join(path, cxx) shcxx = os.path.join(path, shcxx) cplusplus.generate(env) env['CXX'] = cxx env['SHCXX'] = shcxx env['CXXVERSION'] = version env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -KPIC') env['SHOBJPREFIX'] = 'so_' env['SHOBJSUFFIX'] = '.o' def exists(env): path, cxx, shcxx, version = get_cppc(env) if path and cxx: cppc = os.path.join(path, cxx) if os.path.exists(cppc): return cppc return None # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/pdftex.py0000644000175000017500000000711313606712377022147 0ustar kurtkurt"""SCons.Tool.pdftex Tool-specific initialization for pdftex. Generates .pdf files from .tex files There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/pdftex.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Util import SCons.Tool.tex PDFTeXAction = None # This action might be needed more than once if we are dealing with # labels and bibtex. PDFLaTeXAction = None def PDFLaTeXAuxAction(target = None, source= None, env=None): result = SCons.Tool.tex.InternalLaTeXAuxAction( PDFLaTeXAction, target, source, env ) return result def PDFTeXLaTeXFunction(target = None, source= None, env=None): """A builder for TeX and LaTeX that scans the source file to decide the "flavor" of the source and then executes the appropriate program.""" if SCons.Tool.tex.is_LaTeX(source): result = PDFLaTeXAuxAction(target,source,env) if result != 0: print(env['PDFLATEX']," returned an error, check the log file") else: result = PDFTeXAction(target,source,env) if result != 0: print(env['PDFTEX']," returned an error, check the log file") return result PDFTeXLaTeXAction = None def generate(env): """Add Builders and construction variables for pdftex to an Environment.""" global PDFTeXAction if PDFTeXAction is None: PDFTeXAction = SCons.Action.Action('$PDFTEXCOM', '$PDFTEXCOMSTR') global PDFLaTeXAction if PDFLaTeXAction is None: PDFLaTeXAction = SCons.Action.Action("$PDFLATEXCOM", "$PDFLATEXCOMSTR") global PDFTeXLaTeXAction if PDFTeXLaTeXAction is None: PDFTeXLaTeXAction = SCons.Action.Action(PDFTeXLaTeXFunction, strfunction=SCons.Tool.tex.TeXLaTeXStrFunction) env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) import pdf pdf.generate(env) bld = env['BUILDERS']['PDF'] bld.add_action('.tex', PDFTeXLaTeXAction) bld.add_emitter('.tex', SCons.Tool.tex.tex_pdf_emitter) # Add the epstopdf builder after the pdftex builder # so pdftex is the default for no source suffix pdf.generate2(env) SCons.Tool.tex.generate_common(env) def exists(env): return env.Detect('pdftex') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/lex.py0000644000175000017500000000650213606712377021446 0ustar kurtkurt"""SCons.Tool.lex Tool-specific initialization for lex. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/lex.py 4369 2009/09/19 15:58:29 scons" import os.path import string import SCons.Action import SCons.Tool import SCons.Util LexAction = SCons.Action.Action("$LEXCOM", "$LEXCOMSTR") def lexEmitter(target, source, env): sourceBase, sourceExt = os.path.splitext(SCons.Util.to_String(source[0])) if sourceExt == ".lm": # If using Objective-C target = [sourceBase + ".m"] # the extension is ".m". # This emitter essentially tries to add to the target all extra # files generated by flex. # Different options that are used to trigger the creation of extra files. fileGenOptions = ["--header-file=", "--tables-file="] lexflags = env.subst("$LEXFLAGS", target=target, source=source) for option in SCons.Util.CLVar(lexflags): for fileGenOption in fileGenOptions: l = len(fileGenOption) if option[:l] == fileGenOption: # A file generating option is present, so add the # file name to the target list. fileName = string.strip(option[l:]) target.append(fileName) return (target, source) def generate(env): """Add Builders and construction variables for lex to an Environment.""" c_file, cxx_file = SCons.Tool.createCFileBuilders(env) # C c_file.add_action(".l", LexAction) c_file.add_emitter(".l", lexEmitter) c_file.add_action(".lex", LexAction) c_file.add_emitter(".lex", lexEmitter) # Objective-C cxx_file.add_action(".lm", LexAction) cxx_file.add_emitter(".lm", lexEmitter) # C++ cxx_file.add_action(".ll", LexAction) cxx_file.add_emitter(".ll", lexEmitter) env["LEX"] = env.Detect("flex") or "lex" env["LEXFLAGS"] = SCons.Util.CLVar("") env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET" def exists(env): return env.Detect(["flex", "lex"]) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/tex.py0000644000175000017500000007005613606712377021463 0ustar kurtkurt"""SCons.Tool.tex Tool-specific initialization for TeX. Generates .dvi files from .tex files There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/tex.py 4369 2009/09/19 15:58:29 scons" import os.path import re import string import shutil import SCons.Action import SCons.Node import SCons.Node.FS import SCons.Util import SCons.Scanner.LaTeX Verbose = False must_rerun_latex = True # these are files that just need to be checked for changes and then rerun latex check_suffixes = ['.toc', '.lof', '.lot', '.out', '.nav', '.snm'] # these are files that require bibtex or makeindex to be run when they change all_suffixes = check_suffixes + ['.bbl', '.idx', '.nlo', '.glo', '.acn'] # # regular expressions used to search for Latex features # or outputs that require rerunning latex # # search for all .aux files opened by latex (recorded in the .fls file) openout_aux_re = re.compile(r"INPUT *(.*\.aux)") #printindex_re = re.compile(r"^[^%]*\\printindex", re.MULTILINE) #printnomenclature_re = re.compile(r"^[^%]*\\printnomenclature", re.MULTILINE) #printglossary_re = re.compile(r"^[^%]*\\printglossary", re.MULTILINE) # search to find rerun warnings warning_rerun_str = '(^LaTeX Warning:.*Rerun)|(^Package \w+ Warning:.*Rerun)' warning_rerun_re = re.compile(warning_rerun_str, re.MULTILINE) # search to find citation rerun warnings rerun_citations_str = "^LaTeX Warning:.*\n.*Rerun to get citations correct" rerun_citations_re = re.compile(rerun_citations_str, re.MULTILINE) # search to find undefined references or citations warnings undefined_references_str = '(^LaTeX Warning:.*undefined references)|(^Package \w+ Warning:.*undefined citations)' undefined_references_re = re.compile(undefined_references_str, re.MULTILINE) # used by the emitter auxfile_re = re.compile(r".", re.MULTILINE) tableofcontents_re = re.compile(r"^[^%\n]*\\tableofcontents", re.MULTILINE) makeindex_re = re.compile(r"^[^%\n]*\\makeindex", re.MULTILINE) bibliography_re = re.compile(r"^[^%\n]*\\bibliography", re.MULTILINE) listoffigures_re = re.compile(r"^[^%\n]*\\listoffigures", re.MULTILINE) listoftables_re = re.compile(r"^[^%\n]*\\listoftables", re.MULTILINE) hyperref_re = re.compile(r"^[^%\n]*\\usepackage.*\{hyperref\}", re.MULTILINE) makenomenclature_re = re.compile(r"^[^%\n]*\\makenomenclature", re.MULTILINE) makeglossary_re = re.compile(r"^[^%\n]*\\makeglossary", re.MULTILINE) makeglossaries_re = re.compile(r"^[^%\n]*\\makeglossaries", re.MULTILINE) makeacronyms_re = re.compile(r"^[^%\n]*\\makeglossaries", re.MULTILINE) beamer_re = re.compile(r"^[^%\n]*\\documentclass\{beamer\}", re.MULTILINE) # search to find all files included by Latex include_re = re.compile(r'^[^%\n]*\\(?:include|input){([^}]*)}', re.MULTILINE) # search to find all graphics files included by Latex includegraphics_re = re.compile(r'^[^%\n]*\\(?:includegraphics(?:\[[^\]]+\])?){([^}]*)}', re.MULTILINE) # search to find all files opened by Latex (recorded in .log file) openout_re = re.compile(r"OUTPUT *(.*)") # list of graphics file extensions for TeX and LaTeX TexGraphics = SCons.Scanner.LaTeX.TexGraphics LatexGraphics = SCons.Scanner.LaTeX.LatexGraphics # An Action sufficient to build any generic tex file. TeXAction = None # An action to build a latex file. This action might be needed more # than once if we are dealing with labels and bibtex. LaTeXAction = None # An action to run BibTeX on a file. BibTeXAction = None # An action to run MakeIndex on a file. MakeIndexAction = None # An action to run MakeIndex (for nomencl) on a file. MakeNclAction = None # An action to run MakeIndex (for glossary) on a file. MakeGlossaryAction = None # An action to run MakeIndex (for acronyms) on a file. MakeAcronymsAction = None # Used as a return value of modify_env_var if the variable is not set. _null = SCons.Scanner.LaTeX._null modify_env_var = SCons.Scanner.LaTeX.modify_env_var def FindFile(name,suffixes,paths,env,requireExt=False): if requireExt: name,ext = SCons.Util.splitext(name) # if the user gave an extension use it. if ext: name = name + ext if Verbose: print(" searching for '%s' with extensions: " % name,suffixes) for path in paths: testName = os.path.join(path,name) if Verbose: print(" look for '%s'" % testName) if os.path.exists(testName): if Verbose: print(" found '%s'" % testName) return env.fs.File(testName) else: name_ext = SCons.Util.splitext(testName)[1] if name_ext: continue # if no suffix try adding those passed in for suffix in suffixes: testNameExt = testName + suffix if Verbose: print(" look for '%s'" % testNameExt) if os.path.exists(testNameExt): if Verbose: print(" found '%s'" % testNameExt) return env.fs.File(testNameExt) if Verbose: print(" did not find '%s'" % name) return None def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None): """A builder for LaTeX files that checks the output in the aux file and decides how many times to use LaTeXAction, and BibTeXAction.""" global must_rerun_latex # This routine is called with two actions. In this file for DVI builds # with LaTeXAction and from the pdflatex.py with PDFLaTeXAction # set this up now for the case where the user requests a different extension # for the target filename if (XXXLaTeXAction == LaTeXAction): callerSuffix = ".dvi" else: callerSuffix = env['PDFSUFFIX'] basename = SCons.Util.splitext(str(source[0]))[0] basedir = os.path.split(str(source[0]))[0] basefile = os.path.split(str(basename))[1] abspath = os.path.abspath(basedir) targetext = os.path.splitext(str(target[0]))[1] targetdir = os.path.split(str(target[0]))[0] saved_env = {} for var in SCons.Scanner.LaTeX.LaTeX.env_variables: saved_env[var] = modify_env_var(env, var, abspath) # Create base file names with the target directory since the auxiliary files # will be made there. That's because the *COM variables have the cd # command in the prolog. We check # for the existence of files before opening them--even ones like the # aux file that TeX always creates--to make it possible to write tests # with stubs that don't necessarily generate all of the same files. targetbase = os.path.join(targetdir, basefile) # if there is a \makeindex there will be a .idx and thus # we have to run makeindex at least once to keep the build # happy even if there is no index. # Same for glossaries and nomenclature src_content = source[0].get_text_contents() run_makeindex = makeindex_re.search(src_content) and not os.path.exists(targetbase + '.idx') run_nomenclature = makenomenclature_re.search(src_content) and not os.path.exists(targetbase + '.nlo') run_glossary = makeglossary_re.search(src_content) and not os.path.exists(targetbase + '.glo') run_glossaries = makeglossaries_re.search(src_content) and not os.path.exists(targetbase + '.glo') run_acronyms = makeacronyms_re.search(src_content) and not os.path.exists(targetbase + '.acn') saved_hashes = {} suffix_nodes = {} for suffix in all_suffixes: theNode = env.fs.File(targetbase + suffix) suffix_nodes[suffix] = theNode saved_hashes[suffix] = theNode.get_csig() if Verbose: print("hashes: ",saved_hashes) must_rerun_latex = True # # routine to update MD5 hash and compare # # TODO(1.5): nested scopes def check_MD5(filenode, suffix, saved_hashes=saved_hashes, targetbase=targetbase): global must_rerun_latex # two calls to clear old csig filenode.clear_memoized_values() filenode.ninfo = filenode.new_ninfo() new_md5 = filenode.get_csig() if saved_hashes[suffix] == new_md5: if Verbose: print("file %s not changed" % (targetbase+suffix)) return False # unchanged saved_hashes[suffix] = new_md5 must_rerun_latex = True if Verbose: print("file %s changed, rerunning Latex, new hash = " % (targetbase+suffix), new_md5) return True # changed # generate the file name that latex will generate resultfilename = targetbase + callerSuffix count = 0 while (must_rerun_latex and count < int(env.subst('$LATEXRETRIES'))) : result = XXXLaTeXAction(target, source, env) if result != 0: return result count = count + 1 must_rerun_latex = False # Decide if various things need to be run, or run again. # Read the log file to find warnings/errors logfilename = targetbase + '.log' logContent = '' if os.path.exists(logfilename): logContent = open(logfilename, "rb").read() # Read the fls file to find all .aux files flsfilename = targetbase + '.fls' flsContent = '' auxfiles = [] if os.path.exists(flsfilename): flsContent = open(flsfilename, "rb").read() auxfiles = openout_aux_re.findall(flsContent) if Verbose: print("auxfiles ",auxfiles) # Now decide if bibtex will need to be run. # The information that bibtex reads from the .aux file is # pass-independent. If we find (below) that the .bbl file is unchanged, # then the last latex saw a correct bibliography. # Therefore only do this on the first pass if count == 1: for auxfilename in auxfiles: target_aux = os.path.join(targetdir, auxfilename) if os.path.exists(target_aux): content = open(target_aux, "rb").read() if string.find(content, "bibdata") != -1: if Verbose: print("Need to run bibtex") bibfile = env.fs.File(targetbase) result = BibTeXAction(bibfile, bibfile, env) if result != 0: print(env['BIBTEX']," returned an error, check the blg file") return result must_rerun_latex = check_MD5(suffix_nodes['.bbl'],'.bbl') break # Now decide if latex will need to be run again due to index. if check_MD5(suffix_nodes['.idx'],'.idx') or (count == 1 and run_makeindex): # We must run makeindex if Verbose: print("Need to run makeindex") idxfile = suffix_nodes['.idx'] result = MakeIndexAction(idxfile, idxfile, env) if result != 0: print(env['MAKEINDEX']," returned an error, check the ilg file") return result # TO-DO: need to add a way for the user to extend this list for whatever # auxiliary files they create in other (or their own) packages # Harder is case is where an action needs to be called -- that should be rare (I hope?) for index in check_suffixes: check_MD5(suffix_nodes[index],index) # Now decide if latex will need to be run again due to nomenclature. if check_MD5(suffix_nodes['.nlo'],'.nlo') or (count == 1 and run_nomenclature): # We must run makeindex if Verbose: print("Need to run makeindex for nomenclature") nclfile = suffix_nodes['.nlo'] result = MakeNclAction(nclfile, nclfile, env) if result != 0: print(env['MAKENCL']," (nomenclature) returned an error, check the nlg file") #return result # Now decide if latex will need to be run again due to glossary. if check_MD5(suffix_nodes['.glo'],'.glo') or (count == 1 and run_glossaries) or (count == 1 and run_glossary): # We must run makeindex if Verbose: print("Need to run makeindex for glossary") glofile = suffix_nodes['.glo'] result = MakeGlossaryAction(glofile, glofile, env) if result != 0: print(env['MAKEGLOSSARY']," (glossary) returned an error, check the glg file") #return result # Now decide if latex will need to be run again due to acronyms. if check_MD5(suffix_nodes['.acn'],'.acn') or (count == 1 and run_acronyms): # We must run makeindex if Verbose: print("Need to run makeindex for acronyms") acrfile = suffix_nodes['.acn'] result = MakeAcronymsAction(acrfile, acrfile, env) if result != 0: print(env['MAKEACRONYMS']," (acronymns) returned an error, check the alg file") return result # Now decide if latex needs to be run yet again to resolve warnings. if warning_rerun_re.search(logContent): must_rerun_latex = True if Verbose: print("rerun Latex due to latex or package rerun warning") if rerun_citations_re.search(logContent): must_rerun_latex = True if Verbose: print("rerun Latex due to 'Rerun to get citations correct' warning") if undefined_references_re.search(logContent): must_rerun_latex = True if Verbose: print("rerun Latex due to undefined references or citations") if (count >= int(env.subst('$LATEXRETRIES')) and must_rerun_latex): print("reached max number of retries on Latex ,",int(env.subst('$LATEXRETRIES'))) # end of while loop # rename Latex's output to what the target name is if not (str(target[0]) == resultfilename and os.path.exists(resultfilename)): if os.path.exists(resultfilename): print("move %s to %s" % (resultfilename, str(target[0]), )) shutil.move(resultfilename,str(target[0])) # Original comment (when TEXPICTS was not restored): # The TEXPICTS enviroment variable is needed by a dvi -> pdf step # later on Mac OSX so leave it # # It is also used when searching for pictures (implicit dependencies). # Why not set the variable again in the respective builder instead # of leaving local modifications in the environment? What if multiple # latex builds in different directories need different TEXPICTS? for var in SCons.Scanner.LaTeX.LaTeX.env_variables: if var == 'TEXPICTS': continue if saved_env[var] is _null: try: del env['ENV'][var] except KeyError: pass # was never set else: env['ENV'][var] = saved_env[var] return result def LaTeXAuxAction(target = None, source= None, env=None): result = InternalLaTeXAuxAction( LaTeXAction, target, source, env ) return result LaTeX_re = re.compile("\\\\document(style|class)") def is_LaTeX(flist): # Scan a file list to decide if it's TeX- or LaTeX-flavored. for f in flist: content = f.get_text_contents() if LaTeX_re.search(content): return 1 return 0 def TeXLaTeXFunction(target = None, source= None, env=None): """A builder for TeX and LaTeX that scans the source file to decide the "flavor" of the source and then executes the appropriate program.""" if is_LaTeX(source): result = LaTeXAuxAction(target,source,env) if result != 0: print(env['LATEX']," returned an error, check the log file") else: result = TeXAction(target,source,env) if result != 0: print(env['TEX']," returned an error, check the log file") return result def TeXLaTeXStrFunction(target = None, source= None, env=None): """A strfunction for TeX and LaTeX that scans the source file to decide the "flavor" of the source and then returns the appropriate command string.""" if env.GetOption("no_exec"): if is_LaTeX(source): result = env.subst('$LATEXCOM',0,target,source)+" ..." else: result = env.subst("$TEXCOM",0,target,source)+" ..." else: result = '' return result def tex_eps_emitter(target, source, env): """An emitter for TeX and LaTeX sources when executing tex or latex. It will accept .ps and .eps graphics files """ (target, source) = tex_emitter_core(target, source, env, TexGraphics) return (target, source) def tex_pdf_emitter(target, source, env): """An emitter for TeX and LaTeX sources when executing pdftex or pdflatex. It will accept graphics files of types .pdf, .jpg, .png, .gif, and .tif """ (target, source) = tex_emitter_core(target, source, env, LatexGraphics) return (target, source) def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir): # for theFile (a Node) update any file_tests and search for graphics files # then find all included files and call ScanFiles for each of them content = theFile.get_text_contents() if Verbose: print(" scanning ",str(theFile)) for i in range(len(file_tests_search)): if file_tests[i][0] is None: file_tests[i][0] = file_tests_search[i].search(content) # recursively call this on each of the included files inc_files = [ ] inc_files.extend( include_re.findall(content) ) if Verbose: print("files included by '%s': "%str(theFile),inc_files) # inc_files is list of file names as given. need to find them # using TEXINPUTS paths. for src in inc_files: srcNode = srcNode = FindFile(src,['.tex','.ltx','.latex'],paths,env,requireExt=False) if srcNode is not None: file_test = ScanFiles(srcNode, target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir) if Verbose: print(" done scanning ",str(theFile)) return file_tests def tex_emitter_core(target, source, env, graphics_extensions): """An emitter for TeX and LaTeX sources. For LaTeX sources we try and find the common created files that are needed on subsequent runs of latex to finish tables of contents, bibliographies, indices, lists of figures, and hyperlink references. """ basename = SCons.Util.splitext(str(source[0]))[0] basefile = os.path.split(str(basename))[1] targetdir = os.path.split(str(target[0]))[0] targetbase = os.path.join(targetdir, basefile) basedir = os.path.split(str(source[0]))[0] abspath = os.path.abspath(basedir) target[0].attributes.path = abspath # # file names we will make use of in searching the sources and log file # emit_suffixes = ['.aux', '.log', '.ilg', '.blg', '.nls', '.nlg', '.gls', '.glg', '.alg'] + all_suffixes auxfilename = targetbase + '.aux' logfilename = targetbase + '.log' flsfilename = targetbase + '.fls' env.SideEffect(auxfilename,target[0]) env.SideEffect(logfilename,target[0]) env.SideEffect(flsfilename,target[0]) if Verbose: print("side effect :",auxfilename,logfilename,flsfilename) env.Clean(target[0],auxfilename) env.Clean(target[0],logfilename) env.Clean(target[0],flsfilename) content = source[0].get_text_contents() idx_exists = os.path.exists(targetbase + '.idx') nlo_exists = os.path.exists(targetbase + '.nlo') glo_exists = os.path.exists(targetbase + '.glo') acr_exists = os.path.exists(targetbase + '.acn') # set up list with the regular expressions # we use to find features used file_tests_search = [auxfile_re, makeindex_re, bibliography_re, tableofcontents_re, listoffigures_re, listoftables_re, hyperref_re, makenomenclature_re, makeglossary_re, makeglossaries_re, makeacronyms_re, beamer_re ] # set up list with the file suffixes that need emitting # when a feature is found file_tests_suff = [['.aux'], ['.idx', '.ind', '.ilg'], ['.bbl', '.blg'], ['.toc'], ['.lof'], ['.lot'], ['.out'], ['.nlo', '.nls', '.nlg'], ['.glo', '.gls', '.glg'], ['.glo', '.gls', '.glg'], ['.acn', '.acr', '.alg'], ['.nav', '.snm', '.out', '.toc'] ] # build the list of lists file_tests = [] for i in range(len(file_tests_search)): file_tests.append( [None, file_tests_suff[i]] ) # TO-DO: need to add a way for the user to extend this list for whatever # auxiliary files they create in other (or their own) packages # get path list from both env['TEXINPUTS'] and env['ENV']['TEXINPUTS'] savedpath = modify_env_var(env, 'TEXINPUTS', abspath) paths = env['ENV']['TEXINPUTS'] if SCons.Util.is_List(paths): pass else: # Split at os.pathsep to convert into absolute path # TODO(1.5) #paths = paths.split(os.pathsep) paths = string.split(paths, os.pathsep) # now that we have the path list restore the env if savedpath is _null: try: del env['ENV']['TEXINPUTS'] except KeyError: pass # was never set else: env['ENV']['TEXINPUTS'] = savedpath if Verbose: print("search path ",paths) file_tests = ScanFiles(source[0], target, paths, file_tests, file_tests_search, env, graphics_extensions, targetdir) for (theSearch,suffix_list) in file_tests: if theSearch: for suffix in suffix_list: env.SideEffect(targetbase + suffix,target[0]) if Verbose: print("side effect :",targetbase + suffix) env.Clean(target[0],targetbase + suffix) # read fls file to get all other files that latex creates and will read on the next pass # remove files from list that we explicitly dealt with above if os.path.exists(flsfilename): content = open(flsfilename, "rb").read() out_files = openout_re.findall(content) myfiles = [auxfilename, logfilename, flsfilename, targetbase+'.dvi',targetbase+'.pdf'] for filename in out_files[:]: if filename in myfiles: out_files.remove(filename) env.SideEffect(out_files,target[0]) if Verbose: print("side effect :",out_files) env.Clean(target[0],out_files) return (target, source) TeXLaTeXAction = None def generate(env): """Add Builders and construction variables for TeX to an Environment.""" global TeXLaTeXAction if TeXLaTeXAction is None: TeXLaTeXAction = SCons.Action.Action(TeXLaTeXFunction, strfunction=TeXLaTeXStrFunction) env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) generate_common(env) import dvi dvi.generate(env) bld = env['BUILDERS']['DVI'] bld.add_action('.tex', TeXLaTeXAction) bld.add_emitter('.tex', tex_eps_emitter) def generate_common(env): """Add internal Builders and construction variables for LaTeX to an Environment.""" # A generic tex file Action, sufficient for all tex files. global TeXAction if TeXAction is None: TeXAction = SCons.Action.Action("$TEXCOM", "$TEXCOMSTR") # An Action to build a latex file. This might be needed more # than once if we are dealing with labels and bibtex. global LaTeXAction if LaTeXAction is None: LaTeXAction = SCons.Action.Action("$LATEXCOM", "$LATEXCOMSTR") # Define an action to run BibTeX on a file. global BibTeXAction if BibTeXAction is None: BibTeXAction = SCons.Action.Action("$BIBTEXCOM", "$BIBTEXCOMSTR") # Define an action to run MakeIndex on a file. global MakeIndexAction if MakeIndexAction is None: MakeIndexAction = SCons.Action.Action("$MAKEINDEXCOM", "$MAKEINDEXCOMSTR") # Define an action to run MakeIndex on a file for nomenclatures. global MakeNclAction if MakeNclAction is None: MakeNclAction = SCons.Action.Action("$MAKENCLCOM", "$MAKENCLCOMSTR") # Define an action to run MakeIndex on a file for glossaries. global MakeGlossaryAction if MakeGlossaryAction is None: MakeGlossaryAction = SCons.Action.Action("$MAKEGLOSSARYCOM", "$MAKEGLOSSARYCOMSTR") # Define an action to run MakeIndex on a file for acronyms. global MakeAcronymsAction if MakeAcronymsAction is None: MakeAcronymsAction = SCons.Action.Action("$MAKEACRONYMSCOM", "$MAKEACRONYMSCOMSTR") env['TEX'] = 'tex' env['TEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder') env['TEXCOM'] = 'cd ${TARGET.dir} && $TEX $TEXFLAGS ${SOURCE.file}' env['PDFTEX'] = 'pdftex' env['PDFTEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder') env['PDFTEXCOM'] = 'cd ${TARGET.dir} && $PDFTEX $PDFTEXFLAGS ${SOURCE.file}' env['LATEX'] = 'latex' env['LATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder') env['LATEXCOM'] = 'cd ${TARGET.dir} && $LATEX $LATEXFLAGS ${SOURCE.file}' env['LATEXRETRIES'] = 3 env['PDFLATEX'] = 'pdflatex' env['PDFLATEXFLAGS'] = SCons.Util.CLVar('-interaction=nonstopmode -recorder') env['PDFLATEXCOM'] = 'cd ${TARGET.dir} && $PDFLATEX $PDFLATEXFLAGS ${SOURCE.file}' env['BIBTEX'] = 'bibtex' env['BIBTEXFLAGS'] = SCons.Util.CLVar('') env['BIBTEXCOM'] = 'cd ${TARGET.dir} && $BIBTEX $BIBTEXFLAGS ${SOURCE.filebase}' env['MAKEINDEX'] = 'makeindex' env['MAKEINDEXFLAGS'] = SCons.Util.CLVar('') env['MAKEINDEXCOM'] = 'cd ${TARGET.dir} && $MAKEINDEX $MAKEINDEXFLAGS ${SOURCE.file}' env['MAKEGLOSSARY'] = 'makeindex' env['MAKEGLOSSARYSTYLE'] = '${SOURCE.filebase}.ist' env['MAKEGLOSSARYFLAGS'] = SCons.Util.CLVar('-s ${MAKEGLOSSARYSTYLE} -t ${SOURCE.filebase}.glg') env['MAKEGLOSSARYCOM'] = 'cd ${TARGET.dir} && $MAKEGLOSSARY ${SOURCE.filebase}.glo $MAKEGLOSSARYFLAGS -o ${SOURCE.filebase}.gls' env['MAKEACRONYMS'] = 'makeindex' env['MAKEACRONYMSSTYLE'] = '${SOURCE.filebase}.ist' env['MAKEACRONYMSFLAGS'] = SCons.Util.CLVar('-s ${MAKEACRONYMSSTYLE} -t ${SOURCE.filebase}.alg') env['MAKEACRONYMSCOM'] = 'cd ${TARGET.dir} && $MAKEACRONYMS ${SOURCE.filebase}.acn $MAKEACRONYMSFLAGS -o ${SOURCE.filebase}.acr' env['MAKENCL'] = 'makeindex' env['MAKENCLSTYLE'] = 'nomencl.ist' env['MAKENCLFLAGS'] = '-s ${MAKENCLSTYLE} -t ${SOURCE.filebase}.nlg' env['MAKENCLCOM'] = 'cd ${TARGET.dir} && $MAKENCL ${SOURCE.filebase}.nlo $MAKENCLFLAGS -o ${SOURCE.filebase}.nls' def exists(env): return env.Detect('tex') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sunar.py0000644000175000017500000000476713606712377022021 0ustar kurtkurt"""engine.SCons.Tool.sunar Tool-specific initialization for Solaris (Forte) ar (library archive). If CC exists, static libraries should be built with it, so that template instantians can be resolved. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sunar.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Util def generate(env): """Add Builders and construction variables for ar to an Environment.""" SCons.Tool.createStaticLibBuilder(env) if env.Detect('CC'): env['AR'] = 'CC' env['ARFLAGS'] = SCons.Util.CLVar('-xar') env['ARCOM'] = '$AR $ARFLAGS -o $TARGET $SOURCES' else: env['AR'] = 'ar' env['ARFLAGS'] = SCons.Util.CLVar('r') env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES' env['SHLINK'] = '$LINK' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -G') env['SHLINKCOM'] = '$SHLINK $SHLINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['LIBPREFIX'] = 'lib' env['LIBSUFFIX'] = '.a' def exists(env): return env.Detect('CC') or env.Detect('ar') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/dmd.py0000644000175000017500000002066513606712377021430 0ustar kurtkurt"""SCons.Tool.dmd Tool-specific initialization for the Digital Mars D compiler. (http://digitalmars.com/d) Coded by Andy Friesen (andy@ikagames.com) 15 November 2003 There are a number of problems with this script at this point in time. The one that irritates me the most is the Windows linker setup. The D linker doesn't have a way to add lib paths on the commandline, as far as I can see. You have to specify paths relative to the SConscript or use absolute paths. To hack around it, add '#/blah'. This will link blah.lib from the directory where SConstruct resides. Compiler variables: DC - The name of the D compiler to use. Defaults to dmd or gdmd, whichever is found. DPATH - List of paths to search for import modules. DVERSIONS - List of version tags to enable when compiling. DDEBUG - List of debug tags to enable when compiling. Linker related variables: LIBS - List of library files to link in. DLINK - Name of the linker to use. Defaults to dmd or gdmd. DLINKFLAGS - List of linker flags. Lib tool variables: DLIB - Name of the lib tool to use. Defaults to lib. DLIBFLAGS - List of flags to pass to the lib tool. LIBS - Same as for the linker. (libraries to pull into the .lib) """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/dmd.py 4369 2009/09/19 15:58:29 scons" import os import string import SCons.Action import SCons.Builder import SCons.Defaults import SCons.Scanner.D import SCons.Tool # Adapted from c++.py def isD(source): if not source: return 0 for s in source: if s.sources: ext = os.path.splitext(str(s.sources[0]))[1] if ext == '.d': return 1 return 0 smart_link = {} smart_lib = {} def generate(env): global smart_link global smart_lib static_obj, shared_obj = SCons.Tool.createObjBuilders(env) DAction = SCons.Action.Action('$DCOM', '$DCOMSTR') static_obj.add_action('.d', DAction) shared_obj.add_action('.d', DAction) static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter) shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter) dc = env.Detect(['dmd', 'gdmd']) env['DC'] = dc env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of$TARGET $SOURCES' env['_DINCFLAGS'] = '$( ${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' env['_DVERFLAGS'] = '$( ${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)} $)' env['_DDEBUGFLAGS'] = '$( ${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)} $)' env['_DFLAGS'] = '$( ${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)} $)' env['DPATH'] = ['#/'] env['DFLAGS'] = [] env['DVERSIONS'] = [] env['DDEBUG'] = [] if dc: # Add the path to the standard library. # This is merely for the convenience of the dependency scanner. dmd_path = env.WhereIs(dc) if dmd_path: x = string.rindex(dmd_path, dc) phobosDir = dmd_path[:x] + '/../src/phobos' if os.path.isdir(phobosDir): env.Append(DPATH = [phobosDir]) env['DINCPREFIX'] = '-I' env['DINCSUFFIX'] = '' env['DVERPREFIX'] = '-version=' env['DVERSUFFIX'] = '' env['DDEBUGPREFIX'] = '-debug=' env['DDEBUGSUFFIX'] = '' env['DFLAGPREFIX'] = '-' env['DFLAGSUFFIX'] = '' env['DFILESUFFIX'] = '.d' # Need to use the Digital Mars linker/lib on windows. # *nix can just use GNU link. if env['PLATFORM'] == 'win32': env['DLINK'] = '$DC' env['DLINKCOM'] = '$DLINK -of$TARGET $SOURCES $DFLAGS $DLINKFLAGS $_DLINKLIBFLAGS' env['DLIB'] = 'lib' env['DLIBCOM'] = '$DLIB $_DLIBFLAGS -c $TARGET $SOURCES $_DLINKLIBFLAGS' env['_DLINKLIBFLAGS'] = '$( ${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' env['_DLIBFLAGS'] = '$( ${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)} $)' env['DLINKFLAGS'] = [] env['DLIBLINKPREFIX'] = '' env['DLIBLINKSUFFIX'] = '.lib' env['DLIBFLAGPREFIX'] = '-' env['DLIBFLAGSUFFIX'] = '' env['DLINKFLAGPREFIX'] = '-' env['DLINKFLAGSUFFIX'] = '' SCons.Tool.createStaticLibBuilder(env) # Basically, we hijack the link and ar builders with our own. # these builders check for the presence of D source, and swap out # the system's defaults for the Digital Mars tools. If there's no D # source, then we silently return the previous settings. linkcom = env.get('LINKCOM') try: env['SMART_LINKCOM'] = smart_link[linkcom] except KeyError: def _smartLink(source, target, env, for_signature, defaultLinker=linkcom): if isD(source): # XXX I'm not sure how to add a $DLINKCOMSTR variable # so that it works with this _smartLink() logic, # and I don't have a D compiler/linker to try it out, # so we'll leave it alone for now. return '$DLINKCOM' else: return defaultLinker env['SMART_LINKCOM'] = smart_link[linkcom] = _smartLink arcom = env.get('ARCOM') try: env['SMART_ARCOM'] = smart_lib[arcom] except KeyError: def _smartLib(source, target, env, for_signature, defaultLib=arcom): if isD(source): # XXX I'm not sure how to add a $DLIBCOMSTR variable # so that it works with this _smartLib() logic, and # I don't have a D compiler/archiver to try it out, # so we'll leave it alone for now. return '$DLIBCOM' else: return defaultLib env['SMART_ARCOM'] = smart_lib[arcom] = _smartLib # It is worth noting that the final space in these strings is # absolutely pivotal. SCons sees these as actions and not generators # if it is not there. (very bad) env['ARCOM'] = '$SMART_ARCOM ' env['LINKCOM'] = '$SMART_LINKCOM ' else: # assuming linux linkcom = env.get('LINKCOM') try: env['SMART_LINKCOM'] = smart_link[linkcom] except KeyError: def _smartLink(source, target, env, for_signature, defaultLinker=linkcom, dc=dc): if isD(source): try: libs = env['LIBS'] except KeyError: libs = [] if 'phobos' not in libs and 'gphobos' not in libs: if dc is 'dmd': env.Append(LIBS = ['phobos']) elif dc is 'gdmd': env.Append(LIBS = ['gphobos']) if 'pthread' not in libs: env.Append(LIBS = ['pthread']) if 'm' not in libs: env.Append(LIBS = ['m']) return defaultLinker env['SMART_LINKCOM'] = smart_link[linkcom] = _smartLink env['LINKCOM'] = '$SMART_LINKCOM ' def exists(env): return env.Detect(['dmd', 'gdmd']) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/mwld.py0000644000175000017500000000705013606712377021620 0ustar kurtkurt"""SCons.Tool.mwld Tool-specific initialization for the Metrowerks CodeWarrior linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/mwld.py 4369 2009/09/19 15:58:29 scons" import SCons.Tool def generate(env): """Add Builders and construction variables for lib to an Environment.""" SCons.Tool.createStaticLibBuilder(env) SCons.Tool.createSharedLibBuilder(env) SCons.Tool.createProgBuilder(env) env['AR'] = 'mwld' env['ARCOM'] = '$AR $ARFLAGS -library -o $TARGET $SOURCES' env['LIBDIRPREFIX'] = '-L' env['LIBDIRSUFFIX'] = '' env['LIBLINKPREFIX'] = '-l' env['LIBLINKSUFFIX'] = '.lib' env['LINK'] = 'mwld' env['LINKCOM'] = '$LINK $LINKFLAGS -o $TARGET $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['SHLINK'] = '$LINK' env['SHLINKFLAGS'] = '$LINKFLAGS' env['SHLINKCOM'] = shlib_action env['SHLIBEMITTER']= shlib_emitter def exists(env): import SCons.Tool.mwcc return SCons.Tool.mwcc.set_vars(env) def shlib_generator(target, source, env, for_signature): cmd = ['$SHLINK', '$SHLINKFLAGS', '-shared'] no_import_lib = env.get('no_import_lib', 0) if no_import_lib: cmd.extend('-noimplib') dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') if dll: cmd.extend(['-o', dll]) implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') if implib: cmd.extend(['-implib', implib.get_string(for_signature)]) cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) return [cmd] def shlib_emitter(target, source, env): dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') no_import_lib = env.get('no_import_lib', 0) if not dll: raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")) if not no_import_lib and \ not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'): # Append an import library to the list of targets. target.append(env.ReplaceIxes(dll, 'SHLIBPREFIX', 'SHLIBSUFFIX', 'LIBPREFIX', 'LIBSUFFIX')) return target, source shlib_action = SCons.Action.Action(shlib_generator, generator=1) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/aixcc.py0000644000175000017500000000451313606712377021745 0ustar kurtkurt"""SCons.Tool.aixcc Tool-specific initialization for IBM xlc / Visual Age C compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/aixcc.py 4369 2009/09/19 15:58:29 scons" import os.path import SCons.Platform.aix import cc packages = ['vac.C', 'ibmcxx.cmp'] def get_xlc(env): xlc = env.get('CC', 'xlc') xlc_r = env.get('SHCC', 'xlc_r') return SCons.Platform.aix.get_xlc(env, xlc, xlc_r, packages) def generate(env): """Add Builders and construction variables for xlc / Visual Age suite to an Environment.""" path, _cc, _shcc, version = get_xlc(env) if path: _cc = os.path.join(path, _cc) _shcc = os.path.join(path, _shcc) cc.generate(env) env['CC'] = _cc env['SHCC'] = _shcc env['CCVERSION'] = version def exists(env): path, _cc, _shcc, version = get_xlc(env) if path and _cc: xlc = os.path.join(path, _cc) if os.path.exists(xlc): return xlc return None # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/nasm.py0000644000175000017500000000514713606712377021620 0ustar kurtkurt"""SCons.Tool.nasm Tool-specific initialization for nasm, the famous Netwide Assembler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/nasm.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Util ASSuffixes = ['.s', '.asm', '.ASM'] ASPPSuffixes = ['.spp', '.SPP', '.sx'] if SCons.Util.case_sensitive_suffixes('.s', '.S'): ASPPSuffixes.extend(['.S']) else: ASSuffixes.extend(['.S']) def generate(env): """Add Builders and construction variables for nasm to an Environment.""" static_obj, shared_obj = SCons.Tool.createObjBuilders(env) for suffix in ASSuffixes: static_obj.add_action(suffix, SCons.Defaults.ASAction) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) for suffix in ASPPSuffixes: static_obj.add_action(suffix, SCons.Defaults.ASPPAction) static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter) env['AS'] = 'nasm' env['ASFLAGS'] = SCons.Util.CLVar('') env['ASPPFLAGS'] = '$ASFLAGS' env['ASCOM'] = '$AS $ASFLAGS -o $TARGET $SOURCES' env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES' def exists(env): return env.Detect('nasm') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/zip.py0000644000175000017500000000633313606712377021462 0ustar kurtkurt"""SCons.Tool.zip Tool-specific initialization for zip. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/zip.py 4369 2009/09/19 15:58:29 scons" import os.path import SCons.Builder import SCons.Defaults import SCons.Node.FS import SCons.Util try: import zipfile internal_zip = 1 except ImportError: internal_zip = 0 if internal_zip: zipcompression = zipfile.ZIP_DEFLATED def zip(target, source, env): def visit(arg, dirname, names): for name in names: path = os.path.join(dirname, name) if os.path.isfile(path): arg.write(path) compression = env.get('ZIPCOMPRESSION', 0) zf = zipfile.ZipFile(str(target[0]), 'w', compression) for s in source: if s.isdir(): os.path.walk(str(s), visit, zf) else: zf.write(str(s)) zf.close() else: zipcompression = 0 zip = "$ZIP $ZIPFLAGS ${TARGET.abspath} $SOURCES" zipAction = SCons.Action.Action(zip, varlist=['ZIPCOMPRESSION']) ZipBuilder = SCons.Builder.Builder(action = SCons.Action.Action('$ZIPCOM', '$ZIPCOMSTR'), source_factory = SCons.Node.FS.Entry, source_scanner = SCons.Defaults.DirScanner, suffix = '$ZIPSUFFIX', multi = 1) def generate(env): """Add Builders and construction variables for zip to an Environment.""" try: bld = env['BUILDERS']['Zip'] except KeyError: bld = ZipBuilder env['BUILDERS']['Zip'] = bld env['ZIP'] = 'zip' env['ZIPFLAGS'] = SCons.Util.CLVar('') env['ZIPCOM'] = zipAction env['ZIPCOMPRESSION'] = zipcompression env['ZIPSUFFIX'] = '.zip' def exists(env): return internal_zip or env.Detect('zip') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/ilink32.py0000644000175000017500000000405013606712377022125 0ustar kurtkurt"""SCons.Tool.ilink32 XXX """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/ilink32.py 4369 2009/09/19 15:58:29 scons" import SCons.Tool import SCons.Tool.bcc32 import SCons.Util def generate(env): """Add Builders and construction variables for Borland ilink to an Environment.""" SCons.Tool.createSharedLibBuilder(env) SCons.Tool.createProgBuilder(env) env['LINK'] = '$CC' env['LINKFLAGS'] = SCons.Util.CLVar('') env['LINKCOM'] = '$LINK -q $LINKFLAGS -e$TARGET $SOURCES $LIBS' env['LIBDIRPREFIX']='' env['LIBDIRSUFFIX']='' env['LIBLINKPREFIX']='' env['LIBLINKSUFFIX']='$LIBSUFFIX' def exists(env): # Uses bcc32 to do linking as it generally knows where the standard # LIBS are and set up the linking correctly return SCons.Tool.bcc32.findIt('bcc32', env) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/m4.py0000644000175000017500000000446213606712377021201 0ustar kurtkurt"""SCons.Tool.m4 Tool-specific initialization for m4. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/m4.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Builder import SCons.Util def generate(env): """Add Builders and construction variables for m4 to an Environment.""" M4Action = SCons.Action.Action('$M4COM', '$M4COMSTR') bld = SCons.Builder.Builder(action = M4Action, src_suffix = '.m4') env['BUILDERS']['M4'] = bld # .m4 files might include other files, and it would be pretty hard # to write a scanner for it, so let's just cd to the dir of the m4 # file and run from there. # The src_suffix setup is like so: file.c.m4 -> file.c, # file.cpp.m4 -> file.cpp etc. env['M4'] = 'm4' env['M4FLAGS'] = SCons.Util.CLVar('-E') env['M4COM'] = 'cd ${SOURCE.rsrcdir} && $M4 $M4FLAGS < ${SOURCE.file} > ${TARGET.abspath}' def exists(env): return env.Detect('m4') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/BitKeeper.py0000644000175000017500000000442313606712377022530 0ustar kurtkurt"""SCons.Tool.BitKeeper.py Tool-specific initialization for the BitKeeper source code control system. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/BitKeeper.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Builder import SCons.Util def generate(env): """Add a Builder factory function and construction variables for BitKeeper to an Environment.""" def BitKeeperFactory(env=env): """ """ act = SCons.Action.Action("$BITKEEPERCOM", "$BITKEEPERCOMSTR") return SCons.Builder.Builder(action = act, env = env) #setattr(env, 'BitKeeper', BitKeeperFactory) env.BitKeeper = BitKeeperFactory env['BITKEEPER'] = 'bk' env['BITKEEPERGET'] = '$BITKEEPER get' env['BITKEEPERGETFLAGS'] = SCons.Util.CLVar('') env['BITKEEPERCOM'] = '$BITKEEPERGET $BITKEEPERGETFLAGS $TARGET' def exists(env): return env.Detect('bk') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/g++.py0000644000175000017500000000623213606712377021232 0ustar kurtkurt"""SCons.Tool.g++ Tool-specific initialization for g++. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/g++.py 4369 2009/09/19 15:58:29 scons" import os.path import re import subprocess import SCons.Tool import SCons.Util cplusplus = __import__('c++', globals(), locals(), []) compilers = ['g++'] def generate(env): """Add Builders and construction variables for g++ to an Environment.""" static_obj, shared_obj = SCons.Tool.createObjBuilders(env) cplusplus.generate(env) env['CXX'] = env.Detect(compilers) # platform specific settings if env['PLATFORM'] == 'aix': env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc') env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 env['SHOBJSUFFIX'] = '$OBJSUFFIX' elif env['PLATFORM'] == 'hpux': env['SHOBJSUFFIX'] = '.pic.o' elif env['PLATFORM'] == 'sunos': env['SHOBJSUFFIX'] = '.pic.o' # determine compiler version if env['CXX']: #pipe = SCons.Action._subproc(env, [env['CXX'], '-dumpversion'], pipe = SCons.Action._subproc(env, [env['CXX'], '--version'], stdin = 'devnull', stderr = 'devnull', stdout = subprocess.PIPE) if pipe.wait() != 0: return # -dumpversion was added in GCC 3.0. As long as we're supporting # GCC versions older than that, we should use --version and a # regular expression. #line = pipe.stdout.read().strip() #if line: # env['CXXVERSION'] = line line = pipe.stdout.readline() match = re.search(r'[0-9]+(\.[0-9]+)+', line) if match: env['CXXVERSION'] = match.group(0) def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/dvipdf.py0000644000175000017500000000776413606712377022145 0ustar kurtkurt"""SCons.Tool.dvipdf Tool-specific initialization for dvipdf. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/dvipdf.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Defaults import SCons.Tool.pdf import SCons.Tool.tex import SCons.Util _null = SCons.Scanner.LaTeX._null def DviPdfPsFunction(XXXDviAction, target = None, source= None, env=None): """A builder for DVI files that sets the TEXPICTS environment variable before running dvi2ps or dvipdf.""" try: abspath = source[0].attributes.path except AttributeError : abspath = '' saved_env = SCons.Scanner.LaTeX.modify_env_var(env, 'TEXPICTS', abspath) result = XXXDviAction(target, source, env) if saved_env is _null: try: del env['ENV']['TEXPICTS'] except KeyError: pass # was never set else: env['ENV']['TEXPICTS'] = saved_env return result def DviPdfFunction(target = None, source= None, env=None): result = DviPdfPsFunction(PDFAction,target,source,env) return result def DviPdfStrFunction(target = None, source= None, env=None): """A strfunction for dvipdf that returns the appropriate command string for the no_exec options.""" if env.GetOption("no_exec"): result = env.subst('$DVIPDFCOM',0,target,source) else: result = '' return result PDFAction = None DVIPDFAction = None def PDFEmitter(target, source, env): """Strips any .aux or .log files from the input source list. These are created by the TeX Builder that in all likelihood was used to generate the .dvi file we're using as input, and we only care about the .dvi file. """ def strip_suffixes(n): return not SCons.Util.splitext(str(n))[1] in ['.aux', '.log'] source = filter(strip_suffixes, source) return (target, source) def generate(env): """Add Builders and construction variables for dvipdf to an Environment.""" global PDFAction if PDFAction is None: PDFAction = SCons.Action.Action('$DVIPDFCOM', '$DVIPDFCOMSTR') global DVIPDFAction if DVIPDFAction is None: DVIPDFAction = SCons.Action.Action(DviPdfFunction, strfunction = DviPdfStrFunction) import pdf pdf.generate(env) bld = env['BUILDERS']['PDF'] bld.add_action('.dvi', DVIPDFAction) bld.add_emitter('.dvi', PDFEmitter) env['DVIPDF'] = 'dvipdf' env['DVIPDFFLAGS'] = SCons.Util.CLVar('') env['DVIPDFCOM'] = 'cd ${TARGET.dir} && $DVIPDF $DVIPDFFLAGS ${SOURCE.file} ${TARGET.file}' # Deprecated synonym. env['PDFCOM'] = ['$DVIPDFCOM'] def exists(env): return env.Detect('dvipdf') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/link.py0000644000175000017500000001077713606712377021624 0ustar kurtkurt"""SCons.Tool.link Tool-specific initialization for the generic Posix linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/link.py 4369 2009/09/19 15:58:29 scons" import SCons.Defaults import SCons.Tool import SCons.Util import SCons.Warnings from SCons.Tool.FortranCommon import isfortran cplusplus = __import__('c++', globals(), locals(), []) issued_mixed_link_warning = False def smart_link(source, target, env, for_signature): has_cplusplus = cplusplus.iscplusplus(source) has_fortran = isfortran(env, source) if has_cplusplus and has_fortran: global issued_mixed_link_warning if not issued_mixed_link_warning: msg = "Using $CXX to link Fortran and C++ code together.\n\t" + \ "This may generate a buggy executable if the '%s'\n\t" + \ "compiler does not know how to deal with Fortran runtimes." SCons.Warnings.warn(SCons.Warnings.FortranCxxMixWarning, msg % env.subst('$CXX')) issued_mixed_link_warning = True return '$CXX' elif has_fortran: return '$FORTRAN' elif has_cplusplus: return '$CXX' return '$CC' def shlib_emitter(target, source, env): for tgt in target: tgt.attributes.shared = 1 return (target, source) def generate(env): """Add Builders and construction variables for gnulink to an Environment.""" SCons.Tool.createSharedLibBuilder(env) SCons.Tool.createProgBuilder(env) env['SHLINK'] = '$LINK' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' # don't set up the emitter, cause AppendUnique will generate a list # starting with None :-( env.Append(SHLIBEMITTER = [shlib_emitter]) env['SMARTLINK'] = smart_link env['LINK'] = "$SMARTLINK" env['LINKFLAGS'] = SCons.Util.CLVar('') env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' env['LIBDIRPREFIX']='-L' env['LIBDIRSUFFIX']='' env['_LIBFLAGS']='${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}' env['LIBLINKPREFIX']='-l' env['LIBLINKSUFFIX']='' if env['PLATFORM'] == 'hpux': env['SHLIBSUFFIX'] = '.sl' elif env['PLATFORM'] == 'aix': env['SHLIBSUFFIX'] = '.a' # For most platforms, a loadable module is the same as a shared # library. Platforms which are different can override these, but # setting them the same means that LoadableModule works everywhere. SCons.Tool.createLoadableModuleBuilder(env) env['LDMODULE'] = '$SHLINK' # don't set up the emitter, cause AppendUnique will generate a list # starting with None :-( env.Append(LDMODULEEMITTER='$SHLIBEMITTER') env['LDMODULEPREFIX'] = '$SHLIBPREFIX' env['LDMODULESUFFIX'] = '$SHLIBSUFFIX' env['LDMODULEFLAGS'] = '$SHLINKFLAGS' env['LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS' def exists(env): # This module isn't really a Tool on its own, it's common logic for # other linkers. return None # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/pdf.py0000644000175000017500000000571213606712377021431 0ustar kurtkurt"""SCons.Tool.pdf Common PDF Builder definition for various other Tool modules that use it. Add an explicit action to run epstopdf to convert .eps files to .pdf """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/pdf.py 4369 2009/09/19 15:58:29 scons" import SCons.Builder import SCons.Tool PDFBuilder = None EpsPdfAction = SCons.Action.Action('$EPSTOPDFCOM', '$EPSTOPDFCOMSTR') def generate(env): try: env['BUILDERS']['PDF'] except KeyError: global PDFBuilder if PDFBuilder is None: PDFBuilder = SCons.Builder.Builder(action = {}, source_scanner = SCons.Tool.PDFLaTeXScanner, prefix = '$PDFPREFIX', suffix = '$PDFSUFFIX', emitter = {}, source_ext_match = None, single_source=True) env['BUILDERS']['PDF'] = PDFBuilder env['PDFPREFIX'] = '' env['PDFSUFFIX'] = '.pdf' # put the epstopdf builder in this routine so we can add it after # the pdftex builder so that one is the default for no source suffix def generate2(env): bld = env['BUILDERS']['PDF'] #bld.add_action('.ps', EpsPdfAction) # this is covered by direct Ghostcript action in gs.py bld.add_action('.eps', EpsPdfAction) env['EPSTOPDF'] = 'epstopdf' env['EPSTOPDFFLAGS'] = SCons.Util.CLVar('') env['EPSTOPDFCOM'] = '$EPSTOPDF $EPSTOPDFFLAGS ${SOURCE} -o ${TARGET}' def exists(env): # This only puts a skeleton Builder in place, so if someone # references this Tool directly, it's always "available." return 1 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/javah.py0000644000175000017500000001111013606712377021736 0ustar kurtkurt"""SCons.Tool.javah Tool-specific initialization for javah. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/javah.py 4369 2009/09/19 15:58:29 scons" import os.path import string import SCons.Action import SCons.Builder import SCons.Node.FS import SCons.Tool.javac import SCons.Util def emit_java_headers(target, source, env): """Create and return lists of Java stub header files that will be created from a set of class files. """ class_suffix = env.get('JAVACLASSSUFFIX', '.class') classdir = env.get('JAVACLASSDIR') if not classdir: try: s = source[0] except IndexError: classdir = '.' else: try: classdir = s.attributes.java_classdir except AttributeError: classdir = '.' classdir = env.Dir(classdir).rdir() if str(classdir) == '.': c_ = None else: c_ = str(classdir) + os.sep slist = [] for src in source: try: classname = src.attributes.java_classname except AttributeError: classname = str(src) if c_ and classname[:len(c_)] == c_: classname = classname[len(c_):] if class_suffix and classname[-len(class_suffix):] == class_suffix: classname = classname[:-len(class_suffix)] classname = SCons.Tool.javac.classname(classname) s = src.rfile() s.attributes.java_classname = classname slist.append(s) s = source[0].rfile() if not hasattr(s.attributes, 'java_classdir'): s.attributes.java_classdir = classdir if target[0].__class__ is SCons.Node.FS.File: tlist = target else: if not isinstance(target[0], SCons.Node.FS.Dir): target[0].__class__ = SCons.Node.FS.Dir target[0]._morph() tlist = [] for s in source: fname = string.replace(s.attributes.java_classname, '.', '_') + '.h' t = target[0].File(fname) t.attributes.java_lookupdir = target[0] tlist.append(t) return tlist, source def JavaHOutFlagGenerator(target, source, env, for_signature): try: t = target[0] except (AttributeError, IndexError, TypeError): t = target try: return '-d ' + str(t.attributes.java_lookupdir) except AttributeError: return '-o ' + str(t) def getJavaHClassPath(env,target, source, for_signature): path = "${SOURCE.attributes.java_classdir}" if 'JAVACLASSPATH' in env and env['JAVACLASSPATH']: path = SCons.Util.AppendPath(path, env['JAVACLASSPATH']) return "-classpath %s" % (path) def generate(env): """Add Builders and construction variables for javah to an Environment.""" java_javah = SCons.Tool.CreateJavaHBuilder(env) java_javah.emitter = emit_java_headers env['_JAVAHOUTFLAG'] = JavaHOutFlagGenerator env['JAVAH'] = 'javah' env['JAVAHFLAGS'] = SCons.Util.CLVar('') env['_JAVAHCLASSPATH'] = getJavaHClassPath env['JAVAHCOM'] = '$JAVAH $JAVAHFLAGS $_JAVAHOUTFLAG $_JAVAHCLASSPATH ${SOURCES.attributes.java_classname}' env['JAVACLASSSUFFIX'] = '.class' def exists(env): return env.Detect('javah') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/aixc++.py0000644000175000017500000000524313606712377021731 0ustar kurtkurt"""SCons.Tool.aixc++ Tool-specific initialization for IBM xlC / Visual Age C++ compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/aixc++.py 4369 2009/09/19 15:58:29 scons" import os.path import SCons.Platform.aix cplusplus = __import__('c++', globals(), locals(), []) packages = ['vacpp.cmp.core', 'vacpp.cmp.batch', 'vacpp.cmp.C', 'ibmcxx.cmp'] def get_xlc(env): xlc = env.get('CXX', 'xlC') xlc_r = env.get('SHCXX', 'xlC_r') return SCons.Platform.aix.get_xlc(env, xlc, xlc_r, packages) def smart_cxxflags(source, target, env, for_signature): build_dir = env.GetBuildPath() if build_dir: return '-qtempinc=' + os.path.join(build_dir, 'tempinc') return '' def generate(env): """Add Builders and construction variables for xlC / Visual Age suite to an Environment.""" path, _cxx, _shcxx, version = get_xlc(env) if path: _cxx = os.path.join(path, _cxx) _shcxx = os.path.join(path, _shcxx) cplusplus.generate(env) env['CXX'] = _cxx env['SHCXX'] = _shcxx env['CXXVERSION'] = version env['SHOBJSUFFIX'] = '.pic.o' def exists(env): path, _cxx, _shcxx, version = get_xlc(env) if path and _cxx: xlc = os.path.join(path, _cxx) if os.path.exists(xlc): return xlc return None # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/mslink.py0000644000175000017500000002476013606712377022161 0ustar kurtkurt"""SCons.Tool.mslink Tool-specific initialization for the Microsoft linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/mslink.py 4369 2009/09/19 15:58:29 scons" import os.path import SCons.Action import SCons.Defaults import SCons.Errors import SCons.Platform.win32 import SCons.Tool import SCons.Tool.msvc import SCons.Tool.msvs import SCons.Util from MSCommon import merge_default_version, msvs_exists def pdbGenerator(env, target, source, for_signature): try: return ['/PDB:%s' % target[0].attributes.pdb, '/DEBUG'] except (AttributeError, IndexError): return None def _dllTargets(target, source, env, for_signature, paramtp): listCmd = [] dll = env.FindIxes(target, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp) if dll: listCmd.append("/out:%s"%dll.get_string(for_signature)) implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') if implib: listCmd.append("/implib:%s"%implib.get_string(for_signature)) return listCmd def _dllSources(target, source, env, for_signature, paramtp): listCmd = [] deffile = env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX") for src in source: # Check explicitly for a non-None deffile so that the __cmp__ # method of the base SCons.Util.Proxy class used for some Node # proxies doesn't try to use a non-existent __dict__ attribute. if deffile and src == deffile: # Treat this source as a .def file. listCmd.append("/def:%s" % src.get_string(for_signature)) else: # Just treat it as a generic source file. listCmd.append(src) return listCmd def windowsShlinkTargets(target, source, env, for_signature): return _dllTargets(target, source, env, for_signature, 'SHLIB') def windowsShlinkSources(target, source, env, for_signature): return _dllSources(target, source, env, for_signature, 'SHLIB') def _windowsLdmodTargets(target, source, env, for_signature): """Get targets for loadable modules.""" return _dllTargets(target, source, env, for_signature, 'LDMODULE') def _windowsLdmodSources(target, source, env, for_signature): """Get sources for loadable modules.""" return _dllSources(target, source, env, for_signature, 'LDMODULE') def _dllEmitter(target, source, env, paramtp): """Common implementation of dll emitter.""" SCons.Tool.msvc.validate_vars(env) extratargets = [] extrasources = [] dll = env.FindIxes(target, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp) no_import_lib = env.get('no_import_lib', 0) if not dll: raise SCons.Errors.UserError('A shared library should have exactly one target with the suffix: %s' % env.subst('$%sSUFFIX' % paramtp)) insert_def = env.subst("$WINDOWS_INSERT_DEF") if not insert_def in ['', '0', 0] and \ not env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX"): # append a def file to the list of sources extrasources.append( env.ReplaceIxes(dll, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX")) version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0')) if version_num >= 8.0 and env.get('WINDOWS_INSERT_MANIFEST', 0): # MSVC 8 automatically generates .manifest files that must be installed extratargets.append( env.ReplaceIxes(dll, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp, "WINDOWSSHLIBMANIFESTPREFIX", "WINDOWSSHLIBMANIFESTSUFFIX")) if 'PDB' in env and env['PDB']: pdb = env.arg2nodes('$PDB', target=target, source=source)[0] extratargets.append(pdb) target[0].attributes.pdb = pdb if not no_import_lib and \ not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"): # Append an import library to the list of targets. extratargets.append( env.ReplaceIxes(dll, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp, "LIBPREFIX", "LIBSUFFIX")) # and .exp file is created if there are exports from a DLL extratargets.append( env.ReplaceIxes(dll, '%sPREFIX' % paramtp, '%sSUFFIX' % paramtp, "WINDOWSEXPPREFIX", "WINDOWSEXPSUFFIX")) return (target+extratargets, source+extrasources) def windowsLibEmitter(target, source, env): return _dllEmitter(target, source, env, 'SHLIB') def ldmodEmitter(target, source, env): """Emitter for loadable modules. Loadable modules are identical to shared libraries on Windows, but building them is subject to different parameters (LDMODULE*). """ return _dllEmitter(target, source, env, 'LDMODULE') def prog_emitter(target, source, env): SCons.Tool.msvc.validate_vars(env) extratargets = [] exe = env.FindIxes(target, "PROGPREFIX", "PROGSUFFIX") if not exe: raise SCons.Errors.UserError("An executable should have exactly one target with the suffix: %s" % env.subst("$PROGSUFFIX")) version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0')) if version_num >= 8.0 and env.get('WINDOWS_INSERT_MANIFEST', 0): # MSVC 8 automatically generates .manifest files that have to be installed extratargets.append( env.ReplaceIxes(exe, "PROGPREFIX", "PROGSUFFIX", "WINDOWSPROGMANIFESTPREFIX", "WINDOWSPROGMANIFESTSUFFIX")) if 'PDB' in env and env['PDB']: pdb = env.arg2nodes('$PDB', target=target, source=source)[0] extratargets.append(pdb) target[0].attributes.pdb = pdb return (target+extratargets,source) def RegServerFunc(target, source, env): if 'register' in env and env['register']: ret = regServerAction([target[0]], [source[0]], env) if ret: raise SCons.Errors.UserError("Unable to register %s" % target[0]) else: print("Registered %s sucessfully" % target[0]) return ret return 0 regServerAction = SCons.Action.Action("$REGSVRCOM", "$REGSVRCOMSTR") regServerCheck = SCons.Action.Action(RegServerFunc, None) shlibLinkAction = SCons.Action.Action('${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_SHLINK_SOURCES")}') compositeShLinkAction = shlibLinkAction + regServerCheck ldmodLinkAction = SCons.Action.Action('${TEMPFILE("$LDMODULE $LDMODULEFLAGS $_LDMODULE_TARGETS $_LIBDIRFLAGS $_LIBFLAGS $_PDB $_LDMODULE_SOURCES")}') compositeLdmodAction = ldmodLinkAction + regServerCheck def generate(env): """Add Builders and construction variables for ar to an Environment.""" SCons.Tool.createSharedLibBuilder(env) SCons.Tool.createProgBuilder(env) env['SHLINK'] = '$LINK' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS /dll') env['_SHLINK_TARGETS'] = windowsShlinkTargets env['_SHLINK_SOURCES'] = windowsShlinkSources env['SHLINKCOM'] = compositeShLinkAction env.Append(SHLIBEMITTER = [windowsLibEmitter]) env['LINK'] = 'link' env['LINKFLAGS'] = SCons.Util.CLVar('/nologo') env['_PDB'] = pdbGenerator env['LINKCOM'] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET.windows $_LIBDIRFLAGS $_LIBFLAGS $_PDB $SOURCES.windows")}' env.Append(PROGEMITTER = [prog_emitter]) env['LIBDIRPREFIX']='/LIBPATH:' env['LIBDIRSUFFIX']='' env['LIBLINKPREFIX']='' env['LIBLINKSUFFIX']='$LIBSUFFIX' env['WIN32DEFPREFIX'] = '' env['WIN32DEFSUFFIX'] = '.def' env['WIN32_INSERT_DEF'] = 0 env['WINDOWSDEFPREFIX'] = '${WIN32DEFPREFIX}' env['WINDOWSDEFSUFFIX'] = '${WIN32DEFSUFFIX}' env['WINDOWS_INSERT_DEF'] = '${WIN32_INSERT_DEF}' env['WIN32EXPPREFIX'] = '' env['WIN32EXPSUFFIX'] = '.exp' env['WINDOWSEXPPREFIX'] = '${WIN32EXPPREFIX}' env['WINDOWSEXPSUFFIX'] = '${WIN32EXPSUFFIX}' env['WINDOWSSHLIBMANIFESTPREFIX'] = '' env['WINDOWSSHLIBMANIFESTSUFFIX'] = '${SHLIBSUFFIX}.manifest' env['WINDOWSPROGMANIFESTPREFIX'] = '' env['WINDOWSPROGMANIFESTSUFFIX'] = '${PROGSUFFIX}.manifest' env['REGSVRACTION'] = regServerCheck env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32') env['REGSVRFLAGS'] = '/s ' env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS ${TARGET.windows}' # Set-up ms tools paths for default version merge_default_version(env) # Loadable modules are on Windows the same as shared libraries, but they # are subject to different build parameters (LDMODULE* variables). # Therefore LDMODULE* variables correspond as much as possible to # SHLINK*/SHLIB* ones. SCons.Tool.createLoadableModuleBuilder(env) env['LDMODULE'] = '$SHLINK' env['LDMODULEPREFIX'] = '$SHLIBPREFIX' env['LDMODULESUFFIX'] = '$SHLIBSUFFIX' env['LDMODULEFLAGS'] = '$SHLINKFLAGS' env['_LDMODULE_TARGETS'] = _windowsLdmodTargets env['_LDMODULE_SOURCES'] = _windowsLdmodSources env['LDMODULEEMITTER'] = [ldmodEmitter] env['LDMODULECOM'] = compositeLdmodAction def exists(env): return msvs_exists() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/Perforce.py0000644000175000017500000000711313606712377022422 0ustar kurtkurt"""SCons.Tool.Perforce.py Tool-specific initialization for Perforce Source Code Management system. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/Perforce.py 4369 2009/09/19 15:58:29 scons" import os import SCons.Action import SCons.Builder import SCons.Node.FS import SCons.Util # This function should maybe be moved to SCons.Util? from SCons.Tool.PharLapCommon import addPathIfNotExists # Variables that we want to import from the base OS environment. _import_env = [ 'P4PORT', 'P4CLIENT', 'P4USER', 'USER', 'USERNAME', 'P4PASSWD', 'P4CHARSET', 'P4LANGUAGE', 'SystemRoot' ] PerforceAction = SCons.Action.Action('$P4COM', '$P4COMSTR') def generate(env): """Add a Builder factory function and construction variables for Perforce to an Environment.""" def PerforceFactory(env=env): """ """ return SCons.Builder.Builder(action = PerforceAction, env = env) #setattr(env, 'Perforce', PerforceFactory) env.Perforce = PerforceFactory env['P4'] = 'p4' env['P4FLAGS'] = SCons.Util.CLVar('') env['P4COM'] = '$P4 $P4FLAGS sync $TARGET' try: environ = env['ENV'] except KeyError: environ = {} env['ENV'] = environ # Perforce seems to use the PWD environment variable rather than # calling getcwd() for itself, which is odd. If no PWD variable # is present, p4 WILL call getcwd, but this seems to cause problems # with good ol' Windows's tilde-mangling for long file names. environ['PWD'] = env.Dir('#').get_abspath() for var in _import_env: v = os.environ.get(var) if v: environ[var] = v if SCons.Util.can_read_reg: # If we can read the registry, add the path to Perforce to our environment. try: k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, 'Software\\Perforce\\environment') val, tok = SCons.Util.RegQueryValueEx(k, 'P4INSTROOT') addPathIfNotExists(environ, 'PATH', val) except SCons.Util.RegError: # Can't detect where Perforce is, hope the user has it set in the # PATH. pass def exists(env): return env.Detect('p4') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/dvips.py0000644000175000017500000000656613606712377022015 0ustar kurtkurt"""SCons.Tool.dvips Tool-specific initialization for dvips. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/dvips.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Builder import SCons.Tool.dvipdf import SCons.Util def DviPsFunction(target = None, source= None, env=None): result = SCons.Tool.dvipdf.DviPdfPsFunction(PSAction,target,source,env) return result def DviPsStrFunction(target = None, source= None, env=None): """A strfunction for dvipdf that returns the appropriate command string for the no_exec options.""" if env.GetOption("no_exec"): result = env.subst('$PSCOM',0,target,source) else: result = '' return result PSAction = None DVIPSAction = None PSBuilder = None def generate(env): """Add Builders and construction variables for dvips to an Environment.""" global PSAction if PSAction is None: PSAction = SCons.Action.Action('$PSCOM', '$PSCOMSTR') global DVIPSAction if DVIPSAction is None: DVIPSAction = SCons.Action.Action(DviPsFunction, strfunction = DviPsStrFunction) global PSBuilder if PSBuilder is None: PSBuilder = SCons.Builder.Builder(action = PSAction, prefix = '$PSPREFIX', suffix = '$PSSUFFIX', src_suffix = '.dvi', src_builder = 'DVI', single_source=True) env['BUILDERS']['PostScript'] = PSBuilder env['DVIPS'] = 'dvips' env['DVIPSFLAGS'] = SCons.Util.CLVar('') # I'm not quite sure I got the directories and filenames right for variant_dir # We need to be in the correct directory for the sake of latex \includegraphics eps included files. env['PSCOM'] = 'cd ${TARGET.dir} && $DVIPS $DVIPSFLAGS -o ${TARGET.file} ${SOURCE.file}' env['PSPREFIX'] = '' env['PSSUFFIX'] = '.ps' def exists(env): return env.Detect('dvips') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/pdflatex.py0000644000175000017500000000560313606712377022466 0ustar kurtkurt"""SCons.Tool.pdflatex Tool-specific initialization for pdflatex. Generates .pdf files from .latex or .ltx files There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/pdflatex.py 4369 2009/09/19 15:58:29 scons" import SCons.Action import SCons.Util import SCons.Tool.pdf import SCons.Tool.tex PDFLaTeXAction = None def PDFLaTeXAuxFunction(target = None, source= None, env=None): result = SCons.Tool.tex.InternalLaTeXAuxAction( PDFLaTeXAction, target, source, env ) if result != 0: print(env['PDFLATEX']," returned an error, check the log file") return result PDFLaTeXAuxAction = None def generate(env): """Add Builders and construction variables for pdflatex to an Environment.""" global PDFLaTeXAction if PDFLaTeXAction is None: PDFLaTeXAction = SCons.Action.Action('$PDFLATEXCOM', '$PDFLATEXCOMSTR') global PDFLaTeXAuxAction if PDFLaTeXAuxAction is None: PDFLaTeXAuxAction = SCons.Action.Action(PDFLaTeXAuxFunction, strfunction=SCons.Tool.tex.TeXLaTeXStrFunction) env.AppendUnique(LATEXSUFFIXES=SCons.Tool.LaTeXSuffixes) import pdf pdf.generate(env) bld = env['BUILDERS']['PDF'] bld.add_action('.ltx', PDFLaTeXAuxAction) bld.add_action('.latex', PDFLaTeXAuxAction) bld.add_emitter('.ltx', SCons.Tool.tex.tex_pdf_emitter) bld.add_emitter('.latex', SCons.Tool.tex.tex_pdf_emitter) SCons.Tool.tex.generate_common(env) def exists(env): return env.Detect('pdflatex') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sunlink.py0000644000175000017500000000460513606712377022343 0ustar kurtkurt"""SCons.Tool.sunlink Tool-specific initialization for the Sun Solaris (Forte) linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sunlink.py 4369 2009/09/19 15:58:29 scons" import os import os.path import SCons.Util import link ccLinker = None # search for the acc compiler and linker front end try: dirs = os.listdir('/opt') except (IOError, OSError): # Not being able to read the directory because it doesn't exist # (IOError) or isn't readable (OSError) is okay. dirs = [] for d in dirs: linker = '/opt/' + d + '/bin/CC' if os.path.exists(linker): ccLinker = linker break def generate(env): """Add Builders and construction variables for Forte to an Environment.""" link.generate(env) env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -G') env.Append(LINKFLAGS=['$__RPATH']) env['RPATHPREFIX'] = '-R' env['RPATHSUFFIX'] = '' env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' def exists(env): return ccLinker # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/swig.py0000644000175000017500000001570013606712377021627 0ustar kurtkurt"""SCons.Tool.swig Tool-specific initialization for swig. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/swig.py 4369 2009/09/19 15:58:29 scons" import os.path import re import string import subprocess import SCons.Action import SCons.Defaults import SCons.Scanner import SCons.Tool import SCons.Util SwigAction = SCons.Action.Action('$SWIGCOM', '$SWIGCOMSTR') def swigSuffixEmitter(env, source): if '-c++' in SCons.Util.CLVar(env.subst("$SWIGFLAGS", source=source)): return '$SWIGCXXFILESUFFIX' else: return '$SWIGCFILESUFFIX' # Match '%module test', as well as '%module(directors="1") test' # Also allow for test to be quoted (SWIG permits double quotes, but not single) _reModule = re.compile(r'%module(\s*\(.*\))?\s+("?)(.+)\2') def _find_modules(src): """Find all modules referenced by %module lines in `src`, a SWIG .i file. Returns a list of all modules, and a flag set if SWIG directors have been requested (SWIG will generate an additional header file in this case.)""" directors = 0 mnames = [] matches = _reModule.findall(open(src).read()) for m in matches: mnames.append(m[2]) directors = directors or string.find(m[0], 'directors') >= 0 return mnames, directors def _add_director_header_targets(target, env): # Directors only work with C++ code, not C suffix = env.subst(env['SWIGCXXFILESUFFIX']) # For each file ending in SWIGCXXFILESUFFIX, add a new target director # header by replacing the ending with SWIGDIRECTORSUFFIX. for x in target[:]: n = x.name d = x.dir if n[-len(suffix):] == suffix: target.append(d.File(n[:-len(suffix)] + env['SWIGDIRECTORSUFFIX'])) def _swigEmitter(target, source, env): swigflags = env.subst("$SWIGFLAGS", target=target, source=source) flags = SCons.Util.CLVar(swigflags) for src in source: src = str(src.rfile()) mnames = None if "-python" in flags and "-noproxy" not in flags: if mnames is None: mnames, directors = _find_modules(src) if directors: _add_director_header_targets(target, env) python_files = map(lambda m: m + ".py", mnames) outdir = env.subst('$SWIGOUTDIR', target=target, source=source) # .py files should be generated in SWIGOUTDIR if specified, # otherwise in the same directory as the target if outdir: python_files = map(lambda j, o=outdir, e=env: e.fs.File(os.path.join(o, j)), python_files) else: python_files = map(lambda m, d=target[0].dir: d.File(m), python_files) target.extend(python_files) if "-java" in flags: if mnames is None: mnames, directors = _find_modules(src) if directors: _add_director_header_targets(target, env) java_files = map(lambda m: [m + ".java", m + "JNI.java"], mnames) java_files = SCons.Util.flatten(java_files) outdir = env.subst('$SWIGOUTDIR', target=target, source=source) if outdir: java_files = map(lambda j, o=outdir: os.path.join(o, j), java_files) java_files = map(env.fs.File, java_files) for jf in java_files: t_from_s = lambda t, p, s, x: t.dir SCons.Util.AddMethod(jf, t_from_s, 'target_from_source') target.extend(java_files) return (target, source) def _get_swig_version(env): """Run the SWIG command line tool to get and return the version number""" pipe = SCons.Action._subproc(env, [env['SWIG'], '-version'], stdin = 'devnull', stderr = 'devnull', stdout = subprocess.PIPE) if pipe.wait() != 0: return out = pipe.stdout.read() match = re.search(r'SWIG Version\s+(\S+)$', out, re.MULTILINE) if match: return match.group(1) def generate(env): """Add Builders and construction variables for swig to an Environment.""" c_file, cxx_file = SCons.Tool.createCFileBuilders(env) c_file.suffix['.i'] = swigSuffixEmitter cxx_file.suffix['.i'] = swigSuffixEmitter c_file.add_action('.i', SwigAction) c_file.add_emitter('.i', _swigEmitter) cxx_file.add_action('.i', SwigAction) cxx_file.add_emitter('.i', _swigEmitter) java_file = SCons.Tool.CreateJavaFileBuilder(env) java_file.suffix['.i'] = swigSuffixEmitter java_file.add_action('.i', SwigAction) java_file.add_emitter('.i', _swigEmitter) env['SWIG'] = 'swig' env['SWIGVERSION'] = _get_swig_version(env) env['SWIGFLAGS'] = SCons.Util.CLVar('') env['SWIGDIRECTORSUFFIX'] = '_wrap.h' env['SWIGCFILESUFFIX'] = '_wrap$CFILESUFFIX' env['SWIGCXXFILESUFFIX'] = '_wrap$CXXFILESUFFIX' env['_SWIGOUTDIR'] = r'${"-outdir \"%s\"" % SWIGOUTDIR}' env['SWIGPATH'] = [] env['SWIGINCPREFIX'] = '-I' env['SWIGINCSUFFIX'] = '' env['_SWIGINCFLAGS'] = '$( ${_concat(SWIGINCPREFIX, SWIGPATH, SWIGINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' env['SWIGCOM'] = '$SWIG -o $TARGET ${_SWIGOUTDIR} ${_SWIGINCFLAGS} $SWIGFLAGS $SOURCES' expr = '^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)' scanner = SCons.Scanner.ClassicCPP("SWIGScan", ".i", "SWIGPATH", expr) env.Append(SCANNERS = scanner) def exists(env): return env.Detect(['swig']) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/applelink.py0000644000175000017500000000543313606712377022637 0ustar kurtkurt"""SCons.Tool.applelink Tool-specific initialization for the Apple gnu-like linker. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/applelink.py 4369 2009/09/19 15:58:29 scons" import SCons.Util # Even though the Mac is based on the GNU toolchain, it doesn't understand # the -rpath option, so we use the "link" tool instead of "gnulink". import link def generate(env): """Add Builders and construction variables for applelink to an Environment.""" link.generate(env) env['FRAMEWORKPATHPREFIX'] = '-F' env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__)}' env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}' env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib') env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' # override the default for loadable modules, which are different # on OS X than dynamic shared libs. echoing what XCode does for # pre/suffixes: env['LDMODULEPREFIX'] = '' env['LDMODULESUFFIX'] = '' env['LDMODULEFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -bundle') env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' def exists(env): return env['PLATFORM'] == 'darwin' # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/intelc.py0000644000175000017500000004566313606712377022147 0ustar kurtkurt"""SCons.Tool.icl Tool-specific initialization for the Intel C/C++ compiler. Supports Linux and Windows compilers, v7 and up. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/intelc.py 4369 2009/09/19 15:58:29 scons" import math, sys, os.path, glob, string, re is_windows = sys.platform == 'win32' is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or ('PROCESSOR_ARCHITEW6432' in os.environ and os.environ['PROCESSOR_ARCHITEW6432'] == 'AMD64')) is_linux = sys.platform == 'linux2' is_mac = sys.platform == 'darwin' if is_windows: import SCons.Tool.msvc elif is_linux: import SCons.Tool.gcc elif is_mac: import SCons.Tool.gcc import SCons.Util import SCons.Warnings # Exceptions for this tool class IntelCError(SCons.Errors.InternalError): pass class MissingRegistryError(IntelCError): # missing registry entry pass class MissingDirError(IntelCError): # dir not found pass class NoRegistryModuleError(IntelCError): # can't read registry at all pass def uniquify(s): """Return a sequence containing only one copy of each unique element from input sequence s. Does not preserve order. Input sequence must be hashable (i.e. must be usable as a dictionary key).""" u = {} for x in s: u[x] = 1 return u.keys() def linux_ver_normalize(vstr): """Normalize a Linux compiler version number. Intel changed from "80" to "9.0" in 2005, so we assume if the number is greater than 60 it's an old-style number and otherwise new-style. Always returns an old-style float like 80 or 90 for compatibility with Windows. Shades of Y2K!""" # Check for version number like 9.1.026: return 91.026 m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)', vstr) if m: vmaj,vmin,build = m.groups() return float(vmaj) * 10 + float(vmin) + float(build) / 1000.; else: f = float(vstr) if is_windows: return f else: if f < 60: return f * 10.0 else: return f def check_abi(abi): """Check for valid ABI (application binary interface) name, and map into canonical one""" if not abi: return None abi = abi.lower() # valid_abis maps input name to canonical name if is_windows: valid_abis = {'ia32' : 'ia32', 'x86' : 'ia32', 'ia64' : 'ia64', 'em64t' : 'em64t', 'amd64' : 'em64t'} if is_linux: valid_abis = {'ia32' : 'ia32', 'x86' : 'ia32', 'x86_64' : 'x86_64', 'em64t' : 'x86_64', 'amd64' : 'x86_64'} if is_mac: valid_abis = {'ia32' : 'ia32', 'x86' : 'ia32', 'x86_64' : 'x86_64', 'em64t' : 'x86_64'} try: abi = valid_abis[abi] except KeyError: raise SCons.Errors.UserError("Intel compiler: Invalid ABI %s, valid values are %s"% \ (abi, valid_abis.keys())) return abi def vercmp(a, b): """Compare strings as floats, but Intel changed Linux naming convention at 9.0""" return cmp(linux_ver_normalize(b), linux_ver_normalize(a)) def get_version_from_list(v, vlist): """See if we can match v (string) in vlist (list of strings) Linux has to match in a fuzzy way.""" if is_windows: # Simple case, just find it in the list if v in vlist: return v else: return None else: # Fuzzy match: normalize version number first, but still return # original non-normalized form. fuzz = 0.001 for vi in vlist: if math.fabs(linux_ver_normalize(vi) - linux_ver_normalize(v)) < fuzz: return vi # Not found return None def get_intel_registry_value(valuename, version=None, abi=None): """ Return a value from the Intel compiler registry tree. (Windows only) """ # Open the key: if is_win64: K = 'Software\\Wow6432Node\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper() else: K = 'Software\\Intel\\Compilers\\C++\\' + version + '\\'+abi.upper() try: k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) except SCons.Util.RegError: raise MissingRegistryError("%s was not found in the registry, for Intel compiler version %s, abi='%s'"%(K, version,abi)) # Get the value: try: v = SCons.Util.RegQueryValueEx(k, valuename)[0] return v # or v.encode('iso-8859-1', 'replace') to remove unicode? except SCons.Util.RegError: raise MissingRegistryError("%s\\%s was not found in the registry."%(K, valuename)) def get_all_compiler_versions(): """Returns a sorted list of strings, like "70" or "80" or "9.0" with most recent compiler version first. """ versions=[] if is_windows: if is_win64: keyname = 'Software\\WoW6432Node\\Intel\\Compilers\\C++' else: keyname = 'Software\\Intel\\Compilers\\C++' try: k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, keyname) except WindowsError: return [] i = 0 versions = [] try: while i < 100: subkey = SCons.Util.RegEnumKey(k, i) # raises EnvironmentError # Check that this refers to an existing dir. # This is not 100% perfect but should catch common # installation issues like when the compiler was installed # and then the install directory deleted or moved (rather # than uninstalling properly), so the registry values # are still there. ok = False for try_abi in ('IA32', 'IA32e', 'IA64', 'EM64T'): try: d = get_intel_registry_value('ProductDir', subkey, try_abi) except MissingRegistryError: continue # not found in reg, keep going if os.path.exists(d): ok = True if ok: versions.append(subkey) else: try: # Registry points to nonexistent dir. Ignore this # version. value = get_intel_registry_value('ProductDir', subkey, 'IA32') except MissingRegistryError as e: # Registry key is left dangling (potentially # after uninstalling). print("scons: *** Ignoring the registry key for the Intel compiler version %s.\n" \ "scons: *** It seems that the compiler was uninstalled and that the registry\n" \ "scons: *** was not cleaned up properly.\n" % subkey) else: print("scons: *** Ignoring "+str(value)) i = i + 1 except EnvironmentError: # no more subkeys pass elif is_linux: for d in glob.glob('/opt/intel_cc_*'): # Typical dir here is /opt/intel_cc_80. m = re.search(r'cc_(.*)$', d) if m: versions.append(m.group(1)) for d in glob.glob('/opt/intel/cc*/*'): # Typical dir here is /opt/intel/cc/9.0 for IA32, # /opt/intel/cce/9.0 for EMT64 (AMD64) m = re.search(r'([0-9.]+)$', d) if m: versions.append(m.group(1)) elif is_mac: for d in glob.glob('/opt/intel/cc*/*'): # Typical dir here is /opt/intel/cc/9.0 for IA32, # /opt/intel/cce/9.0 for EMT64 (AMD64) m = re.search(r'([0-9.]+)$', d) if m: versions.append(m.group(1)) versions = uniquify(versions) # remove dups versions.sort(vercmp) return versions def get_intel_compiler_top(version, abi): """ Return the main path to the top-level dir of the Intel compiler, using the given version. The compiler will be in /bin/icl.exe (icc on linux), the include dir is /include, etc. """ if is_windows: if not SCons.Util.can_read_reg: raise NoRegistryModuleError("No Windows registry module was found") top = get_intel_registry_value('ProductDir', version, abi) # pre-11, icl was in Bin. 11 and later, it's in Bin/ apparently. if not os.path.exists(os.path.join(top, "Bin", "icl.exe")) \ and not os.path.exists(os.path.join(top, "Bin", abi, "icl.exe")): raise MissingDirError("Can't find Intel compiler in %s"%(top)) elif is_mac or is_linux: # first dir is new (>=9.0) style, second is old (8.0) style. dirs=('/opt/intel/cc/%s', '/opt/intel_cc_%s') if abi == 'x86_64': dirs=('/opt/intel/cce/%s',) # 'e' stands for 'em64t', aka x86_64 aka amd64 top=None for d in dirs: if os.path.exists(os.path.join(d%version, "bin", "icc")): top = d%version break if not top: raise MissingDirError("Can't find version %s Intel compiler in %s (abi='%s')"%(version,top, abi)) return top def generate(env, version=None, abi=None, topdir=None, verbose=0): """Add Builders and construction variables for Intel C/C++ compiler to an Environment. args: version: (string) compiler version to use, like "80" abi: (string) 'win32' or whatever Itanium version wants topdir: (string) compiler top dir, like "c:\Program Files\Intel\Compiler70" If topdir is used, version and abi are ignored. verbose: (int) if >0, prints compiler version used. """ if not (is_mac or is_linux or is_windows): # can't handle this platform return if is_windows: SCons.Tool.msvc.generate(env) elif is_linux: SCons.Tool.gcc.generate(env) elif is_mac: SCons.Tool.gcc.generate(env) # if version is unspecified, use latest vlist = get_all_compiler_versions() if not version: if vlist: version = vlist[0] else: # User may have specified '90' but we need to get actual dirname '9.0'. # get_version_from_list does that mapping. v = get_version_from_list(version, vlist) if not v: raise SCons.Errors.UserError("Invalid Intel compiler version %s: "%version + \ "installed versions are %s"%(', '.join(vlist))) version = v # if abi is unspecified, use ia32 # alternatives are ia64 for Itanium, or amd64 or em64t or x86_64 (all synonyms here) abi = check_abi(abi) if abi is None: if is_mac or is_linux: # Check if we are on 64-bit linux, default to 64 then. uname_m = os.uname()[4] if uname_m == 'x86_64': abi = 'x86_64' else: abi = 'ia32' else: if is_win64: abi = 'em64t' else: abi = 'ia32' if version and not topdir: try: topdir = get_intel_compiler_top(version, abi) except (SCons.Util.RegError, IntelCError): topdir = None if not topdir: # Normally this is an error, but it might not be if the compiler is # on $PATH and the user is importing their env. class ICLTopDirWarning(SCons.Warnings.Warning): pass if (is_mac or is_linux) and not env.Detect('icc') or \ is_windows and not env.Detect('icl'): SCons.Warnings.enableWarningClass(ICLTopDirWarning) SCons.Warnings.warn(ICLTopDirWarning, "Failed to find Intel compiler for version='%s', abi='%s'"% (str(version), str(abi))) else: # should be cleaned up to say what this other version is # since in this case we have some other Intel compiler installed SCons.Warnings.enableWarningClass(ICLTopDirWarning) SCons.Warnings.warn(ICLTopDirWarning, "Can't find Intel compiler top dir for version='%s', abi='%s'"% (str(version), str(abi))) if topdir: if verbose: print("Intel C compiler: using version %s (%g), abi %s, in '%s'"%\ (repr(version), linux_ver_normalize(version),abi,topdir)) if is_linux: # Show the actual compiler version by running the compiler. os.system('%s/bin/icc --version'%topdir) if is_mac: # Show the actual compiler version by running the compiler. os.system('%s/bin/icc --version'%topdir) env['INTEL_C_COMPILER_TOP'] = topdir if is_linux: paths={'INCLUDE' : 'include', 'LIB' : 'lib', 'PATH' : 'bin', 'LD_LIBRARY_PATH' : 'lib'} for p in paths.keys(): env.PrependENVPath(p, os.path.join(topdir, paths[p])) if is_mac: paths={'INCLUDE' : 'include', 'LIB' : 'lib', 'PATH' : 'bin', 'LD_LIBRARY_PATH' : 'lib'} for p in paths.keys(): env.PrependENVPath(p, os.path.join(topdir, paths[p])) if is_windows: # env key reg valname default subdir of top paths=(('INCLUDE', 'IncludeDir', 'Include'), ('LIB' , 'LibDir', 'Lib'), ('PATH' , 'BinDir', 'Bin')) # We are supposed to ignore version if topdir is set, so set # it to the emptry string if it's not already set. if version is None: version = '' # Each path has a registry entry, use that or default to subdir for p in paths: try: path=get_intel_registry_value(p[1], version, abi) # These paths may have $(ICInstallDir) # which needs to be substituted with the topdir. path=path.replace('$(ICInstallDir)', topdir + os.sep) except IntelCError: # Couldn't get it from registry: use default subdir of topdir env.PrependENVPath(p[0], os.path.join(topdir, p[2])) else: env.PrependENVPath(p[0], string.split(path, os.pathsep)) # print "ICL %s: %s, final=%s"%(p[0], path, str(env['ENV'][p[0]])) if is_windows: env['CC'] = 'icl' env['CXX'] = 'icl' env['LINK'] = 'xilink' else: env['CC'] = 'icc' env['CXX'] = 'icpc' # Don't reset LINK here; # use smart_link which should already be here from link.py. #env['LINK'] = '$CC' env['AR'] = 'xiar' env['LD'] = 'xild' # not used by default # This is not the exact (detailed) compiler version, # just the major version as determined above or specified # by the user. It is a float like 80 or 90, in normalized form for Linux # (i.e. even for Linux 9.0 compiler, still returns 90 rather than 9.0) if version: env['INTEL_C_COMPILER_VERSION']=linux_ver_normalize(version) if is_windows: # Look for license file dir # in system environment, registry, and default location. envlicdir = os.environ.get("INTEL_LICENSE_FILE", '') K = ('SOFTWARE\Intel\Licenses') try: k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K) reglicdir = SCons.Util.RegQueryValueEx(k, "w_cpp")[0] except (AttributeError, SCons.Util.RegError): reglicdir = "" defaultlicdir = r'C:\Program Files\Common Files\Intel\Licenses' licdir = None for ld in [envlicdir, reglicdir]: # If the string contains an '@', then assume it's a network # license (port@system) and good by definition. if ld and (string.find(ld, '@') != -1 or os.path.exists(ld)): licdir = ld break if not licdir: licdir = defaultlicdir if not os.path.exists(licdir): class ICLLicenseDirWarning(SCons.Warnings.Warning): pass SCons.Warnings.enableWarningClass(ICLLicenseDirWarning) SCons.Warnings.warn(ICLLicenseDirWarning, "Intel license dir was not found." " Tried using the INTEL_LICENSE_FILE environment variable (%s), the registry (%s) and the default path (%s)." " Using the default path as a last resort." % (envlicdir, reglicdir, defaultlicdir)) env['ENV']['INTEL_LICENSE_FILE'] = licdir def exists(env): if not (is_mac or is_linux or is_windows): # can't handle this platform return 0 try: versions = get_all_compiler_versions() except (SCons.Util.RegError, IntelCError): versions = None detected = versions is not None and len(versions) > 0 if not detected: # try env.Detect, maybe that will work if is_windows: return env.Detect('icl') elif is_linux: return env.Detect('icc') elif is_mac: return env.Detect('icc') return detected # end of file # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/g77.py0000644000175000017500000000465613606712377021272 0ustar kurtkurt"""engine.SCons.Tool.g77 Tool-specific initialization for g77. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/g77.py 4369 2009/09/19 15:58:29 scons" import SCons.Util from SCons.Tool.FortranCommon import add_all_to_env, add_f77_to_env compilers = ['g77', 'f77'] def generate(env): """Add Builders and construction variables for g77 to an Environment.""" add_all_to_env(env) add_f77_to_env(env) fcomp = env.Detect(compilers) or 'g77' if env['PLATFORM'] in ['cygwin', 'win32']: env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS') env['SHF77FLAGS'] = SCons.Util.CLVar('$F77FLAGS') else: env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -fPIC') env['SHF77FLAGS'] = SCons.Util.CLVar('$F77FLAGS -fPIC') env['FORTRAN'] = fcomp env['SHFORTRAN'] = '$FORTRAN' env['F77'] = fcomp env['SHF77'] = '$F77' env['INCFORTRANPREFIX'] = "-I" env['INCFORTRANSUFFIX'] = "" env['INCF77PREFIX'] = "-I" env['INCF77SUFFIX'] = "" def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/filesystem.py0000644000175000017500000000662313606712377023046 0ustar kurtkurt"""SCons.Tool.filesystem Tool-specific initialization for the filesystem tools. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/filesystem.py 4369 2009/09/19 15:58:29 scons" import SCons from SCons.Tool.install import copyFunc copyToBuilder, copyAsBuilder = None, None def copyto_emitter(target, source, env): """ changes the path of the source to be under the target (which are assumed to be directories. """ n_target = [] for t in target: n_target = n_target + map( lambda s, t=t: t.File( str( s ) ), source ) return (n_target, source) def copy_action_func(target, source, env): assert( len(target) == len(source) ), "\ntarget: %s\nsource: %s" %(map(str, target),map(str, source)) for t, s in zip(target, source): if copyFunc(t.get_path(), s.get_path(), env): return 1 return 0 def copy_action_str(target, source, env): return env.subst_target_source(env['COPYSTR'], 0, target, source) copy_action = SCons.Action.Action( copy_action_func, copy_action_str ) def generate(env): try: env['BUILDERS']['CopyTo'] env['BUILDERS']['CopyAs'] except KeyError as e: global copyToBuilder if copyToBuilder is None: copyToBuilder = SCons.Builder.Builder( action = copy_action, target_factory = env.fs.Dir, source_factory = env.fs.Entry, multi = 1, emitter = [ copyto_emitter, ] ) global copyAsBuilder if copyAsBuilder is None: copyAsBuilder = SCons.Builder.Builder( action = copy_action, target_factory = env.fs.Entry, source_factory = env.fs.Entry ) env['BUILDERS']['CopyTo'] = copyToBuilder env['BUILDERS']['CopyAs'] = copyAsBuilder env['COPYSTR'] = 'Copy file(s): "$SOURCES" to "$TARGETS"' def exists(env): return 1 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/jar.py0000644000175000017500000000743713606712377021442 0ustar kurtkurt"""SCons.Tool.jar Tool-specific initialization for jar. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/jar.py 4369 2009/09/19 15:58:29 scons" import SCons.Subst import SCons.Util def jarSources(target, source, env, for_signature): """Only include sources that are not a manifest file.""" try: env['JARCHDIR'] except KeyError: jarchdir_set = False else: jarchdir_set = True jarchdir = env.subst('$JARCHDIR', target=target, source=source) if jarchdir: jarchdir = env.fs.Dir(jarchdir) result = [] for src in source: contents = src.get_text_contents() if contents[:16] != "Manifest-Version": if jarchdir_set: _chdir = jarchdir else: try: _chdir = src.attributes.java_classdir except AttributeError: _chdir = None if _chdir: # If we are changing the dir with -C, then sources should # be relative to that directory. src = SCons.Subst.Literal(src.get_path(_chdir)) result.append('-C') result.append(_chdir) result.append(src) return result def jarManifest(target, source, env, for_signature): """Look in sources for a manifest file, if any.""" for src in source: contents = src.get_text_contents() if contents[:16] == "Manifest-Version": return src return '' def jarFlags(target, source, env, for_signature): """If we have a manifest, make sure that the 'm' flag is specified.""" jarflags = env.subst('$JARFLAGS', target=target, source=source) for src in source: contents = src.get_text_contents() if contents[:16] == "Manifest-Version": if not 'm' in jarflags: return jarflags + 'm' break return jarflags def generate(env): """Add Builders and construction variables for jar to an Environment.""" SCons.Tool.CreateJarBuilder(env) env['JAR'] = 'jar' env['JARFLAGS'] = SCons.Util.CLVar('cf') env['_JARFLAGS'] = jarFlags env['_JARMANIFEST'] = jarManifest env['_JARSOURCES'] = jarSources env['_JARCOM'] = '$JAR $_JARFLAGS $TARGET $_JARMANIFEST $_JARSOURCES' env['JARCOM'] = "${TEMPFILE('$_JARCOM')}" env['JARSUFFIX'] = '.jar' def exists(env): return env.Detect('jar') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/sunf77.py0000644000175000017500000000415613606712377022012 0ustar kurtkurt"""SCons.Tool.sunf77 Tool-specific initialization for sunf77, the Sun Studio F77 compiler. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/sunf77.py 4369 2009/09/19 15:58:29 scons" import SCons.Util from FortranCommon import add_all_to_env compilers = ['sunf77', 'f77'] def generate(env): """Add Builders and construction variables for sunf77 to an Environment.""" add_all_to_env(env) fcomp = env.Detect(compilers) or 'f77' env['FORTRAN'] = fcomp env['F77'] = fcomp env['SHFORTRAN'] = '$FORTRAN' env['SHF77'] = '$F77' env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -KPIC') env['SHF77FLAGS'] = SCons.Util.CLVar('$F77FLAGS -KPIC') def exists(env): return env.Detect(compilers) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Tool/msvs.py0000644000175000017500000015133313606712377021651 0ustar kurtkurt"""SCons.Tool.msvs Tool-specific initialization for Microsoft Visual Studio project files. There normally shouldn't be any need to import this module directly. It will usually be imported through the generic SCons.Tool.Tool() selection method. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Tool/msvs.py 4369 2009/09/19 15:58:29 scons" import base64 import hashlib import ntpath import os import pickle import re import string import sys import SCons.Builder import SCons.Node.FS import SCons.Platform.win32 import SCons.Script.SConscript import SCons.Util import SCons.Warnings from MSCommon import msvs_exists, merge_default_version from SCons.Defaults import processDefines ############################################################################## # Below here are the classes and functions for generation of # DSP/DSW/SLN/VCPROJ files. ############################################################################## def _hexdigest(s): """Return a string as a string of hex characters. """ # NOTE: This routine is a method in the Python 2.0 interface # of the native md5 module, but we want SCons to operate all # the way back to at least Python 1.5.2, which doesn't have it. h = string.hexdigits r = '' for c in s: i = ord(c) r = r + h[(i >> 4) & 0xF] + h[i & 0xF] return r def xmlify(s): s = string.replace(s, "&", "&") # do this first s = string.replace(s, "'", "'") s = string.replace(s, '"', """) return s external_makefile_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}' def _generateGUID(slnfile, name): """This generates a dummy GUID for the sln file to use. It is based on the MD5 signatures of the sln filename plus the name of the project. It basically just needs to be unique, and not change with each invocation.""" m = hashlib.md5() # Normalize the slnfile path to a Windows path (\ separators) so # the generated file has a consistent GUID even if we generate # it on a non-Windows platform. m.update(ntpath.normpath(str(slnfile)) + str(name)) # TODO(1.5) #solution = m.hexdigest().upper() solution = string.upper(_hexdigest(m.digest())) # convert most of the signature to GUID form (discard the rest) solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:20] + "-" + solution[20:32] + "}" return solution version_re = re.compile(r'(\d+\.\d+)(.*)') def msvs_parse_version(s): """ Split a Visual Studio version, which may in fact be something like '7.0Exp', into is version number (returned as a float) and trailing "suite" portion. """ num, suite = version_re.match(s).groups() return float(num), suite # This is how we re-invoke SCons from inside MSVS Project files. # The problem is that we might have been invoked as either scons.bat # or scons.py. If we were invoked directly as scons.py, then we could # use sys.argv[0] to find the SCons "executable," but that doesn't work # if we were invoked as scons.bat, which uses "python -c" to execute # things and ends up with "-c" as sys.argv[0]. Consequently, we have # the MSVS Project file invoke SCons the same way that scons.bat does, # which works regardless of how we were invoked. def getExecScriptMain(env, xml=None): scons_home = env.get('SCONS_HOME') if not scons_home and 'SCONS_LIB_DIR' in os.environ: scons_home = os.environ['SCONS_LIB_DIR'] if scons_home: exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % scons_home else: version = SCons.__version__ exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-%(version)s'), join(sys.prefix, 'scons-%(version)s'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" % locals() if xml: exec_script_main = xmlify(exec_script_main) return exec_script_main # The string for the Python executable we tell the Project file to use # is either sys.executable or, if an external PYTHON_ROOT environment # variable exists, $(PYTHON)ROOT\\python.exe (generalized a little to # pluck the actual executable name from sys.executable). try: python_root = os.environ['PYTHON_ROOT'] except KeyError: python_executable = sys.executable else: python_executable = os.path.join('$$(PYTHON_ROOT)', os.path.split(sys.executable)[1]) class Config: pass def splitFully(path): dir, base = os.path.split(path) if dir and dir != '' and dir != path: return splitFully(dir)+[base] if base == '': return [] return [base] def makeHierarchy(sources): '''Break a list of files into a hierarchy; for each value, if it is a string, then it is a file. If it is a dictionary, it is a folder. The string is the original path of the file.''' hierarchy = {} for file in sources: path = splitFully(file) if len(path): dict = hierarchy for part in path[:-1]: if part not in dict: dict[part] = {} dict = dict[part] dict[path[-1]] = file #else: # print 'Warning: failed to decompose path for '+str(file) return hierarchy class _DSPGenerator: """ Base class for DSP generators """ srcargs = [ 'srcs', 'incs', 'localincs', 'resources', 'misc'] def __init__(self, dspfile, source, env): self.dspfile = str(dspfile) try: get_abspath = dspfile.get_abspath except AttributeError: self.dspabs = os.path.abspath(dspfile) else: self.dspabs = get_abspath() if 'variant' not in env: raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\ "'Release') to create an MSVSProject.") elif SCons.Util.is_String(env['variant']): variants = [env['variant']] elif SCons.Util.is_List(env['variant']): variants = env['variant'] if 'buildtarget' not in env or env['buildtarget'] == None: buildtarget = [''] elif SCons.Util.is_String(env['buildtarget']): buildtarget = [env['buildtarget']] elif SCons.Util.is_List(env['buildtarget']): if len(env['buildtarget']) != len(variants): raise SCons.Errors.InternalError("Sizes of 'buildtarget' and 'variant' lists must be the same.") buildtarget = [] for bt in env['buildtarget']: if SCons.Util.is_String(bt): buildtarget.append(bt) else: buildtarget.append(bt.get_abspath()) else: buildtarget = [env['buildtarget'].get_abspath()] if len(buildtarget) == 1: bt = buildtarget[0] buildtarget = [] for _ in variants: buildtarget.append(bt) if 'outdir' not in env or env['outdir'] == None: outdir = [''] elif SCons.Util.is_String(env['outdir']): outdir = [env['outdir']] elif SCons.Util.is_List(env['outdir']): if len(env['outdir']) != len(variants): raise SCons.Errors.InternalError("Sizes of 'outdir' and 'variant' lists must be the same.") outdir = [] for s in env['outdir']: if SCons.Util.is_String(s): outdir.append(s) else: outdir.append(s.get_abspath()) else: outdir = [env['outdir'].get_abspath()] if len(outdir) == 1: s = outdir[0] outdir = [] for v in variants: outdir.append(s) if 'runfile' not in env or env['runfile'] == None: runfile = buildtarget[-1:] elif SCons.Util.is_String(env['runfile']): runfile = [env['runfile']] elif SCons.Util.is_List(env['runfile']): if len(env['runfile']) != len(variants): raise SCons.Errors.InternalError("Sizes of 'runfile' and 'variant' lists must be the same.") runfile = [] for s in env['runfile']: if SCons.Util.is_String(s): runfile.append(s) else: runfile.append(s.get_abspath()) else: runfile = [env['runfile'].get_abspath()] if len(runfile) == 1: s = runfile[0] runfile = [] for v in variants: runfile.append(s) self.sconscript = env['MSVSSCONSCRIPT'] cmdargs = env.get('cmdargs', '') self.env = env if 'name' in self.env: self.name = self.env['name'] else: self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0]) self.name = self.env.subst(self.name) sourcenames = [ 'Source Files', 'Header Files', 'Local Headers', 'Resource Files', 'Other Files'] self.sources = {} for n in sourcenames: self.sources[n] = [] self.configs = {} self.nokeep = 0 if 'nokeep' in env and env['variant'] != 0: self.nokeep = 1 if self.nokeep == 0 and os.path.exists(self.dspabs): self.Parse() for t in zip(sourcenames,self.srcargs): if t[1] in self.env: if SCons.Util.is_List(self.env[t[1]]): for i in self.env[t[1]]: if not i in self.sources[t[0]]: self.sources[t[0]].append(i) else: if not self.env[t[1]] in self.sources[t[0]]: self.sources[t[0]].append(self.env[t[1]]) for n in sourcenames: # TODO(1.5): #self.sources[n].sort(lambda a, b: cmp(a.lower(), b.lower())) self.sources[n].sort(lambda a, b: cmp(string.lower(a), string.lower(b))) def AddConfig(self, variant, buildtarget, outdir, runfile, cmdargs, dspfile=dspfile): config = Config() config.buildtarget = buildtarget config.outdir = outdir config.cmdargs = cmdargs config.runfile = runfile match = re.match('(.*)\|(.*)', variant) if match: config.variant = match.group(1) config.platform = match.group(2) else: config.variant = variant config.platform = 'Win32' self.configs[variant] = config print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'") for i in range(len(variants)): AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs) self.platforms = [] for key in self.configs.keys(): platform = self.configs[key].platform if not platform in self.platforms: self.platforms.append(platform) def Build(self): pass V6DSPHeader = """\ # Microsoft Developer Studio Project File - Name="%(name)s" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) External Target" 0x0106 CFG=%(name)s - Win32 %(confkey)s !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "%(name)s.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "%(name)s.mak" CFG="%(name)s - Win32 %(confkey)s" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE """ class _GenerateV6DSP(_DSPGenerator): """Generates a Project file for MSVS 6.0""" def PrintHeader(self): # pick a default config confkeys = sorted(self.configs.keys()) name = self.name confkey = confkeys[0] self.file.write(V6DSPHeader % locals()) for kind in confkeys: self.file.write('!MESSAGE "%s - Win32 %s" (based on "Win32 (x86) External Target")\n' % (name, kind)) self.file.write('!MESSAGE \n\n') def PrintProject(self): name = self.name self.file.write('# Begin Project\n' '# PROP AllowPerConfigDependencies 0\n' '# PROP Scc_ProjName ""\n' '# PROP Scc_LocalPath ""\n\n') first = 1 confkeys = sorted(self.configs.keys()) for kind in confkeys: outdir = self.configs[kind].outdir buildtarget = self.configs[kind].buildtarget if first == 1: self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind)) first = 0 else: self.file.write('\n!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind)) env_has_buildtarget = 'MSVSBUILDTARGET' in self.env if not env_has_buildtarget: self.env['MSVSBUILDTARGET'] = buildtarget # have to write this twice, once with the BASE settings, and once without for base in ("BASE ",""): self.file.write('# PROP %sUse_MFC 0\n' '# PROP %sUse_Debug_Libraries ' % (base, base)) # TODO(1.5): #if kind.lower().find('debug') < 0: if string.find(string.lower(kind), 'debug') < 0: self.file.write('0\n') else: self.file.write('1\n') self.file.write('# PROP %sOutput_Dir "%s"\n' '# PROP %sIntermediate_Dir "%s"\n' % (base,outdir,base,outdir)) cmd = 'echo Starting SCons && ' + self.env.subst('$MSVSBUILDCOM', 1) self.file.write('# PROP %sCmd_Line "%s"\n' '# PROP %sRebuild_Opt "-c && %s"\n' '# PROP %sTarget_File "%s"\n' '# PROP %sBsc_Name ""\n' '# PROP %sTarget_Dir ""\n'\ %(base,cmd,base,cmd,base,buildtarget,base,base)) if not env_has_buildtarget: del self.env['MSVSBUILDTARGET'] self.file.write('\n!ENDIF\n\n' '# Begin Target\n\n') for kind in confkeys: self.file.write('# Name "%s - Win32 %s"\n' % (name,kind)) self.file.write('\n') first = 0 for kind in confkeys: if first == 0: self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind)) first = 1 else: self.file.write('!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind)) self.file.write('!ENDIF \n\n') self.PrintSourceFiles() self.file.write('# End Target\n' '# End Project\n') if self.nokeep == 0: # now we pickle some data and add it to the file -- MSDEV will ignore it. pdata = pickle.dumps(self.configs,1) pdata = base64.encodestring(pdata) self.file.write(pdata + '\n') pdata = pickle.dumps(self.sources,1) pdata = base64.encodestring(pdata) self.file.write(pdata + '\n') def PrintSourceFiles(self): categories = {'Source Files': 'cpp|c|cxx|l|y|def|odl|idl|hpj|bat', 'Header Files': 'h|hpp|hxx|hm|inl', 'Local Headers': 'h|hpp|hxx|hm|inl', 'Resource Files': 'r|rc|ico|cur|bmp|dlg|rc2|rct|bin|cnt|rtf|gif|jpg|jpeg|jpe', 'Other Files': ''} cats = categories.keys() # TODO(1.5): #cats.sort(lambda a, b: cmp(a.lower(), b.lower())) cats.sort(lambda a, b: cmp(string.lower(a), string.lower(b))) for kind in cats: if not self.sources[kind]: continue # skip empty groups self.file.write('# Begin Group "' + kind + '"\n\n') # TODO(1.5) #typelist = categories[kind].replace('|', ';') typelist = string.replace(categories[kind], '|', ';') self.file.write('# PROP Default_Filter "' + typelist + '"\n') for file in self.sources[kind]: file = os.path.normpath(file) self.file.write('# Begin Source File\n\n' 'SOURCE="' + file + '"\n' '# End Source File\n') self.file.write('# End Group\n') # add the SConscript file outside of the groups self.file.write('# Begin Source File\n\n' 'SOURCE="' + str(self.sconscript) + '"\n' '# End Source File\n') def Parse(self): try: dspfile = open(self.dspabs,'r') except IOError: return # doesn't exist yet, so can't add anything to configs. line = dspfile.readline() while line: # TODO(1.5): #if line.find("# End Project") > -1: if string.find(line, "# End Project") > -1: break line = dspfile.readline() line = dspfile.readline() datas = line while line and line != '\n': line = dspfile.readline() datas = datas + line # OK, we've found our little pickled cache of data. try: datas = base64.decodestring(datas) data = pickle.loads(datas) except KeyboardInterrupt: raise except: return # unable to unpickle any data for some reason self.configs.update(data) data = None line = dspfile.readline() datas = line while line and line != '\n': line = dspfile.readline() datas = datas + line # OK, we've found our little pickled cache of data. # it has a "# " in front of it, so we strip that. try: datas = base64.decodestring(datas) data = pickle.loads(datas) except KeyboardInterrupt: raise except: return # unable to unpickle any data for some reason self.sources.update(data) def Build(self): try: self.file = open(self.dspabs,'w') except IOError as detail: raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) else: self.PrintHeader() self.PrintProject() self.file.close() V7DSPHeader = """\ """ V7DSPConfiguration = """\ \t\t \t\t\t \t\t """ V8DSPHeader = """\ """ V8DSPConfiguration = """\ \t\t \t\t\t \t\t """ class _GenerateV7DSP(_DSPGenerator): """Generates a Project file for MSVS .NET""" def __init__(self, dspfile, source, env): _DSPGenerator.__init__(self, dspfile, source, env) self.version = env['MSVS_VERSION'] self.version_num, self.suite = msvs_parse_version(self.version) if self.version_num >= 8.0: self.versionstr = '8.00' self.dspheader = V8DSPHeader self.dspconfiguration = V8DSPConfiguration else: if self.version_num >= 7.1: self.versionstr = '7.10' else: self.versionstr = '7.00' self.dspheader = V7DSPHeader self.dspconfiguration = V7DSPConfiguration self.file = None def PrintHeader(self): env = self.env versionstr = self.versionstr name = self.name encoding = self.env.subst('$MSVSENCODING') scc_provider = env.get('MSVS_SCC_PROVIDER', '') scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '') scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '') scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '') project_guid = env.get('MSVS_PROJECT_GUID', '') if self.version_num >= 8.0 and not project_guid: project_guid = _generateGUID(self.dspfile, '') if scc_provider != '': scc_attrs = ('\tProjectGUID="%s"\n' '\tSccProjectName="%s"\n' '\tSccAuxPath="%s"\n' '\tSccLocalPath="%s"\n' '\tSccProvider="%s"' % (project_guid, scc_project_name, scc_aux_path, scc_local_path, scc_provider)) else: scc_attrs = ('\tProjectGUID="%s"\n' '\tSccProjectName="%s"\n' '\tSccLocalPath="%s"' % (project_guid, scc_project_name, scc_local_path)) self.file.write(self.dspheader % locals()) self.file.write('\t\n') for platform in self.platforms: self.file.write( '\t\t\n' % platform) self.file.write('\t\n') if self.version_num >= 8.0: self.file.write('\t\n' '\t\n') def PrintProject(self): self.file.write('\t\n') confkeys = sorted(self.configs.keys()) for kind in confkeys: variant = self.configs[kind].variant platform = self.configs[kind].platform outdir = self.configs[kind].outdir buildtarget = self.configs[kind].buildtarget runfile = self.configs[kind].runfile cmdargs = self.configs[kind].cmdargs env_has_buildtarget = 'MSVSBUILDTARGET' in self.env if not env_has_buildtarget: self.env['MSVSBUILDTARGET'] = buildtarget starting = 'echo Starting SCons && ' if cmdargs: cmdargs = ' ' + cmdargs else: cmdargs = '' buildcmd = xmlify(starting + self.env.subst('$MSVSBUILDCOM', 1) + cmdargs) rebuildcmd = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1) + cmdargs) cleancmd = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1) + cmdargs) # TODO(1.5) #preprocdefs = xmlify(';'.join(self.env.get('CPPDEFINES', []))) #includepath = xmlify(';'.join(self.env.get('CPPPATH', []))) preprocdefs = xmlify(string.join(processDefines(self.env.get('CPPDEFINES', [])), ';')) includepath = xmlify(string.join(self.env.get('CPPPATH', []), ';')) if not env_has_buildtarget: del self.env['MSVSBUILDTARGET'] self.file.write(self.dspconfiguration % locals()) self.file.write('\t\n') if self.version_num >= 7.1: self.file.write('\t\n' '\t\n') self.PrintSourceFiles() self.file.write('\n') if self.nokeep == 0: # now we pickle some data and add it to the file -- MSDEV will ignore it. pdata = pickle.dumps(self.configs,1) pdata = base64.encodestring(pdata) self.file.write('\n') def printSources(self, hierarchy, commonprefix): sorteditems = hierarchy.items() # TODO(1.5): #sorteditems.sort(lambda a, b: cmp(a[0].lower(), b[0].lower())) sorteditems.sort(lambda a, b: cmp(string.lower(a[0]), string.lower(b[0]))) # First folders, then files for key, value in sorteditems: if SCons.Util.is_Dict(value): self.file.write('\t\t\t\n' % (key)) self.printSources(value, commonprefix) self.file.write('\t\t\t\n') for key, value in sorteditems: if SCons.Util.is_String(value): file = value if commonprefix: file = os.path.join(commonprefix, value) file = os.path.normpath(file) self.file.write('\t\t\t\n' '\t\t\t\n' % (file)) def PrintSourceFiles(self): categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat', 'Header Files': 'h;hpp;hxx;hm;inl', 'Local Headers': 'h;hpp;hxx;hm;inl', 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe', 'Other Files': ''} self.file.write('\t\n') cats = categories.keys() # TODO(1.5) #cats.sort(lambda a, b: cmp(a.lower(), b.lower())) cats.sort(lambda a, b: cmp(string.lower(a), string.lower(b))) cats = filter(lambda k, s=self: s.sources[k], cats) for kind in cats: if len(cats) > 1: self.file.write('\t\t\n' % (kind, categories[kind])) sources = self.sources[kind] # First remove any common prefix commonprefix = None if len(sources) > 1: s = map(os.path.normpath, sources) # take the dirname because the prefix may include parts # of the filenames (e.g. if you have 'dir\abcd' and # 'dir\acde' then the cp will be 'dir\a' ) cp = os.path.dirname( os.path.commonprefix(s) ) if cp and s[0][len(cp)] == os.sep: # +1 because the filename starts after the separator sources = map(lambda s, l=len(cp)+1: s[l:], sources) commonprefix = cp elif len(sources) == 1: commonprefix = os.path.dirname( sources[0] ) sources[0] = os.path.basename( sources[0] ) hierarchy = makeHierarchy(sources) self.printSources(hierarchy, commonprefix=commonprefix) if len(cats)>1: self.file.write('\t\t\n') # add the SConscript file outside of the groups self.file.write('\t\t\n' '\t\t\n' % str(self.sconscript)) self.file.write('\t\n' '\t\n' '\t\n') def Parse(self): try: dspfile = open(self.dspabs,'r') except IOError: return # doesn't exist yet, so can't add anything to configs. line = dspfile.readline() while line: # TODO(1.5) #if line.find(' Node B(Pending) --> Node C (NoState) ^ | | | +-------------------------------------+ Now, when the Taskmaster examines the Node C's child Node A, it finds that Node A is in the "pending" state. Therefore, Node A is a pending child of node C. Pending children indicate that the Taskmaster has potentially loop back through a cycle. We say potentially because it could also occur when a DAG is evaluated in parallel. For example, consider the following graph: Node A (Pending) --> Node B(Pending) --> Node C (Pending) --> ... | ^ | | +----------> Node D (NoState) --------+ / Next candidate / The Taskmaster first evaluates the nodes A, B, and C and starts building some children of node C. Assuming, that the maximum parallel level has not been reached, the Taskmaster will examine Node D. It will find that Node C is a pending child of Node D. In summary, evaluating a graph with a cycle will always involve a pending child at one point. A pending child might indicate either a cycle or a diamond-shaped DAG. Only a fraction of the nodes ends-up being a "pending child" of another node. This keeps the pending_children set small in practice. We can differentiate between the two cases if we wait until the end of the build. At this point, all the pending children nodes due to a diamond-shaped DAG will have been properly built (or will have failed to build). But, the pending children involved in a cycle will still be in the pending state. The taskmaster removes nodes from the pending_children set as soon as a pending_children node moves out of the pending state. This also helps to keep the pending_children set small. """ for n in self.pending_children: assert n.state in (NODE_PENDING, NODE_EXECUTING), \ (str(n), StateString[n.state]) assert len(n.waiting_parents) != 0, (str(n), len(n.waiting_parents)) for p in n.waiting_parents: assert p.ref_count > 0, (str(n), str(p), p.ref_count) def trace_message(self, message): return 'Taskmaster: %s\n' % message def trace_node(self, node): return '<%-10s %-3s %s>' % (StateString[node.get_state()], node.ref_count, repr(str(node))) def _find_next_ready_node(self): """ Finds the next node that is ready to be built. This is *the* main guts of the DAG walk. We loop through the list of candidates, looking for something that has no un-built children (i.e., that is a leaf Node or has dependencies that are all leaf Nodes or up-to-date). Candidate Nodes are re-scanned (both the target Node itself and its sources, which are always scanned in the context of a given target) to discover implicit dependencies. A Node that must wait for some children to be built will be put back on the candidates list after the children have finished building. A Node that has been put back on the candidates list in this way may have itself (or its sources) re-scanned, in order to handle generated header files (e.g.) and the implicit dependencies therein. Note that this method does not do any signature calculation or up-to-date check itself. All of that is handled by the Task class. This is purely concerned with the dependency graph walk. """ self.ready_exc = None T = self.trace if T: T.write('\n' + self.trace_message('Looking for a node to evaluate')) while True: node = self.next_candidate() if node is None: if T: T.write(self.trace_message('No candidate anymore.') + '\n') return None node = node.disambiguate() state = node.get_state() # For debugging only: # # try: # self._validate_pending_children() # except: # self.ready_exc = sys.exc_info() # return node if CollectStats: if not hasattr(node, 'stats'): node.stats = Stats() StatsNodes.append(node) S = node.stats S.considered = S.considered + 1 else: S = None if T: T.write(self.trace_message(' Considering node %s and its children:' % self.trace_node(node))) if state == NODE_NO_STATE: # Mark this node as being on the execution stack: node.set_state(NODE_PENDING) elif state > NODE_PENDING: # Skip this node if it has already been evaluated: if S: S.already_handled = S.already_handled + 1 if T: T.write(self.trace_message(' already handled (executed)')) continue executor = node.get_executor() try: children = executor.get_all_children() except SystemExit: exc_value = sys.exc_info()[1] e = SCons.Errors.ExplicitExit(node, exc_value.code) self.ready_exc = (SCons.Errors.ExplicitExit, e) if T: T.write(self.trace_message(' SystemExit')) return node except Exception as e: # We had a problem just trying to figure out the # children (like a child couldn't be linked in to a # VariantDir, or a Scanner threw something). Arrange to # raise the exception when the Task is "executed." self.ready_exc = sys.exc_info() if S: S.problem = S.problem + 1 if T: T.write(self.trace_message(' exception %s while scanning children.\n' % e)) return node children_not_visited = [] children_pending = set() children_not_ready = [] children_failed = False for child in chain(executor.get_all_prerequisites(), children): childstate = child.get_state() if T: T.write(self.trace_message(' ' + self.trace_node(child))) if childstate == NODE_NO_STATE: children_not_visited.append(child) elif childstate == NODE_PENDING: children_pending.add(child) elif childstate == NODE_FAILED: children_failed = True if childstate <= NODE_EXECUTING: children_not_ready.append(child) # These nodes have not even been visited yet. Add # them to the list so that on some next pass we can # take a stab at evaluating them (or their children). children_not_visited.reverse() self.candidates.extend(self.order(children_not_visited)) #if T and children_not_visited: # T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited))) # T.write(self.trace_message(' candidates now: %s\n' % map(str, self.candidates))) # Skip this node if any of its children have failed. # # This catches the case where we're descending a top-level # target and one of our children failed while trying to be # built by a *previous* descent of an earlier top-level # target. # # It can also occur if a node is reused in multiple # targets. One first descends though the one of the # target, the next time occurs through the other target. # # Note that we can only have failed_children if the # --keep-going flag was used, because without it the build # will stop before diving in the other branch. # # Note that even if one of the children fails, we still # added the other children to the list of candidate nodes # to keep on building (--keep-going). if children_failed: for n in executor.get_action_targets(): n.set_state(NODE_FAILED) if S: S.child_failed = S.child_failed + 1 if T: T.write(self.trace_message('****** %s\n' % self.trace_node(node))) continue if children_not_ready: for child in children_not_ready: # We're waiting on one or more derived targets # that have not yet finished building. if S: S.not_built = S.not_built + 1 # Add this node to the waiting parents lists of # anything we're waiting on, with a reference # count so we can be put back on the list for # re-evaluation when they've all finished. node.ref_count = node.ref_count + child.add_to_waiting_parents(node) if T: T.write(self.trace_message(' adjusted ref count: %s, child %s' % (self.trace_node(node), repr(str(child))))) if T: for pc in children_pending: T.write(self.trace_message(' adding %s to the pending children set\n' % self.trace_node(pc))) self.pending_children = self.pending_children | children_pending continue # Skip this node if it has side-effects that are # currently being built: wait_side_effects = False for se in executor.get_action_side_effects(): if se.get_state() == NODE_EXECUTING: se.add_to_waiting_s_e(node) wait_side_effects = True if wait_side_effects: if S: S.side_effects = S.side_effects + 1 continue # The default when we've gotten through all of the checks above: # this node is ready to be built. if S: S.build = S.build + 1 if T: T.write(self.trace_message('Evaluating %s\n' % self.trace_node(node))) # For debugging only: # # try: # self._validate_pending_children() # except: # self.ready_exc = sys.exc_info() # return node return node return None def next_task(self): """ Returns the next task to be executed. This simply asks for the next Node to be evaluated, and then wraps it in the specific Task subclass with which we were initialized. """ node = self._find_next_ready_node() if node is None: return None tlist = node.get_executor().get_all_targets() task = self.tasker(self, tlist, node in self.original_top, node) try: task.make_ready() except: # We had a problem just trying to get this task ready (like # a child couldn't be linked in to a VariantDir when deciding # whether this node is current). Arrange to raise the # exception when the Task is "executed." self.ready_exc = sys.exc_info() if self.ready_exc: task.exception_set(self.ready_exc) self.ready_exc = None return task def will_not_build(self, nodes, node_func=lambda n: None): """ Perform clean-up about nodes that will never be built. Invokes a user defined function on all of these nodes (including all of their parents). """ T = self.trace pending_children = self.pending_children to_visit = set(nodes) pending_children = pending_children - to_visit if T: for n in nodes: T.write(self.trace_message(' removing node %s from the pending children set\n' % self.trace_node(n))) try: while True: try: node = to_visit.pop() except AttributeError: # Python 1.5.2 if len(to_visit): node = to_visit[0] to_visit.remove(node) else: break node_func(node) # Prune recursion by flushing the waiting children # list immediately. parents = node.waiting_parents node.waiting_parents = set() to_visit = to_visit | parents pending_children = pending_children - parents for p in parents: p.ref_count = p.ref_count - 1 if T: T.write(self.trace_message(' removing parent %s from the pending children set\n' % self.trace_node(p))) except KeyError: # The container to_visit has been emptied. pass # We have the stick back the pending_children list into the # task master because the python 1.5.2 compatibility does not # allow us to use in-place updates self.pending_children = pending_children def stop(self): """ Stops the current build completely. """ self.next_candidate = self.no_next_candidate def cleanup(self): """ Check for dependency cycles. """ if not self.pending_children: return # TODO(1.5) #nclist = [ (n, find_cycle([n], set())) for n in self.pending_children ] nclist = map(lambda n: (n, find_cycle([n], set())), self.pending_children) # TODO(1.5) #genuine_cycles = [ # node for node, cycle in nclist # if cycle or node.get_state() != NODE_EXECUTED #] genuine_cycles = filter(lambda t: t[1] or t[0].get_state() != NODE_EXECUTED, nclist) if not genuine_cycles: # All of the "cycles" found were single nodes in EXECUTED state, # which is to say, they really weren't cycles. Just return. return desc = 'Found dependency cycle(s):\n' for node, cycle in nclist: if cycle: desc = desc + " " + string.join(map(str, cycle), " -> ") + "\n" else: desc = desc + \ " Internal Error: no cycle found for node %s (%s) in state %s\n" % \ (node, repr(node), StateString[node.get_state()]) raise SCons.Errors.UserError(desc) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Job.py0000644000175000017500000003744613606712377020466 0ustar kurtkurt"""SCons.Job This module defines the Serial and Parallel classes that execute tasks to complete a build. The Jobs class provides a higher level interface to start, stop, and wait on jobs. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Job.py 4369 2009/09/19 15:58:29 scons" import os import signal import SCons.Errors # The default stack size (in kilobytes) of the threads used to execute # jobs in parallel. # # We use a stack size of 256 kilobytes. The default on some platforms # is too large and prevents us from creating enough threads to fully # parallelized the build. For example, the default stack size on linux # is 8 MBytes. explicit_stack_size = None default_stack_size = 256 interrupt_msg = 'Build interrupted.' class InterruptState: def __init__(self): self.interrupted = False def set(self): self.interrupted = True def __call__(self): return self.interrupted class Jobs: """An instance of this class initializes N jobs, and provides methods for starting, stopping, and waiting on all N jobs. """ def __init__(self, num, taskmaster): """ create 'num' jobs using the given taskmaster. If 'num' is 1 or less, then a serial job will be used, otherwise a parallel job with 'num' worker threads will be used. The 'num_jobs' attribute will be set to the actual number of jobs allocated. If more than one job is requested but the Parallel class can't do it, it gets reset to 1. Wrapping interfaces that care should check the value of 'num_jobs' after initialization. """ self.job = None if num > 1: stack_size = explicit_stack_size if stack_size is None: stack_size = default_stack_size try: self.job = Parallel(taskmaster, num, stack_size) self.num_jobs = num except NameError: pass if self.job is None: self.job = Serial(taskmaster) self.num_jobs = 1 def run(self, postfunc=lambda: None): """Run the jobs. postfunc() will be invoked after the jobs has run. It will be invoked even if the jobs are interrupted by a keyboard interrupt (well, in fact by a signal such as either SIGINT, SIGTERM or SIGHUP). The execution of postfunc() is protected against keyboard interrupts and is guaranteed to run to completion.""" self._setup_sig_handler() try: self.job.start() finally: postfunc() self._reset_sig_handler() def were_interrupted(self): """Returns whether the jobs were interrupted by a signal.""" return self.job.interrupted() def _setup_sig_handler(self): """Setup an interrupt handler so that SCons can shutdown cleanly in various conditions: a) SIGINT: Keyboard interrupt b) SIGTERM: kill or system shutdown c) SIGHUP: Controlling shell exiting We handle all of these cases by stopping the taskmaster. It turns out that it very difficult to stop the build process by throwing asynchronously an exception such as KeyboardInterrupt. For example, the python Condition variables (threading.Condition) and Queue's do not seem to asynchronous-exception-safe. It would require adding a whole bunch of try/finally block and except KeyboardInterrupt all over the place. Note also that we have to be careful to handle the case when SCons forks before executing another process. In that case, we want the child to exit immediately. """ def handler(signum, stack, self=self, parentpid=os.getpid()): if os.getpid() == parentpid: self.job.taskmaster.stop() self.job.interrupted.set() else: os._exit(2) self.old_sigint = signal.signal(signal.SIGINT, handler) self.old_sigterm = signal.signal(signal.SIGTERM, handler) try: self.old_sighup = signal.signal(signal.SIGHUP, handler) except AttributeError: pass def _reset_sig_handler(self): """Restore the signal handlers to their previous state (before the call to _setup_sig_handler().""" signal.signal(signal.SIGINT, self.old_sigint) signal.signal(signal.SIGTERM, self.old_sigterm) try: signal.signal(signal.SIGHUP, self.old_sighup) except AttributeError: pass class Serial: """This class is used to execute tasks in series, and is more efficient than Parallel, but is only appropriate for non-parallel builds. Only one instance of this class should be in existence at a time. This class is not thread safe. """ def __init__(self, taskmaster): """Create a new serial job given a taskmaster. The taskmaster's next_task() method should return the next task that needs to be executed, or None if there are no more tasks. The taskmaster's executed() method will be called for each task when it is successfully executed or failed() will be called if it failed to execute (e.g. execute() raised an exception).""" self.taskmaster = taskmaster self.interrupted = InterruptState() def start(self): """Start the job. This will begin pulling tasks from the taskmaster and executing them, and return when there are no more tasks. If a task fails to execute (i.e. execute() raises an exception), then the job will stop.""" while True: task = self.taskmaster.next_task() if task is None: break try: task.prepare() if task.needs_execute(): task.execute() except: if self.interrupted(): try: raise SCons.Errors.BuildError( task.targets[0], errstr=interrupt_msg) except: task.exception_set() else: task.exception_set() # Let the failed() callback function arrange for the # build to stop if that's appropriate. task.failed() else: task.executed() task.postprocess() self.taskmaster.cleanup() # Trap import failure so that everything in the Job module but the # Parallel class (and its dependent classes) will work if the interpreter # doesn't support threads. try: import Queue import threading except ImportError: pass else: class Worker(threading.Thread): """A worker thread waits on a task to be posted to its request queue, dequeues the task, executes it, and posts a tuple including the task and a boolean indicating whether the task executed successfully. """ def __init__(self, requestQueue, resultsQueue, interrupted): threading.Thread.__init__(self) self.setDaemon(1) self.requestQueue = requestQueue self.resultsQueue = resultsQueue self.interrupted = interrupted self.start() def run(self): while True: task = self.requestQueue.get() if task is None: # The "None" value is used as a sentinel by # ThreadPool.cleanup(). This indicates that there # are no more tasks, so we should quit. break try: if self.interrupted(): raise SCons.Errors.BuildError( task.targets[0], errstr=interrupt_msg) task.execute() except: task.exception_set() ok = False else: ok = True self.resultsQueue.put((task, ok)) class ThreadPool: """This class is responsible for spawning and managing worker threads.""" def __init__(self, num, stack_size, interrupted): """Create the request and reply queues, and 'num' worker threads. One must specify the stack size of the worker threads. The stack size is specified in kilobytes. """ self.requestQueue = Queue.Queue(0) self.resultsQueue = Queue.Queue(0) try: prev_size = threading.stack_size(stack_size*1024) except AttributeError as e: # Only print a warning if the stack size has been # explicitly set. if not explicit_stack_size is None: msg = "Setting stack size is unsupported by this version of Python:\n " + \ e.args[0] SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg) except ValueError as e: msg = "Setting stack size failed:\n " + str(e) SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg) # Create worker threads self.workers = [] for _ in range(num): worker = Worker(self.requestQueue, self.resultsQueue, interrupted) self.workers.append(worker) # Once we drop Python 1.5 we can change the following to: #if 'prev_size' in locals(): if 'prev_size' in locals().keys(): threading.stack_size(prev_size) def put(self, task): """Put task into request queue.""" self.requestQueue.put(task) def get(self): """Remove and return a result tuple from the results queue.""" return self.resultsQueue.get() def preparation_failed(self, task): self.resultsQueue.put((task, False)) def cleanup(self): """ Shuts down the thread pool, giving each worker thread a chance to shut down gracefully. """ # For each worker thread, put a sentinel "None" value # on the requestQueue (indicating that there's no work # to be done) so that each worker thread will get one and # terminate gracefully. for _ in self.workers: self.requestQueue.put(None) # Wait for all of the workers to terminate. # # If we don't do this, later Python versions (2.4, 2.5) often # seem to raise exceptions during shutdown. This happens # in requestQueue.get(), as an assertion failure that # requestQueue.not_full is notified while not acquired, # seemingly because the main thread has shut down (or is # in the process of doing so) while the workers are still # trying to pull sentinels off the requestQueue. # # Normally these terminations should happen fairly quickly, # but we'll stick a one-second timeout on here just in case # someone gets hung. for worker in self.workers: worker.join(1.0) self.workers = [] class Parallel: """This class is used to execute tasks in parallel, and is somewhat less efficient than Serial, but is appropriate for parallel builds. This class is thread safe. """ def __init__(self, taskmaster, num, stack_size): """Create a new parallel job given a taskmaster. The taskmaster's next_task() method should return the next task that needs to be executed, or None if there are no more tasks. The taskmaster's executed() method will be called for each task when it is successfully executed or failed() will be called if the task failed to execute (i.e. execute() raised an exception). Note: calls to taskmaster are serialized, but calls to execute() on distinct tasks are not serialized, because that is the whole point of parallel jobs: they can execute multiple tasks simultaneously. """ self.taskmaster = taskmaster self.interrupted = InterruptState() self.tp = ThreadPool(num, stack_size, self.interrupted) self.maxjobs = num def start(self): """Start the job. This will begin pulling tasks from the taskmaster and executing them, and return when there are no more tasks. If a task fails to execute (i.e. execute() raises an exception), then the job will stop.""" jobs = 0 while True: # Start up as many available tasks as we're # allowed to. while jobs < self.maxjobs: task = self.taskmaster.next_task() if task is None: break try: # prepare task for execution task.prepare() except: task.exception_set() task.failed() task.postprocess() else: if task.needs_execute(): # dispatch task self.tp.put(task) jobs = jobs + 1 else: task.executed() task.postprocess() if not task and not jobs: break # Let any/all completed tasks finish up before we go # back and put the next batch of tasks on the queue. while True: task, ok = self.tp.get() jobs = jobs - 1 if ok: task.executed() else: if self.interrupted(): try: raise SCons.Errors.BuildError( task.targets[0], errstr=interrupt_msg) except: task.exception_set() # Let the failed() callback function arrange # for the build to stop if that's appropriate. task.failed() task.postprocess() if self.tp.resultsQueue.empty(): break self.tp.cleanup() self.taskmaster.cleanup() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Util.py0000644000175000017500000015076713606712377020673 0ustar kurtkurt"""SCons.Util Various utility functions go here. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Util.py 4369 2009/09/19 15:58:29 scons" import copy import os import os.path import re import string import sys import types from UserDict import UserDict from UserList import UserList from UserString import UserString # Don't "from types import ..." these because we need to get at the # types module later to look for UnicodeType. DictType = dict InstanceType = types.InstanceType ListType = list StringType = bytes TupleType = tuple def dictify(keys, values, result={}): for k, v in zip(keys, values): result[k] = v return result _altsep = os.altsep if _altsep is None and sys.platform == 'win32': # My ActivePython 2.0.1 doesn't set os.altsep! What gives? _altsep = '/' if _altsep: def rightmost_separator(path, sep, _altsep=_altsep): rfind = string.rfind return max(rfind(path, sep), rfind(path, _altsep)) else: rightmost_separator = string.rfind # First two from the Python Cookbook, just for completeness. # (Yeah, yeah, YAGNI...) def containsAny(str, set): """Check whether sequence str contains ANY of the items in set.""" for c in set: if c in str: return 1 return 0 def containsAll(str, set): """Check whether sequence str contains ALL of the items in set.""" for c in set: if c not in str: return 0 return 1 def containsOnly(str, set): """Check whether sequence str contains ONLY items in set.""" for c in str: if c not in set: return 0 return 1 def splitext(path): "Same as os.path.splitext() but faster." sep = rightmost_separator(path, os.sep) dot = string.rfind(path, '.') # An ext is only real if it has at least one non-digit char if dot > sep and not containsOnly(path[dot:], "0123456789."): return path[:dot],path[dot:] else: return path,"" def updrive(path): """ Make the drive letter (if any) upper case. This is useful because Windows is inconsitent on the case of the drive letter, which can cause inconsistencies when calculating command signatures. """ drive, rest = os.path.splitdrive(path) if drive: path = string.upper(drive) + rest return path class NodeList(UserList): """This class is almost exactly like a regular list of Nodes (actually it can hold any object), with one important difference. If you try to get an attribute from this list, it will return that attribute from every item in the list. For example: >>> someList = NodeList([ ' foo ', ' bar ' ]) >>> someList.strip() [ 'foo', 'bar' ] """ def __nonzero__(self): return len(self.data) != 0 def __str__(self): return string.join(map(str, self.data)) def __iter__(self): return iter(self.data) def __call__(self, *args, **kwargs): result = map(lambda x, args=args, kwargs=kwargs: x(*args, **kwargs), self.data) return self.__class__(result) def __getattr__(self, name): result = map(lambda x, n=name: getattr(x, n), self.data) return self.__class__(result) _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$') def get_environment_var(varstr): """Given a string, first determine if it looks like a reference to a single environment variable, like "$FOO" or "${FOO}". If so, return that variable with no decorations ("FOO"). If not, return None.""" mo=_get_env_var.match(to_String(varstr)) if mo: var = mo.group(1) if var[0] == '{': return var[1:-1] else: return var else: return None class DisplayEngine: def __init__(self): self.__call__ = self.print_it def print_it(self, text, append_newline=1): if append_newline: text = text + '\n' try: sys.stdout.write(text) except IOError: # Stdout might be connected to a pipe that has been closed # by now. The most likely reason for the pipe being closed # is that the user has press ctrl-c. It this is the case, # then SCons is currently shutdown. We therefore ignore # IOError's here so that SCons can continue and shutdown # properly so that the .sconsign is correctly written # before SCons exits. pass def dont_print(self, text, append_newline=1): pass def set_mode(self, mode): if mode: self.__call__ = self.print_it else: self.__call__ = self.dont_print def render_tree(root, child_func, prune=0, margin=[0], visited={}): """ Render a tree of nodes into an ASCII tree view. root - the root node of the tree child_func - the function called to get the children of a node prune - don't visit the same node twice margin - the format of the left margin to use for children of root. 1 results in a pipe, and 0 results in no pipe. visited - a dictionary of visited nodes in the current branch if not prune, or in the whole tree if prune. """ rname = str(root) children = child_func(root) retval = "" for pipe in margin[:-1]: if pipe: retval = retval + "| " else: retval = retval + " " if rname in visited: return retval + "+-[" + rname + "]\n" retval = retval + "+-" + rname + "\n" if not prune: visited = copy.copy(visited) visited[rname] = 1 for i in range(len(children)): margin.append(i 0 last = t[0] lasti = i = 1 while i < n: if t[i] != last: t[lasti] = last = t[i] lasti = lasti + 1 i = i + 1 return t[:lasti] del t # Brute force is all that's left. u = [] for x in s: if x not in u: u.append(x) return u # From Alex Martelli, # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 # ASPN: Python Cookbook: Remove duplicates from a sequence # First comment, dated 2001/10/13. # (Also in the printed Python Cookbook.) def uniquer(seq, idfun=None): if idfun is None: def idfun(x): return x seen = {} result = [] for item in seq: marker = idfun(item) # in old Python versions: # if seen.has_key(marker) # but in new ones: if marker in seen: continue seen[marker] = 1 result.append(item) return result # A more efficient implementation of Alex's uniquer(), this avoids the # idfun() argument and function-call overhead by assuming that all # items in the sequence are hashable. def uniquer_hashables(seq): seen = {} result = [] for item in seq: #if not item in seen: if item not in seen: seen[item] = 1 result.append(item) return result # Much of the logic here was originally based on recipe 4.9 from the # Python CookBook, but we had to dumb it way down for Python 1.5.2. class LogicalLines: def __init__(self, fileobj): self.fileobj = fileobj def readline(self): result = [] while True: line = self.fileobj.readline() if not line: break if line[-2:] == '\\\n': result.append(line[:-2]) else: result.append(line) break return string.join(result, '') def readlines(self): result = [] while True: line = self.readline() if not line: break result.append(line) return result class UniqueList(UserList): def __init__(self, seq = []): UserList.__init__(self, seq) self.unique = True def __make_unique(self): if not self.unique: self.data = uniquer_hashables(self.data) self.unique = True def __lt__(self, other): self.__make_unique() return UserList.__lt__(self, other) def __le__(self, other): self.__make_unique() return UserList.__le__(self, other) def __eq__(self, other): self.__make_unique() return UserList.__eq__(self, other) def __ne__(self, other): self.__make_unique() return UserList.__ne__(self, other) def __gt__(self, other): self.__make_unique() return UserList.__gt__(self, other) def __ge__(self, other): self.__make_unique() return UserList.__ge__(self, other) def __cmp__(self, other): self.__make_unique() return UserList.__cmp__(self, other) def __len__(self): self.__make_unique() return UserList.__len__(self) def __getitem__(self, i): self.__make_unique() return UserList.__getitem__(self, i) def __setitem__(self, i, item): UserList.__setitem__(self, i, item) self.unique = False def __getslice__(self, i, j): self.__make_unique() return UserList.__getslice__(self, i, j) def __setslice__(self, i, j, other): UserList.__setslice__(self, i, j, other) self.unique = False def __add__(self, other): result = UserList.__add__(self, other) result.unique = False return result def __radd__(self, other): result = UserList.__radd__(self, other) result.unique = False return result def __iadd__(self, other): result = UserList.__iadd__(self, other) result.unique = False return result def __mul__(self, other): result = UserList.__mul__(self, other) result.unique = False return result def __rmul__(self, other): result = UserList.__rmul__(self, other) result.unique = False return result def __imul__(self, other): result = UserList.__imul__(self, other) result.unique = False return result def append(self, item): UserList.append(self, item) self.unique = False def insert(self, i): UserList.insert(self, i) self.unique = False def count(self, item): self.__make_unique() return UserList.count(self, item) def index(self, item): self.__make_unique() return UserList.index(self, item) def reverse(self): self.__make_unique() UserList.reverse(self) def sort(self, *args, **kwds): self.__make_unique() #return UserList.sort(self, *args, **kwds) return UserList.sort(*(self,)+args, **kwds) def extend(self, other): UserList.extend(self, other) self.unique = False class Unbuffered: """ A proxy class that wraps a file object, flushing after every write, and delegating everything else to the wrapped object. """ def __init__(self, file): self.file = file def write(self, arg): try: self.file.write(arg) self.file.flush() except IOError: # Stdout might be connected to a pipe that has been closed # by now. The most likely reason for the pipe being closed # is that the user has press ctrl-c. It this is the case, # then SCons is currently shutdown. We therefore ignore # IOError's here so that SCons can continue and shutdown # properly so that the .sconsign is correctly written # before SCons exits. pass def __getattr__(self, attr): return getattr(self.file, attr) def make_path_relative(path): """ makes an absolute path name to a relative pathname. """ if os.path.isabs(path): drive_s,path = os.path.splitdrive(path) import re if not drive_s: path=re.compile("/*(.*)").findall(path)[0] else: path=path[1:] assert( not os.path.isabs( path ) ), path return path # The original idea for AddMethod() and RenameFunction() come from the # following post to the ActiveState Python Cookbook: # # ASPN: Python Cookbook : Install bound methods in an instance # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613 # # That code was a little fragile, though, so the following changes # have been wrung on it: # # * Switched the installmethod() "object" and "function" arguments, # so the order reflects that the left-hand side is the thing being # "assigned to" and the right-hand side is the value being assigned. # # * Changed explicit type-checking to the "try: klass = object.__class__" # block in installmethod() below so that it still works with the # old-style classes that SCons uses. # # * Replaced the by-hand creation of methods and functions with use of # the "new" module, as alluded to in Alex Martelli's response to the # following Cookbook post: # # ASPN: Python Cookbook : Dynamically added methods to a class # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 def AddMethod(object, function, name = None): """ Adds either a bound method to an instance or an unbound method to a class. If name is ommited the name of the specified function is used by default. Example: a = A() def f(self, x, y): self.z = x + y AddMethod(f, A, "add") a.add(2, 4) print a.z AddMethod(lambda self, i: self.l[i], a, "listIndex") print a.listIndex(5) """ import new if name is None: name = function.__name__ else: function = RenameFunction(function, name) try: klass = object.__class__ except AttributeError: # "object" is really a class, so it gets an unbound method. object.__dict__[name] = new.instancemethod(function, None, object) else: # "object" is really an instance, so it gets a bound method. object.__dict__[name] = new.instancemethod(function, object, klass) def RenameFunction(function, name): """ Returns a function identical to the specified function, but with the specified name. """ import new # Compatibility for Python 1.5 and 2.1. Can be removed in favor of # passing function.func_defaults directly to new.function() once # we base on Python 2.2 or later. func_defaults = function.__defaults__ if func_defaults is None: func_defaults = () return new.function(function.__code__, function.__globals__, name, func_defaults) md5 = False def MD5signature(s): return str(s) def MD5filesignature(fname, chunksize=65536): f = open(fname, "rb") result = f.read() f.close() return result try: import hashlib except ImportError: pass else: if hasattr(hashlib, 'md5'): md5 = True def MD5signature(s): m = hashlib.md5() m.update(str(s)) return m.hexdigest() def MD5filesignature(fname, chunksize=65536): m = hashlib.md5() f = open(fname, "rb") while True: blck = f.read(chunksize) if not blck: break m.update(str(blck)) f.close() return m.hexdigest() def MD5collect(signatures): """ Collects a list of signatures into an aggregate signature. signatures - a list of signatures returns - the aggregate signature """ if len(signatures) == 1: return signatures[0] else: return MD5signature(string.join(signatures, ', ')) # Wrap the intern() function so it doesn't throw exceptions if ineligible # arguments are passed. The intern() function was moved into the sys module in # Python 3. try: intern except NameError: from sys import intern def silent_intern(x): """ Perform intern() on the passed argument and return the result. If the input is ineligible (e.g. a unicode string) the original argument is returned and no exception is thrown. """ try: return sys.intern(x) except TypeError: return x # From Dinu C. Gherman, # Python Cookbook, second edition, recipe 6.17, p. 277. # Also: # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 # ASPN: Python Cookbook: Null Object Design Pattern # TODO(1.5): #class Null(object): class Null: """ Null objects always and reliably "do nothing." """ def __new__(cls, *args, **kwargs): if not '_inst' in vars(cls): #cls._inst = type.__new__(cls, *args, **kwargs) cls._inst = type.__new__(*(cls,) + args, **kwargs) return cls._inst def __init__(self, *args, **kwargs): pass def __call__(self, *args, **kwargs): return self def __repr__(self): return "Null(0x%08X)" % id(self) def __nonzero__(self): return False def __getattr__(self, name): return self def __setattr__(self, name, value): return self def __delattr__(self, name): return self class NullSeq(Null): def __len__(self): return 0 def __iter__(self): return iter(()) def __getitem__(self, i): return self def __delitem__(self, i): return self def __setitem__(self, i, v): return self del __revision__ # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/SConsign.py0000644000175000017500000003065613606712377021473 0ustar kurtkurt"""SCons.SConsign Writing and reading information to the .sconsign file or files. """ from __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/SConsign.py 4369 2009/09/19 15:58:29 scons" import cPickle import os import os.path import SCons.dblite import SCons.Warnings def corrupt_dblite_warning(filename): SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, "Ignoring corrupt .sconsign file: %s"%filename) SCons.dblite.ignore_corrupt_dbfiles = 1 SCons.dblite.corruption_warning = corrupt_dblite_warning #XXX Get rid of the global array so this becomes re-entrant. sig_files = [] # Info for the database SConsign implementation (now the default): # "DataBase" is a dictionary that maps top-level SConstruct directories # to open database handles. # "DB_Module" is the Python database module to create the handles. # "DB_Name" is the base name of the database file (minus any # extension the underlying DB module will add). DataBase = {} DB_Module = SCons.dblite DB_Name = ".sconsign" DB_sync_list = [] def Get_DataBase(dir): global DataBase, DB_Module, DB_Name top = dir.fs.Top if not os.path.isabs(DB_Name) and top.repositories: mode = "c" for d in [top] + top.repositories: if dir.is_under(d): try: return DataBase[d], mode except KeyError: path = d.entry_abspath(DB_Name) try: db = DataBase[d] = DB_Module.open(path, mode) except (IOError, OSError): pass else: if mode != "r": DB_sync_list.append(db) return db, mode mode = "r" try: return DataBase[top], "c" except KeyError: db = DataBase[top] = DB_Module.open(DB_Name, "c") DB_sync_list.append(db) return db, "c" except TypeError: print("DataBase =", DataBase) raise def Reset(): """Reset global state. Used by unit tests that end up using SConsign multiple times to get a clean slate for each test.""" global sig_files, DB_sync_list sig_files = [] DB_sync_list = [] normcase = os.path.normcase def write(): global sig_files for sig_file in sig_files: sig_file.write(sync=0) for db in DB_sync_list: try: syncmethod = db.sync except AttributeError: pass # Not all anydbm modules have sync() methods. else: syncmethod() class SConsignEntry: """ Wrapper class for the generic entry in a .sconsign file. The Node subclass populates it with attributes as it pleases. XXX As coded below, we do expect a '.binfo' attribute to be added, but we'll probably generalize this in the next refactorings. """ current_version_id = 1 def __init__(self): # Create an object attribute from the class attribute so it ends up # in the pickled data in the .sconsign file. _version_id = self.current_version_id def convert_to_sconsign(self): self.binfo.convert_to_sconsign() def convert_from_sconsign(self, dir, name): self.binfo.convert_from_sconsign(dir, name) class Base: """ This is the controlling class for the signatures for the collection of entries associated with a specific directory. The actual directory association will be maintained by a subclass that is specific to the underlying storage method. This class provides a common set of methods for fetching and storing the individual bits of information that make up signature entry. """ def __init__(self): self.entries = {} self.dirty = False self.to_be_merged = {} def get_entry(self, filename): """ Fetch the specified entry attribute. """ return self.entries[filename] def set_entry(self, filename, obj): """ Set the entry. """ self.entries[filename] = obj self.dirty = True def do_not_set_entry(self, filename, obj): pass def store_info(self, filename, node): entry = node.get_stored_info() entry.binfo.merge(node.get_binfo()) self.to_be_merged[filename] = node self.dirty = True def do_not_store_info(self, filename, node): pass def merge(self): for key, node in self.to_be_merged.items(): entry = node.get_stored_info() try: ninfo = entry.ninfo except AttributeError: # This happens with SConf Nodes, because the configuration # subsystem takes direct control over how the build decision # is made and its information stored. pass else: ninfo.merge(node.get_ninfo()) self.entries[key] = entry self.to_be_merged = {} class DB(Base): """ A Base subclass that reads and writes signature information from a global .sconsign.db* file--the actual file suffix is determined by the database module. """ def __init__(self, dir): Base.__init__(self) self.dir = dir db, mode = Get_DataBase(dir) # Read using the path relative to the top of the Repository # (self.dir.tpath) from which we're fetching the signature # information. path = normcase(dir.tpath) try: rawentries = db[path] except KeyError: pass else: try: self.entries = cPickle.loads(rawentries) if not isinstance(self.entries, type({})): self.entries = {} raise TypeError except KeyboardInterrupt: raise except Exception as e: SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, "Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.tpath, e)) for key, entry in self.entries.items(): entry.convert_from_sconsign(dir, key) if mode == "r": # This directory is actually under a repository, which means # likely they're reaching in directly for a dependency on # a file there. Don't actually set any entry info, so we # won't try to write to that .sconsign.dblite file. self.set_entry = self.do_not_set_entry self.store_info = self.do_not_store_info global sig_files sig_files.append(self) def write(self, sync=1): if not self.dirty: return self.merge() db, mode = Get_DataBase(self.dir) # Write using the path relative to the top of the SConstruct # directory (self.dir.path), not relative to the top of # the Repository; we only write to our own .sconsign file, # not to .sconsign files in Repositories. path = normcase(self.dir.path) for key, entry in self.entries.items(): entry.convert_to_sconsign() db[path] = cPickle.dumps(self.entries, 1) if sync: try: syncmethod = db.sync except AttributeError: # Not all anydbm modules have sync() methods. pass else: syncmethod() class Dir(Base): def __init__(self, fp=None, dir=None): """ fp - file pointer to read entries from """ Base.__init__(self) if not fp: return self.entries = cPickle.load(fp) if not isinstance(self.entries, type({})): self.entries = {} raise TypeError if dir: for key, entry in self.entries.items(): entry.convert_from_sconsign(dir, key) class DirFile(Dir): """ Encapsulates reading and writing a per-directory .sconsign file. """ def __init__(self, dir): """ dir - the directory for the file """ self.dir = dir self.sconsign = os.path.join(dir.path, '.sconsign') try: fp = open(self.sconsign, 'rb') except IOError: fp = None try: Dir.__init__(self, fp, dir) except KeyboardInterrupt: raise except: SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, "Ignoring corrupt .sconsign file: %s"%self.sconsign) global sig_files sig_files.append(self) def write(self, sync=1): """ Write the .sconsign file to disk. Try to write to a temporary file first, and rename it if we succeed. If we can't write to the temporary file, it's probably because the directory isn't writable (and if so, how did we build anything in this directory, anyway?), so try to write directly to the .sconsign file as a backup. If we can't rename, try to copy the temporary contents back to the .sconsign file. Either way, always try to remove the temporary file at the end. """ if not self.dirty: return self.merge() temp = os.path.join(self.dir.path, '.scons%d' % os.getpid()) try: file = open(temp, 'wb') fname = temp except IOError: try: file = open(self.sconsign, 'wb') fname = self.sconsign except IOError: return for key, entry in self.entries.items(): entry.convert_to_sconsign() cPickle.dump(self.entries, file, 1) file.close() if fname != self.sconsign: try: mode = os.stat(self.sconsign)[0] os.chmod(self.sconsign, 0o666) os.unlink(self.sconsign) except (IOError, OSError): # Try to carry on in the face of either OSError # (things like permission issues) or IOError (disk # or network issues). If there's a really dangerous # issue, it should get re-raised by the calls below. pass try: os.rename(fname, self.sconsign) except OSError: # An OSError failure to rename may indicate something # like the directory has no write permission, but # the .sconsign file itself might still be writable, # so try writing on top of it directly. An IOError # here, or in any of the following calls, would get # raised, indicating something like a potentially # serious disk or network issue. open(self.sconsign, 'wb').write(open(fname, 'rb').read()) os.chmod(self.sconsign, mode) try: os.unlink(temp) except (IOError, OSError): pass ForDirectory = DB def File(name, dbm_module=None): """ Arrange for all signatures to be stored in a global .sconsign.db* file. """ global ForDirectory, DB_Name, DB_Module if name is None: ForDirectory = DirFile DB_Module = None else: ForDirectory = DB DB_Name = name if not dbm_module is None: DB_Module = dbm_module # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Memoize.py0000644000175000017500000002525613606712377021355 0ustar kurtkurtfrom __future__ import print_function # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Memoize.py 4369 2009/09/19 15:58:29 scons" __doc__ = """Memoizer A metaclass implementation to count hits and misses of the computed values that various methods cache in memory. Use of this modules assumes that wrapped methods be coded to cache their values in a consistent way. Here is an example of wrapping a method that returns a computed value, with no input parameters: memoizer_counters = [] # Memoization memoizer_counters.append(SCons.Memoize.CountValue('foo')) # Memoization def foo(self): try: # Memoization return self._memo['foo'] # Memoization except KeyError: # Memoization pass # Memoization result = self.compute_foo_value() self._memo['foo'] = result # Memoization return result Here is an example of wrapping a method that will return different values based on one or more input arguments: def _bar_key(self, argument): # Memoization return argument # Memoization memoizer_counters.append(SCons.Memoize.CountDict('bar', _bar_key)) # Memoization def bar(self, argument): memo_key = argument # Memoization try: # Memoization memo_dict = self._memo['bar'] # Memoization except KeyError: # Memoization memo_dict = {} # Memoization self._memo['dict'] = memo_dict # Memoization else: # Memoization try: # Memoization return memo_dict[memo_key] # Memoization except KeyError: # Memoization pass # Memoization result = self.compute_bar_value(argument) memo_dict[memo_key] = result # Memoization return result At one point we avoided replicating this sort of logic in all the methods by putting it right into this module, but we've moved away from that at present (see the "Historical Note," below.). Deciding what to cache is tricky, because different configurations can have radically different performance tradeoffs, and because the tradeoffs involved are often so non-obvious. Consequently, deciding whether or not to cache a given method will likely be more of an art than a science, but should still be based on available data from this module. Here are some VERY GENERAL guidelines about deciding whether or not to cache return values from a method that's being called a lot: -- The first question to ask is, "Can we change the calling code so this method isn't called so often?" Sometimes this can be done by changing the algorithm. Sometimes the *caller* should be memoized, not the method you're looking at. -- The memoized function should be timed with multiple configurations to make sure it doesn't inadvertently slow down some other configuration. -- When memoizing values based on a dictionary key composed of input arguments, you don't need to use all of the arguments if some of them don't affect the return values. Historical Note: The initial Memoizer implementation actually handled the caching of values for the wrapped methods, based on a set of generic algorithms for computing hashable values based on the method's arguments. This collected caching logic nicely, but had two drawbacks: Running arguments through a generic key-conversion mechanism is slower (and less flexible) than just coding these things directly. Since the methods that need memoized values are generally performance-critical, slowing them down in order to collect the logic isn't the right tradeoff. Use of the memoizer really obscured what was being called, because all the memoized methods were wrapped with re-used generic methods. This made it more difficult, for example, to use the Python profiler to figure out how to optimize the underlying methods. """ import new # A flag controlling whether or not we actually use memoization. use_memoizer = None CounterList = [] class Counter: """ Base class for counting memoization hits and misses. We expect that the metaclass initialization will have filled in the .name attribute that represents the name of the function being counted. """ def __init__(self, method_name): """ """ self.method_name = method_name self.hit = 0 self.miss = 0 CounterList.append(self) def display(self): fmt = " %7d hits %7d misses %s()" print(fmt % (self.hit, self.miss, self.name)) def __cmp__(self, other): try: return cmp(self.name, other.name) except AttributeError: return 0 class CountValue(Counter): """ A counter class for simple, atomic memoized values. A CountValue object should be instantiated in a class for each of the class's methods that memoizes its return value by simply storing the return value in its _memo dictionary. We expect that the metaclass initialization will fill in the .underlying_method attribute with the method that we're wrapping. We then call the underlying_method method after counting whether its memoized value has already been set (a hit) or not (a miss). """ def __call__(self, *args, **kw): obj = args[0] if self.method_name in obj._memo: self.hit = self.hit + 1 else: self.miss = self.miss + 1 return self.underlying_method(*args, **kw) class CountDict(Counter): """ A counter class for memoized values stored in a dictionary, with keys based on the method's input arguments. A CountDict object is instantiated in a class for each of the class's methods that memoizes its return value in a dictionary, indexed by some key that can be computed from one or more of its input arguments. We expect that the metaclass initialization will fill in the .underlying_method attribute with the method that we're wrapping. We then call the underlying_method method after counting whether the computed key value is already present in the memoization dictionary (a hit) or not (a miss). """ def __init__(self, method_name, keymaker): """ """ Counter.__init__(self, method_name) self.keymaker = keymaker def __call__(self, *args, **kw): obj = args[0] try: memo_dict = obj._memo[self.method_name] except KeyError: self.miss = self.miss + 1 else: key = self.keymaker(*args, **kw) if key in memo_dict: self.hit = self.hit + 1 else: self.miss = self.miss + 1 return self.underlying_method(*args, **kw) class Memoizer: """Object which performs caching of method calls for its 'primary' instance.""" def __init__(self): pass # Find out if we support metaclasses (Python 2.2 and later). class M: def __init__(cls, name, bases, cls_dict): cls.use_metaclass = 1 def fake_method(self): pass new.instancemethod(fake_method, None, cls) try: class A: __metaclass__ = M use_metaclass = A.use_metaclass except AttributeError: use_metaclass = None reason = 'no metaclasses' except TypeError: use_metaclass = None reason = 'new.instancemethod() bug' else: del A del M if not use_metaclass: def Dump(title): pass try: class Memoized_Metaclass(type): # Just a place-holder so pre-metaclass Python versions don't # have to have special code for the Memoized classes. pass except TypeError: class Memoized_Metaclass: # A place-holder so pre-metaclass Python versions don't # have to have special code for the Memoized classes. pass def EnableMemoization(): import SCons.Warnings msg = 'memoization is not supported in this version of Python (%s)' raise SCons.Warnings.NoMetaclassSupportWarning(msg % reason) else: def Dump(title=None): if title: print(title) CounterList.sort() for counter in CounterList: counter.display() class Memoized_Metaclass(type): def __init__(cls, name, bases, cls_dict): super(Memoized_Metaclass, cls).__init__(name, bases, cls_dict) for counter in cls_dict.get('memoizer_counters', []): method_name = counter.method_name counter.name = cls.__name__ + '.' + method_name counter.underlying_method = cls_dict[method_name] replacement_method = new.instancemethod(counter, None, cls) setattr(cls, method_name, replacement_method) def EnableMemoization(): global use_memoizer use_memoizer = 1 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Builder.py0000644000175000017500000010140013606712377021320 0ustar kurtkurt"""SCons.Builder Builder object subsystem. A Builder object is a callable that encapsulates information about how to execute actions to create a target Node (file) from source Nodes (files), and how to create those dependencies for tracking. The main entry point here is the Builder() factory method. This provides a procedural interface that creates the right underlying Builder object based on the keyword arguments supplied and the types of the arguments. The goal is for this external interface to be simple enough that the vast majority of users can create new Builders as necessary to support building new types of files in their configurations, without having to dive any deeper into this subsystem. The base class here is BuilderBase. This is a concrete base class which does, in fact, represent the Builder objects that we (or users) create. There is also a proxy that looks like a Builder: CompositeBuilder This proxies for a Builder with an action that is actually a dictionary that knows how to map file suffixes to a specific action. This is so that we can invoke different actions (compilers, compile options) for different flavors of source files. Builders and their proxies have the following public interface methods used by other modules: __call__() THE public interface. Calling a Builder object (with the use of internal helper methods) sets up the target and source dependencies, appropriate mapping to a specific action, and the environment manipulation necessary for overridden construction variable. This also takes care of warning about possible mistakes in keyword arguments. add_emitter() Adds an emitter for a specific file suffix, used by some Tool modules to specify that (for example) a yacc invocation on a .y can create a .h *and* a .c file. add_action() Adds an action for a specific file suffix, heavily used by Tool modules to add their specific action(s) for turning a source file into an object file to the global static and shared object file Builders. There are the following methods for internal use within this module: _execute() The internal method that handles the heavily lifting when a Builder is called. This is used so that the __call__() methods can set up warning about possible mistakes in keyword-argument overrides, and *then* execute all of the steps necessary so that the warnings only occur once. get_name() Returns the Builder's name within a specific Environment, primarily used to try to return helpful information in error messages. adjust_suffix() get_prefix() get_suffix() get_src_suffix() set_src_suffix() Miscellaneous stuff for handling the prefix and suffix manipulation we use in turning source file names into target file names. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Builder.py 4369 2009/09/19 15:58:29 scons" import UserDict import UserList import SCons.Action from SCons.Debug import logInstanceCreation from SCons.Errors import InternalError, UserError import SCons.Executor import SCons.Memoize import SCons.Node import SCons.Node.FS import SCons.Util import SCons.Warnings class _Null: pass _null = _Null def match_splitext(path, suffixes = []): if suffixes: matchsuf = filter(lambda S,path=path: path[-len(S):] == S, suffixes) if matchsuf: suf = max(map(None, map(len, matchsuf), matchsuf))[1] return [path[:-len(suf)], path[-len(suf):]] return SCons.Util.splitext(path) class DictCmdGenerator(SCons.Util.Selector): """This is a callable class that can be used as a command generator function. It holds on to a dictionary mapping file suffixes to Actions. It uses that dictionary to return the proper action based on the file suffix of the source file.""" def __init__(self, dict=None, source_ext_match=1): SCons.Util.Selector.__init__(self, dict) self.source_ext_match = source_ext_match def src_suffixes(self): return self.keys() def add_action(self, suffix, action): """Add a suffix-action pair to the mapping. """ self[suffix] = action def __call__(self, target, source, env, for_signature): if not source: return [] if self.source_ext_match: suffixes = self.src_suffixes() ext = None for src in map(str, source): my_ext = match_splitext(src, suffixes)[1] if ext and my_ext != ext: raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s" % (repr(map(str, target)), src, ext, my_ext)) ext = my_ext else: ext = match_splitext(str(source[0]), self.src_suffixes())[1] if not ext: #return ext raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source)))) try: ret = SCons.Util.Selector.__call__(self, env, source, ext) except KeyError as e: raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e[0], e[1], e[2])) if ret is None: raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \ (repr(map(str, target)), repr(map(str, source)), ext, repr(self.keys()))) return ret class CallableSelector(SCons.Util.Selector): """A callable dictionary that will, in turn, call the value it finds if it can.""" def __call__(self, env, source): value = SCons.Util.Selector.__call__(self, env, source) if callable(value): value = value(env, source) return value class DictEmitter(SCons.Util.Selector): """A callable dictionary that maps file suffixes to emitters. When called, it finds the right emitter in its dictionary for the suffix of the first source file, and calls that emitter to get the right lists of targets and sources to return. If there's no emitter for the suffix in its dictionary, the original target and source are returned. """ def __call__(self, target, source, env): emitter = SCons.Util.Selector.__call__(self, env, source) if emitter: target, source = emitter(target, source, env) return (target, source) class ListEmitter(UserList.UserList): """A callable list of emitters that calls each in sequence, returning the result. """ def __call__(self, target, source, env): for e in self.data: target, source = e(target, source, env) return (target, source) # These are a common errors when calling a Builder; # they are similar to the 'target' and 'source' keyword args to builders, # so we issue warnings when we see them. The warnings can, of course, # be disabled. misleading_keywords = { 'targets' : 'target', 'sources' : 'source', } class OverrideWarner(UserDict.UserDict): """A class for warning about keyword arguments that we use as overrides in a Builder call. This class exists to handle the fact that a single Builder call can actually invoke multiple builders. This class only emits the warnings once, no matter how many Builders are invoked. """ def __init__(self, dict): UserDict.UserDict.__init__(self, dict) if __debug__: logInstanceCreation(self, 'Builder.OverrideWarner') self.already_warned = None def warn(self): if self.already_warned: return for k in self.keys(): if k in misleading_keywords: alt = misleading_keywords[k] msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k) SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg) self.already_warned = 1 def Builder(**kw): """A factory for builder objects.""" composite = None if 'generator' in kw: if 'action' in kw: raise UserError("You must not specify both an action and a generator.") kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'], {}) del kw['generator'] elif 'action' in kw: source_ext_match = kw.get('source_ext_match', 1) if 'source_ext_match' in kw: del kw['source_ext_match'] if SCons.Util.is_Dict(kw['action']): composite = DictCmdGenerator(kw['action'], source_ext_match) kw['action'] = SCons.Action.CommandGeneratorAction(composite, {}) kw['src_suffix'] = composite.src_suffixes() else: kw['action'] = SCons.Action.Action(kw['action']) if 'emitter' in kw: emitter = kw['emitter'] if SCons.Util.is_String(emitter): # This allows users to pass in an Environment # variable reference (like "$FOO") as an emitter. # We will look in that Environment variable for # a callable to use as the actual emitter. var = SCons.Util.get_environment_var(emitter) if not var: raise UserError("Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter) kw['emitter'] = EmitterProxy(var) elif SCons.Util.is_Dict(emitter): kw['emitter'] = DictEmitter(emitter) elif SCons.Util.is_List(emitter): kw['emitter'] = ListEmitter(emitter) result = BuilderBase(*(), **kw) if not composite is None: result = CompositeBuilder(result, composite) return result def _node_errors(builder, env, tlist, slist): """Validate that the lists of target and source nodes are legal for this builder and environment. Raise errors or issue warnings as appropriate. """ # First, figure out if there are any errors in the way the targets # were specified. for t in tlist: if t.side_effect: raise UserError("Multiple ways to build the same target were specified for: %s" % t) if t.has_explicit_builder(): if not t.env is None and not t.env is env: action = t.builder.action t_contents = action.get_contents(tlist, slist, t.env) contents = action.get_contents(tlist, slist, env) if t_contents == contents: msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env)) SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg) else: msg = "Two environments with different actions were specified for the same target: %s" % t raise UserError(msg) if builder.multi: if t.builder != builder: msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t) raise UserError(msg) # TODO(batch): list constructed each time! if t.get_executor().get_all_targets() != tlist: msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, map(str, t.get_executor().get_all_targets()), map(str, tlist)) raise UserError(msg) elif t.sources != slist: msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, map(str, t.sources), map(str, slist)) raise UserError(msg) if builder.single_source: if len(slist) > 1: raise UserError("More than one source given for single-source builder: targets=%s sources=%s" % (map(str,tlist), map(str,slist))) class EmitterProxy: """This is a callable class that can act as a Builder emitter. It holds on to a string that is a key into an Environment dictionary, and will look there at actual build time to see if it holds a callable. If so, we will call that as the actual emitter.""" def __init__(self, var): self.var = SCons.Util.to_String(var) def __call__(self, target, source, env): emitter = self.var # Recursively substitute the variable. # We can't use env.subst() because it deals only # in strings. Maybe we should change that? while SCons.Util.is_String(emitter) and emitter in env: emitter = env[emitter] if callable(emitter): target, source = emitter(target, source, env) elif SCons.Util.is_List(emitter): for e in emitter: target, source = e(target, source, env) return (target, source) def __cmp__(self, other): return cmp(self.var, other.var) class BuilderBase: """Base class for Builders, objects that create output nodes (files) from input nodes (files). """ if SCons.Memoize.use_memoizer: __metaclass__ = SCons.Memoize.Memoized_Metaclass memoizer_counters = [] def __init__(self, action = None, prefix = '', suffix = '', src_suffix = '', target_factory = None, source_factory = None, target_scanner = None, source_scanner = None, emitter = None, multi = 0, env = None, single_source = 0, name = None, chdir = _null, is_explicit = 1, src_builder = None, ensure_suffix = False, **overrides): if __debug__: logInstanceCreation(self, 'Builder.BuilderBase') self._memo = {} self.action = action self.multi = multi if SCons.Util.is_Dict(prefix): prefix = CallableSelector(prefix) self.prefix = prefix if SCons.Util.is_Dict(suffix): suffix = CallableSelector(suffix) self.env = env self.single_source = single_source if 'overrides' in overrides: SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, "The \"overrides\" keyword to Builder() creation has been deprecated;\n" +\ "\tspecify the items as keyword arguments to the Builder() call instead.") overrides.update(overrides['overrides']) del overrides['overrides'] if 'scanner' in overrides: SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, "The \"scanner\" keyword to Builder() creation has been deprecated;\n" "\tuse: source_scanner or target_scanner as appropriate.") del overrides['scanner'] self.overrides = overrides self.set_suffix(suffix) self.set_src_suffix(src_suffix) self.ensure_suffix = ensure_suffix self.target_factory = target_factory self.source_factory = source_factory self.target_scanner = target_scanner self.source_scanner = source_scanner self.emitter = emitter # Optional Builder name should only be used for Builders # that don't get attached to construction environments. if name: self.name = name self.executor_kw = {} if not chdir is _null: self.executor_kw['chdir'] = chdir self.is_explicit = is_explicit if src_builder is None: src_builder = [] elif not SCons.Util.is_List(src_builder): src_builder = [ src_builder ] self.src_builder = src_builder def __nonzero__(self): raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead") def get_name(self, env): """Attempts to get the name of the Builder. Look at the BUILDERS variable of env, expecting it to be a dictionary containing this Builder, and return the key of the dictionary. If there's no key, then return a directly-configured name (if there is one) or the name of the class (by default).""" try: index = env['BUILDERS'].values().index(self) return env['BUILDERS'].keys()[index] except (AttributeError, KeyError, TypeError, ValueError): try: return self.name except AttributeError: return str(self.__class__) def __cmp__(self, other): return cmp(self.__dict__, other.__dict__) def splitext(self, path, env=None): if not env: env = self.env if env: suffixes = self.src_suffixes(env) else: suffixes = [] return match_splitext(path, suffixes) def _adjustixes(self, files, pre, suf, ensure_suffix=False): if not files: return [] result = [] if not SCons.Util.is_List(files): files = [files] for f in files: if SCons.Util.is_String(f): f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix) result.append(f) return result def _create_nodes(self, env, target = None, source = None): """Create and return lists of target and source nodes. """ src_suf = self.get_src_suffix(env) target_factory = env.get_factory(self.target_factory) source_factory = env.get_factory(self.source_factory) source = self._adjustixes(source, None, src_suf) slist = env.arg2nodes(source, source_factory) pre = self.get_prefix(env, slist) suf = self.get_suffix(env, slist) if target is None: try: t_from_s = slist[0].target_from_source except AttributeError: raise UserError("Do not know how to create a target from source `%s'" % slist[0]) except IndexError: tlist = [] else: splitext = lambda S,self=self,env=env: self.splitext(S,env) tlist = [ t_from_s(pre, suf, splitext) ] else: target = self._adjustixes(target, pre, suf, self.ensure_suffix) tlist = env.arg2nodes(target, target_factory, target=target, source=source) if self.emitter: # The emitter is going to do str(node), but because we're # being called *from* a builder invocation, the new targets # don't yet have a builder set on them and will look like # source files. Fool the emitter's str() calls by setting # up a temporary builder on the new targets. new_targets = [] for t in tlist: if not t.is_derived(): t.builder_set(self) new_targets.append(t) orig_tlist = tlist[:] orig_slist = slist[:] target, source = self.emitter(target=tlist, source=slist, env=env) # Now delete the temporary builders that we attached to any # new targets, so that _node_errors() doesn't do weird stuff # to them because it thinks they already have builders. for t in new_targets: if t.builder is self: # Only delete the temporary builder if the emitter # didn't change it on us. t.builder_set(None) # Have to call arg2nodes yet again, since it is legal for # emitters to spit out strings as well as Node instances. tlist = env.arg2nodes(target, target_factory, target=orig_tlist, source=orig_slist) slist = env.arg2nodes(source, source_factory, target=orig_tlist, source=orig_slist) return tlist, slist def _execute(self, env, target, source, overwarn={}, executor_kw={}): # We now assume that target and source are lists or None. if self.src_builder: source = self.src_builder_sources(env, source, overwarn) if self.single_source and len(source) > 1 and target is None: result = [] if target is None: target = [None]*len(source) for tgt, src in zip(target, source): if not tgt is None: tgt = [tgt] if not src is None: src = [src] result.extend(self._execute(env, tgt, src, overwarn)) return SCons.Node.NodeList(result) overwarn.warn() tlist, slist = self._create_nodes(env, target, source) # Check for errors with the specified target/source lists. _node_errors(self, env, tlist, slist) # The targets are fine, so find or make the appropriate Executor to # build this particular list of targets from this particular list of # sources. executor = None key = None if self.multi: try: executor = tlist[0].get_executor(create = 0) except (AttributeError, IndexError): pass else: executor.add_sources(slist) if executor is None: if not self.action: fmt = "Builder %s must have an action to build %s." raise UserError(fmt % (self.get_name(env or self.env), map(str,tlist))) key = self.action.batch_key(env or self.env, tlist, slist) if key: try: executor = SCons.Executor.GetBatchExecutor(key) except KeyError: pass else: executor.add_batch(tlist, slist) if executor is None: executor = SCons.Executor.Executor(self.action, env, [], tlist, slist, executor_kw) if key: SCons.Executor.AddBatchExecutor(key, executor) # Now set up the relevant information in the target Nodes themselves. for t in tlist: t.cwd = env.fs.getcwd() t.builder_set(self) t.env_set(env) t.add_source(slist) t.set_executor(executor) t.set_explicit(self.is_explicit) return SCons.Node.NodeList(tlist) def __call__(self, env, target=None, source=None, chdir=_null, **kw): # We now assume that target and source are lists or None. # The caller (typically Environment.BuilderWrapper) is # responsible for converting any scalar values to lists. if chdir is _null: ekw = self.executor_kw else: ekw = self.executor_kw.copy() ekw['chdir'] = chdir if kw: if 'srcdir' in kw: def prependDirIfRelative(f, srcdir=kw['srcdir']): import os.path if SCons.Util.is_String(f) and not os.path.isabs(f): f = os.path.join(srcdir, f) return f if not SCons.Util.is_List(source): source = [source] source = map(prependDirIfRelative, source) del kw['srcdir'] if self.overrides: env_kw = self.overrides.copy() env_kw.update(kw) else: env_kw = kw else: env_kw = self.overrides env = env.Override(env_kw) return self._execute(env, target, source, OverrideWarner(kw), ekw) def adjust_suffix(self, suff): if suff and not suff[0] in [ '.', '_', '$' ]: return '.' + suff return suff def get_prefix(self, env, sources=[]): prefix = self.prefix if callable(prefix): prefix = prefix(env, sources) return env.subst(prefix) def set_suffix(self, suffix): if not callable(suffix): suffix = self.adjust_suffix(suffix) self.suffix = suffix def get_suffix(self, env, sources=[]): suffix = self.suffix if callable(suffix): suffix = suffix(env, sources) return env.subst(suffix) def set_src_suffix(self, src_suffix): if not src_suffix: src_suffix = [] elif not SCons.Util.is_List(src_suffix): src_suffix = [ src_suffix ] adjust = lambda suf, s=self: \ callable(suf) and suf or s.adjust_suffix(suf) self.src_suffix = map(adjust, src_suffix) def get_src_suffix(self, env): """Get the first src_suffix in the list of src_suffixes.""" ret = self.src_suffixes(env) if not ret: return '' return ret[0] def add_emitter(self, suffix, emitter): """Add a suffix-emitter mapping to this Builder. This assumes that emitter has been initialized with an appropriate dictionary type, and will throw a TypeError if not, so the caller is responsible for knowing that this is an appropriate method to call for the Builder in question. """ self.emitter[suffix] = emitter def add_src_builder(self, builder): """ Add a new Builder to the list of src_builders. This requires wiping out cached values so that the computed lists of source suffixes get re-calculated. """ self._memo = {} self.src_builder.append(builder) def _get_sdict(self, env): """ Returns a dictionary mapping all of the source suffixes of all src_builders of this Builder to the underlying Builder that should be called first. This dictionary is used for each target specified, so we save a lot of extra computation by memoizing it for each construction environment. Note that this is re-computed each time, not cached, because there might be changes to one of our source Builders (or one of their source Builders, and so on, and so on...) that we can't "see." The underlying methods we call cache their computed values, though, so we hope repeatedly aggregating them into a dictionary like this won't be too big a hit. We may need to look for a better way to do this if performance data show this has turned into a significant bottleneck. """ sdict = {} for bld in self.get_src_builders(env): for suf in bld.src_suffixes(env): sdict[suf] = bld return sdict def src_builder_sources(self, env, source, overwarn={}): sdict = self._get_sdict(env) src_suffixes = self.src_suffixes(env) lengths = list(set(map(len, src_suffixes))) def match_src_suffix(name, src_suffixes=src_suffixes, lengths=lengths): node_suffixes = map(lambda l, n=name: n[-l:], lengths) for suf in src_suffixes: if suf in node_suffixes: return suf return None result = [] for s in SCons.Util.flatten(source): if SCons.Util.is_String(s): match_suffix = match_src_suffix(env.subst(s)) if not match_suffix and not '.' in s: src_suf = self.get_src_suffix(env) s = self._adjustixes(s, None, src_suf)[0] else: match_suffix = match_src_suffix(s.name) if match_suffix: try: bld = sdict[match_suffix] except KeyError: result.append(s) else: tlist = bld._execute(env, None, [s], overwarn) # If the subsidiary Builder returned more than one # target, then filter out any sources that this # Builder isn't capable of building. if len(tlist) > 1: mss = lambda t, m=match_src_suffix: m(t.name) tlist = filter(mss, tlist) result.extend(tlist) else: result.append(s) source_factory = env.get_factory(self.source_factory) return env.arg2nodes(result, source_factory) def _get_src_builders_key(self, env): return id(env) memoizer_counters.append(SCons.Memoize.CountDict('get_src_builders', _get_src_builders_key)) def get_src_builders(self, env): """ Returns the list of source Builders for this Builder. This exists mainly to look up Builders referenced as strings in the 'BUILDER' variable of the construction environment and cache the result. """ memo_key = id(env) try: memo_dict = self._memo['get_src_builders'] except KeyError: memo_dict = {} self._memo['get_src_builders'] = memo_dict else: try: return memo_dict[memo_key] except KeyError: pass builders = [] for bld in self.src_builder: if SCons.Util.is_String(bld): try: bld = env['BUILDERS'][bld] except KeyError: continue builders.append(bld) memo_dict[memo_key] = builders return builders def _subst_src_suffixes_key(self, env): return id(env) memoizer_counters.append(SCons.Memoize.CountDict('subst_src_suffixes', _subst_src_suffixes_key)) def subst_src_suffixes(self, env): """ The suffix list may contain construction variable expansions, so we have to evaluate the individual strings. To avoid doing this over and over, we memoize the results for each construction environment. """ memo_key = id(env) try: memo_dict = self._memo['subst_src_suffixes'] except KeyError: memo_dict = {} self._memo['subst_src_suffixes'] = memo_dict else: try: return memo_dict[memo_key] except KeyError: pass suffixes = map(lambda x, s=self, e=env: e.subst(x), self.src_suffix) memo_dict[memo_key] = suffixes return suffixes def src_suffixes(self, env): """ Returns the list of source suffixes for all src_builders of this Builder. This is essentially a recursive descent of the src_builder "tree." (This value isn't cached because there may be changes in a src_builder many levels deep that we can't see.) """ sdict = {} suffixes = self.subst_src_suffixes(env) for s in suffixes: sdict[s] = 1 for builder in self.get_src_builders(env): for s in builder.src_suffixes(env): if s not in sdict: sdict[s] = 1 suffixes.append(s) return suffixes class CompositeBuilder(SCons.Util.Proxy): """A Builder Proxy whose main purpose is to always have a DictCmdGenerator as its action, and to provide access to the DictCmdGenerator's add_action() method. """ def __init__(self, builder, cmdgen): if __debug__: logInstanceCreation(self, 'Builder.CompositeBuilder') SCons.Util.Proxy.__init__(self, builder) # cmdgen should always be an instance of DictCmdGenerator. self.cmdgen = cmdgen self.builder = builder def add_action(self, suffix, action): self.cmdgen.add_action(suffix, action) self.set_src_suffix(self.cmdgen.src_suffixes()) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Variables/0000755000175000017500000000000013606712377021274 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Variables/ListVariable.py0000644000175000017500000001072413606712377024233 0ustar kurtkurt"""engine.SCons.Variables.ListVariable This file defines the option type for SCons implementing 'lists'. A 'list' option may either be 'all', 'none' or a list of names separated by comma. After the option has been processed, the option value holds either the named list elements, all list elemens or no list elements at all. Usage example: list_of_libs = Split('x11 gl qt ical') opts = Variables() opts.Add(ListVariable('shared', 'libraries to build as shared libraries', 'all', elems = list_of_libs)) ... for lib in list_of_libs: if lib in env['shared']: env.SharedObject(...) else: env.Object(...) """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Variables/ListVariable.py 4369 2009/09/19 15:58:29 scons" # Know Bug: This should behave like a Set-Type, but does not really, # since elements can occur twice. __all__ = ['ListVariable',] import string import UserList import SCons.Util class _ListVariable(UserList.UserList): def __init__(self, initlist=[], allowedElems=[]): UserList.UserList.__init__(self, filter(None, initlist)) self.allowedElems = allowedElems[:] self.allowedElems.sort() def __cmp__(self, other): raise NotImplementedError def __eq__(self, other): raise NotImplementedError def __ge__(self, other): raise NotImplementedError def __gt__(self, other): raise NotImplementedError def __le__(self, other): raise NotImplementedError def __lt__(self, other): raise NotImplementedError def __str__(self): if len(self) == 0: return 'none' self.data.sort() if self.data == self.allowedElems: return 'all' else: return string.join(self, ',') def prepare_to_store(self): return self.__str__() def _converter(val, allowedElems, mapdict): """ """ if val == 'none': val = [] elif val == 'all': val = allowedElems else: val = filter(None, string.split(val, ',')) val = map(lambda v, m=mapdict: m.get(v, v), val) notAllowed = filter(lambda v, aE=allowedElems: not v in aE, val) if notAllowed: raise ValueError("Invalid value(s) for option: %s" % string.join(notAllowed, ',')) return _ListVariable(val, allowedElems) ## def _validator(key, val, env): ## """ ## """ ## # todo: write validater for pgk list ## return 1 def ListVariable(key, help, default, names, map={}): """ The input parameters describe a 'package list' option, thus they are returned with the correct converter and validater appended. The result is usable for input to opts.Add() . A 'package list' option may either be 'all', 'none' or a list of package names (separated by space). """ names_str = 'allowed names: %s' % string.join(names, ' ') if SCons.Util.is_List(default): default = string.join(default, ',') help = string.join( (help, '(all|none|comma-separated list of names)', names_str), '\n ') return (key, help, default, None, #_validator, lambda val, elems=names, m=map: _converter(val, elems, m)) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Variables/__init__.py0000644000175000017500000002567213606712377023421 0ustar kurtkurt"""engine.SCons.Variables This file defines the Variables class that is used to add user-friendly customizable variables to an SCons build. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Variables/__init__.py 4369 2009/09/19 15:58:29 scons" import os.path import string import sys import SCons.Environment import SCons.Errors import SCons.Util import SCons.Warnings from BoolVariable import BoolVariable # okay from EnumVariable import EnumVariable # okay from ListVariable import ListVariable # naja from PackageVariable import PackageVariable # naja from PathVariable import PathVariable # okay class Variables: instance=None """ Holds all the options, updates the environment with the variables, and renders the help text. """ def __init__(self, files=[], args={}, is_global=1): """ files - [optional] List of option configuration files to load (backward compatibility) If a single string is passed it is automatically placed in a file list """ self.options = [] self.args = args if not SCons.Util.is_List(files): if files: files = [ files ] else: files = [] self.files = files self.unknown = {} # create the singleton instance if is_global: self=Variables.instance if not Variables.instance: Variables.instance=self def _do_add(self, key, help="", default=None, validator=None, converter=None): class Variable: pass option = Variable() # if we get a list or a tuple, we take the first element as the # option key and store the remaining in aliases. if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): option.key = key[0] option.aliases = key[1:] else: option.key = key option.aliases = [ key ] option.help = help option.default = default option.validator = validator option.converter = converter self.options.append(option) # options might be added after the 'unknown' dict has been set up, # so we remove the key and all its aliases from that dict for alias in list(option.aliases) + [ option.key ]: # TODO(1.5) #if alias in self.unknown: if alias in self.unknown.keys(): del self.unknown[alias] def keys(self): """ Returns the keywords for the options """ return map(lambda o: o.key, self.options) def Add(self, key, help="", default=None, validator=None, converter=None, **kw): """ Add an option. key - the name of the variable, or a list or tuple of arguments help - optional help text for the options default - optional default value validator - optional function that is called to validate the option's value Called with (key, value, environment) converter - optional function that is called to convert the option's value before putting it in the environment. """ if SCons.Util.is_List(key) or isinstance(key, type(())): self._do_add(*key) return if not SCons.Util.is_String(key) or \ not SCons.Environment.is_valid_construction_var(key): raise SCons.Errors.UserError("Illegal Variables.Add() key `%s'" % str(key)) self._do_add(key, help, default, validator, converter) def AddVariables(self, *optlist): """ Add a list of options. Each list element is a tuple/list of arguments to be passed on to the underlying method for adding options. Example: opt.AddVariables( ('debug', '', 0), ('CC', 'The C compiler'), ('VALIDATE', 'An option for testing validation', 'notset', validator, None), ) """ for o in optlist: self._do_add(*o) def Update(self, env, args=None): """ Update an environment with the option variables. env - the environment to update. """ values = {} # first set the defaults: for option in self.options: if not option.default is None: values[option.key] = option.default # next set the value specified in the options file for filename in self.files: if os.path.exists(filename): dir = os.path.split(os.path.abspath(filename))[0] if dir: sys.path.insert(0, dir) try: values['__name__'] = filename exec(open(filename, 'rU').read(), {}, values) finally: if dir: del sys.path[0] del values['__name__'] # set the values specified on the command line if args is None: args = self.args for arg, value in args.items(): added = False for option in self.options: if arg in list(option.aliases) + [ option.key ]: values[option.key] = value added = True if not added: self.unknown[arg] = value # put the variables in the environment: # (don't copy over variables that are not declared as options) for option in self.options: try: env[option.key] = values[option.key] except KeyError: pass # Call the convert functions: for option in self.options: if option.converter and option.key in values: value = env.subst('${%s}'%option.key) try: try: env[option.key] = option.converter(value) except TypeError: env[option.key] = option.converter(value, env) except ValueError as x: raise SCons.Errors.UserError('Error converting option: %s\n%s'%(option.key, x)) # Finally validate the values: for option in self.options: if option.validator and option.key in values: option.validator(option.key, env.subst('${%s}'%option.key), env) def UnknownVariables(self): """ Returns any options in the specified arguments lists that were not known, declared options in this object. """ return self.unknown def Save(self, filename, env): """ Saves all the options in the given file. This file can then be used to load the options next run. This can be used to create an option cache file. filename - Name of the file to save into env - the environment get the option values from """ # Create the file and write out the header try: fh = open(filename, 'w') try: # Make an assignment in the file for each option # within the environment that was assigned a value # other than the default. for option in self.options: try: value = env[option.key] try: prepare = value.prepare_to_store except AttributeError: try: eval(repr(value)) except KeyboardInterrupt: raise except: # Convert stuff that has a repr() that # cannot be evaluated into a string value = SCons.Util.to_String(value) else: value = prepare() defaultVal = env.subst(SCons.Util.to_String(option.default)) if option.converter: defaultVal = option.converter(defaultVal) if str(env.subst('${%s}' % option.key)) != str(defaultVal): fh.write('%s = %s\n' % (option.key, repr(value))) except KeyError: pass finally: fh.close() except IOError as x: raise SCons.Errors.UserError('Error writing options to file: %s\n%s' % (filename, x)) def GenerateHelpText(self, env, sort=None): """ Generate the help text for the options. env - an environment that is used to get the current values of the options. """ if sort: options = self.options[:] options.sort(lambda x,y,func=sort: func(x.key,y.key)) else: options = self.options def format(opt, self=self, env=env): if opt.key in env: actual = env.subst('${%s}' % opt.key) else: actual = None return self.FormatVariableHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases) lines = filter(None, map(format, options)) return string.join(lines, '') format = '\n%s: %s\n default: %s\n actual: %s\n' format_ = '\n%s: %s\n default: %s\n actual: %s\n aliases: %s\n' def FormatVariableHelpText(self, env, key, help, default, actual, aliases=[]): # Don't display the key name itself as an alias. aliases = filter(lambda a, k=key: a != k, aliases) if len(aliases)==0: return self.format % (key, help, default, actual) else: return self.format_ % (key, help, default, actual, aliases) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Variables/PackageVariable.py0000644000175000017500000000707613606712377024661 0ustar kurtkurt"""engine.SCons.Variables.PackageVariable This file defines the option type for SCons implementing 'package activation'. To be used whenever a 'package' may be enabled/disabled and the package path may be specified. Usage example: Examples: x11=no (disables X11 support) x11=yes (will search for the package installation dir) x11=/usr/local/X11 (will check this path for existance) To replace autoconf's --with-xxx=yyy opts = Variables() opts.Add(PackageVariable('x11', 'use X11 installed here (yes = search some places', 'yes')) ... if env['x11'] == True: dir = ... search X11 in some standard places ... env['x11'] = dir if env['x11']: ... build with x11 ... """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Variables/PackageVariable.py 4369 2009/09/19 15:58:29 scons" __all__ = ['PackageVariable',] import string import SCons.Errors __enable_strings = ('1', 'yes', 'true', 'on', 'enable', 'search') __disable_strings = ('0', 'no', 'false', 'off', 'disable') def _converter(val): """ """ lval = string.lower(val) if lval in __enable_strings: return True if lval in __disable_strings: return False #raise ValueError("Invalid value for boolean option: %s" % val) return val def _validator(key, val, env, searchfunc): # NB: searchfunc is currenty undocumented and unsupported """ """ # todo: write validator, check for path import os if env[key] is True: if searchfunc: env[key] = searchfunc(key, val) elif env[key] and not os.path.exists(val): raise SCons.Errors.UserError( 'Path does not exist for option %s: %s' % (key, val)) def PackageVariable(key, help, default, searchfunc=None): # NB: searchfunc is currenty undocumented and unsupported """ The input parameters describe a 'package list' option, thus they are returned with the correct converter and validator appended. The result is usable for input to opts.Add() . A 'package list' option may either be 'all', 'none' or a list of package names (seperated by space). """ help = string.join( (help, '( yes | no | /path/to/%s )' % key), '\n ') return (key, help, default, lambda k, v, e, f=searchfunc: _validator(k,v,e,f), _converter) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Variables/PathVariable.py0000644000175000017500000001302513606712377024211 0ustar kurtkurt"""SCons.Variables.PathVariable This file defines an option type for SCons implementing path settings. To be used whenever a a user-specified path override should be allowed. Arguments to PathVariable are: option-name = name of this option on the command line (e.g. "prefix") option-help = help string for option option-dflt = default value for this option validator = [optional] validator for option value. Predefined validators are: PathAccept -- accepts any path setting; no validation PathIsDir -- path must be an existing directory PathIsDirCreate -- path must be a dir; will create PathIsFile -- path must be a file PathExists -- path must exist (any type) [default] The validator is a function that is called and which should return True or False to indicate if the path is valid. The arguments to the validator function are: (key, val, env). The key is the name of the option, the val is the path specified for the option, and the env is the env to which the Otions have been added. Usage example: Examples: prefix=/usr/local opts = Variables() opts = Variables() opts.Add(PathVariable('qtdir', 'where the root of Qt is installed', qtdir, PathIsDir)) opts.Add(PathVariable('qt_includes', 'where the Qt includes are installed', '$qtdir/includes', PathIsDirCreate)) opts.Add(PathVariable('qt_libraries', 'where the Qt library is installed', '$qtdir/lib')) """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Variables/PathVariable.py 4369 2009/09/19 15:58:29 scons" __all__ = ['PathVariable',] import os import os.path import SCons.Errors class _PathVariableClass: def PathAccept(self, key, val, env): """Accepts any path, no checking done.""" pass def PathIsDir(self, key, val, env): """Validator to check if Path is a directory.""" if not os.path.isdir(val): if os.path.isfile(val): m = 'Directory path for option %s is a file: %s' else: m = 'Directory path for option %s does not exist: %s' raise SCons.Errors.UserError(m % (key, val)) def PathIsDirCreate(self, key, val, env): """Validator to check if Path is a directory, creating it if it does not exist.""" if os.path.isfile(val): m = 'Path for option %s is a file, not a directory: %s' raise SCons.Errors.UserError(m % (key, val)) if not os.path.isdir(val): os.makedirs(val) def PathIsFile(self, key, val, env): """validator to check if Path is a file""" if not os.path.isfile(val): if os.path.isdir(val): m = 'File path for option %s is a directory: %s' else: m = 'File path for option %s does not exist: %s' raise SCons.Errors.UserError(m % (key, val)) def PathExists(self, key, val, env): """validator to check if Path exists""" if not os.path.exists(val): m = 'Path for option %s does not exist: %s' raise SCons.Errors.UserError(m % (key, val)) def __call__(self, key, help, default, validator=None): # NB: searchfunc is currenty undocumented and unsupported """ The input parameters describe a 'path list' option, thus they are returned with the correct converter and validator appended. The result is usable for input to opts.Add() . The 'default' option specifies the default path to use if the user does not specify an override with this option. validator is a validator, see this file for examples """ if validator is None: validator = self.PathExists if SCons.Util.is_List(key) or SCons.Util.is_Tuple(key): return (key, '%s ( /path/to/%s )' % (help, key[0]), default, validator, None) else: return (key, '%s ( /path/to/%s )' % (help, key), default, validator, None) PathVariable = _PathVariableClass() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Variables/EnumVariable.py0000644000175000017500000000757213606712377024233 0ustar kurtkurt"""engine.SCons.Variables.EnumVariable This file defines the option type for SCons allowing only specified input-values. Usage example: opts = Variables() opts.Add(EnumVariable('debug', 'debug output and symbols', 'no', allowed_values=('yes', 'no', 'full'), map={}, ignorecase=2)) ... if env['debug'] == 'full': ... """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Variables/EnumVariable.py 4369 2009/09/19 15:58:29 scons" __all__ = ['EnumVariable',] import string import SCons.Errors def _validator(key, val, env, vals): if not val in vals: raise SCons.Errors.UserError( 'Invalid value for option %s: %s' % (key, val)) def EnumVariable(key, help, default, allowed_values, map={}, ignorecase=0): """ The input parameters describe a option with only certain values allowed. They are returned with an appropriate converter and validator appended. The result is usable for input to Variables.Add(). 'key' and 'default' are the values to be passed on to Variables.Add(). 'help' will be appended by the allowed values automatically 'allowed_values' is a list of strings, which are allowed as values for this option. The 'map'-dictionary may be used for converting the input value into canonical values (eg. for aliases). 'ignorecase' defines the behaviour of the validator: If ignorecase == 0, the validator/converter are case-sensitive. If ignorecase == 1, the validator/converter are case-insensitive. If ignorecase == 2, the validator/converter is case-insensitive and the converted value will always be lower-case. The 'validator' tests whether the value is in the list of allowed values. The 'converter' converts input values according to the given 'map'-dictionary (unmapped input values are returned unchanged). """ help = '%s (%s)' % (help, string.join(allowed_values, '|')) # define validator if ignorecase >= 1: validator = lambda key, val, env, vals=allowed_values: \ _validator(key, string.lower(val), env, vals) else: validator = lambda key, val, env, vals=allowed_values: \ _validator(key, val, env, vals) # define converter if ignorecase == 2: converter = lambda val, map=map: \ string.lower(map.get(string.lower(val), val)) elif ignorecase == 1: converter = lambda val, map=map: \ map.get(string.lower(val), val) else: converter = lambda val, map=map: \ map.get(val, val) return (key, help, default, validator, converter) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Variables/BoolVariable.py0000644000175000017500000000600513606712377024210 0ustar kurtkurt"""engine.SCons.Variables.BoolVariable This file defines the option type for SCons implementing true/false values. Usage example: opts = Variables() opts.Add(BoolVariable('embedded', 'build for an embedded system', 0)) ... if env['embedded'] == 1: ... """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Variables/BoolVariable.py 4369 2009/09/19 15:58:29 scons" __all__ = ['BoolVariable',] import string import SCons.Errors __true_strings = ('y', 'yes', 'true', 't', '1', 'on' , 'all' ) __false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none') def _text2bool(val): """ Converts strings to True/False depending on the 'truth' expressed by the string. If the string can't be converted, the original value will be returned. See '__true_strings' and '__false_strings' for values considered 'true' or 'false respectivly. This is usable as 'converter' for SCons' Variables. """ lval = string.lower(val) if lval in __true_strings: return True if lval in __false_strings: return False raise ValueError("Invalid value for boolean option: %s" % val) def _validator(key, val, env): """ Validates the given value to be either '0' or '1'. This is usable as 'validator' for SCons' Variables. """ if not env[key] in (True, False): raise SCons.Errors.UserError( 'Invalid value for boolean option %s: %s' % (key, env[key])) def BoolVariable(key, help, default): """ The input parameters describe a boolen option, thus they are returned with the correct converter and validator appended. The 'help' text will by appended by '(yes|no) to show the valid valued. The result is usable for input to opts.Add(). """ return (key, '%s (yes|no)' % help, default, _validator, _text2bool) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/0000755000175000017500000000000013606712377020647 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/__init__.py0000644000175000017500000002117113606712377022762 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __doc__ = """ SCons compatibility package for old Python versions This subpackage holds modules that provide backwards-compatible implementations of various things that we'd like to use in SCons but which only show up in later versions of Python than the early, old version(s) we still support. Other code will not generally reference things in this package through the SCons.compat namespace. The modules included here add things to the __builtin__ namespace or the global module list so that the rest of our code can use the objects and names imported here regardless of Python version. Simply enough, things that go in the __builtin__ name space come from our builtins module. The rest of the things here will be in individual compatibility modules that are either: 1) suitably modified copies of the future modules that we want to use; or 2) backwards compatible re-implementations of the specific portions of a future module's API that we want to use. GENERAL WARNINGS: Implementations of functions in the SCons.compat modules are *NOT* guaranteed to be fully compliant with these functions in later versions of Python. We are only concerned with adding functionality that we actually use in SCons, so be wary if you lift this code for other uses. (That said, making these more nearly the same as later, official versions is still a desirable goal, we just don't need to be obsessive about it.) We name the compatibility modules with an initial '_scons_' (for example, _scons_subprocess.py is our compatibility module for subprocess) so that we can still try to import the real module name and fall back to our compatibility module if we get an ImportError. The import_as() function defined below loads the module as the "real" name (without the '_scons'), after which all of the "import {module}" statements in the rest of our code will find our pre-loaded compatibility module. """ __revision__ = "src/engine/SCons/compat/__init__.py 4369 2009/09/19 15:58:29 scons" def import_as(module, name): """ Imports the specified module (from our local directory) as the specified name. """ import imp import os.path dir = os.path.split(__file__)[0] file, filename, suffix_mode_type = imp.find_module(module, [dir]) imp.load_module(name, file, filename, suffix_mode_type) import builtins try: import hashlib except ImportError: # Pre-2.5 Python has no hashlib module. try: import_as('_scons_hashlib', 'hashlib') except ImportError: # If we failed importing our compatibility module, it probably # means this version of Python has no md5 module. Don't do # anything and let the higher layer discover this fact, so it # can fall back to using timestamp. pass try: set except NameError: # Pre-2.4 Python has no native set type try: # Python 2.2 and 2.3 can use the copy of the 2.[45] sets module # that we grabbed. import_as('_scons_sets', 'sets') except (ImportError, SyntaxError): # Python 1.5 (ImportError, no __future_ module) and 2.1 # (SyntaxError, no generators in __future__) will blow up # trying to import the 2.[45] sets module, so back off to a # custom sets module that can be discarded easily when we # stop supporting those versions. import_as('_scons_sets15', 'sets') import __builtin__ import sets __builtin__.set = sets.Set import fnmatch try: fnmatch.filter except AttributeError: # Pre-2.2 Python has no fnmatch.filter() function. def filter(names, pat): """Return the subset of the list NAMES that match PAT""" import os,posixpath result=[] pat = os.path.normcase(pat) if pat not in fnmatch._cache: import re res = fnmatch.translate(pat) fnmatch._cache[pat] = re.compile(res) match = fnmatch._cache[pat].match if os.path is posixpath: # normcase on posix is NOP. Optimize it away from the loop. for name in names: if match(name): result.append(name) else: for name in names: if match(os.path.normcase(name)): result.append(name) return result fnmatch.filter = filter del filter try: import itertools except ImportError: # Pre-2.3 Python has no itertools module. import_as('_scons_itertools', 'itertools') # If we need the compatibility version of textwrap, it must be imported # before optparse, which uses it. try: import textwrap except ImportError: # Pre-2.3 Python has no textwrap module. import_as('_scons_textwrap', 'textwrap') try: import optparse except ImportError: # Pre-2.3 Python has no optparse module. import_as('_scons_optparse', 'optparse') import os try: os.devnull except AttributeError: # Pre-2.4 Python has no os.devnull attribute import sys _names = sys.builtin_module_names if 'posix' in _names: os.devnull = '/dev/null' elif 'nt' in _names: os.devnull = 'nul' os.path.devnull = os.devnull try: os.path.lexists except AttributeError: # Pre-2.4 Python has no os.path.lexists function def lexists(path): return os.path.exists(path) or os.path.islink(path) os.path.lexists = lexists import shlex try: shlex.split except AttributeError: # Pre-2.3 Python has no shlex.split() function. # # The full white-space splitting semantics of shlex.split() are # complicated to reproduce by hand, so just use a compatibility # version of the shlex module cribbed from Python 2.5 with some # minor modifications for older Python versions. del shlex import_as('_scons_shlex', 'shlex') import shutil try: shutil.move except AttributeError: # Pre-2.3 Python has no shutil.move() function. # # Cribbed from Python 2.5. import os def move(src, dst): """Recursively move a file or directory to another location. If the destination is on our current filesystem, then simply use rename. Otherwise, copy src to the dst and then remove src. A lot more could be done here... A look at a mv.c shows a lot of the issues this implementation glosses over. """ try: os.rename(src, dst) except OSError: if os.path.isdir(src): if shutil.destinsrc(src, dst): raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) shutil.copytree(src, dst, symlinks=True) shutil.rmtree(src) else: shutil.copy2(src,dst) os.unlink(src) shutil.move = move del move def destinsrc(src, dst): src = os.path.abspath(src) return os.path.abspath(dst)[:len(src)] == src shutil.destinsrc = destinsrc del destinsrc try: import subprocess except ImportError: # Pre-2.4 Python has no subprocess module. import_as('_scons_subprocess', 'subprocess') import sys try: sys.version_info except AttributeError: # Pre-1.6 Python has no sys.version_info import string version_string = string.split(sys.version)[0] version_ints = map(int, string.split(version_string, '.')) sys.version_info = tuple(version_ints + ['final', 0]) try: import UserString except ImportError: # Pre-1.6 Python has no UserString module. import_as('_scons_UserString', 'UserString') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_textwrap.py0000644000175000017500000003432713606712377024454 0ustar kurtkurt"""Text wrapping and filling. """ # Copyright (C) 1999-2001 Gregory P. Ward. # Copyright (C) 2002, 2003 Python Software Foundation. # Written by Greg Ward __revision__ = "$Id: textwrap.py,v 1.32.8.2 2004/05/13 01:48:15 gward Exp $" import string, re try: unicode except NameError: class unicode: pass __all__ = ['TextWrapper', 'wrap', 'fill'] # Hardcode the recognized whitespace characters to the US-ASCII # whitespace characters. The main reason for doing this is that in # ISO-8859-1, 0xa0 is non-breaking whitespace, so in certain locales # that character winds up in string.whitespace. Respecting # string.whitespace in those cases would 1) make textwrap treat 0xa0 the # same as any other whitespace char, which is clearly wrong (it's a # *non-breaking* space), 2) possibly cause problems with Unicode, # since 0xa0 is not in range(128). _whitespace = '\t\n\x0b\x0c\r ' class TextWrapper: """ Object for wrapping/filling text. The public interface consists of the wrap() and fill() methods; the other methods are just there for subclasses to override in order to tweak the default behaviour. If you want to completely replace the main wrapping algorithm, you'll probably have to override _wrap_chunks(). Several instance attributes control various aspects of wrapping: width (default: 70) the maximum width of wrapped lines (unless break_long_words is false) initial_indent (default: "") string that will be prepended to the first line of wrapped output. Counts towards the line's width. subsequent_indent (default: "") string that will be prepended to all lines save the first of wrapped output; also counts towards each line's width. expand_tabs (default: true) Expand tabs in input text to spaces before further processing. Each tab will become 1 .. 8 spaces, depending on its position in its line. If false, each tab is treated as a single character. replace_whitespace (default: true) Replace all whitespace characters in the input text by spaces after tab expansion. Note that if expand_tabs is false and replace_whitespace is true, every tab will be converted to a single space! fix_sentence_endings (default: false) Ensure that sentence-ending punctuation is always followed by two spaces. Off by default because the algorithm is (unavoidably) imperfect. break_long_words (default: true) Break words longer than 'width'. If false, those words will not be broken, and some lines might be longer than 'width'. """ whitespace_trans = string.maketrans(_whitespace, ' ' * len(_whitespace)) unicode_whitespace_trans = {} try: uspace = eval("ord(u' ')") except SyntaxError: # Python1.5 doesn't understand u'' syntax, in which case we # won't actually use the unicode translation below, so it # doesn't matter what value we put in the table. uspace = ord(' ') for x in map(ord, _whitespace): unicode_whitespace_trans[x] = uspace # This funky little regex is just the trick for splitting # text up into word-wrappable chunks. E.g. # "Hello there -- you goof-ball, use the -b option!" # splits into # Hello/ /there/ /--/ /you/ /goof-/ball,/ /use/ /the/ /-b/ /option! # (after stripping out empty strings). try: wordsep_re = re.compile(r'(\s+|' # any whitespace r'[^\s\w]*\w{2,}-(?=\w{2,})|' # hyphenated words r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash except re.error: # Pre-2.0 Python versions don't have the (?<= negative look-behind # assertion. It mostly doesn't matter for the simple input # SCons is going to give it, so just leave it out. wordsep_re = re.compile(r'(\s+|' # any whitespace r'-*\w{2,}-(?=\w{2,}))') # hyphenated words # XXX will there be a locale-or-charset-aware version of # string.lowercase in 2.3? sentence_end_re = re.compile(r'[%s]' # lowercase letter r'[\.\!\?]' # sentence-ending punct. r'[\"\']?' # optional end-of-quote % string.lowercase) def __init__(self, width=70, initial_indent="", subsequent_indent="", expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True): self.width = width self.initial_indent = initial_indent self.subsequent_indent = subsequent_indent self.expand_tabs = expand_tabs self.replace_whitespace = replace_whitespace self.fix_sentence_endings = fix_sentence_endings self.break_long_words = break_long_words # -- Private methods ----------------------------------------------- # (possibly useful for subclasses to override) def _munge_whitespace(self, text): """_munge_whitespace(text : string) -> string Munge whitespace in text: expand tabs and convert all other whitespace characters to spaces. Eg. " foo\tbar\n\nbaz" becomes " foo bar baz". """ if self.expand_tabs: text = string.expandtabs(text) if self.replace_whitespace: if isinstance(text, type('')): text = string.translate(text, self.whitespace_trans) elif isinstance(text, unicode): text = string.translate(text, self.unicode_whitespace_trans) return text def _split(self, text): """_split(text : string) -> [string] Split the text to wrap into indivisible chunks. Chunks are not quite the same as words; see wrap_chunks() for full details. As an example, the text Look, goof-ball -- use the -b option! breaks into the following chunks: 'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ', 'use', ' ', 'the', ' ', '-b', ' ', 'option!' """ chunks = self.wordsep_re.split(text) chunks = filter(None, chunks) return chunks def _fix_sentence_endings(self, chunks): """_fix_sentence_endings(chunks : [string]) Correct for sentence endings buried in 'chunks'. Eg. when the original text contains "... foo.\nBar ...", munge_whitespace() and split() will convert that to [..., "foo.", " ", "Bar", ...] which has one too few spaces; this method simply changes the one space to two. """ i = 0 pat = self.sentence_end_re while i < len(chunks)-1: if chunks[i+1] == " " and pat.search(chunks[i]): chunks[i+1] = " " i = i + 2 else: i = i + 1 def _handle_long_word(self, chunks, cur_line, cur_len, width): """_handle_long_word(chunks : [string], cur_line : [string], cur_len : int, width : int) Handle a chunk of text (most likely a word, not whitespace) that is too long to fit in any line. """ space_left = max(width - cur_len, 1) # If we're allowed to break long words, then do so: put as much # of the next chunk onto the current line as will fit. if self.break_long_words: cur_line.append(chunks[0][0:space_left]) chunks[0] = chunks[0][space_left:] # Otherwise, we have to preserve the long word intact. Only add # it to the current line if there's nothing already there -- # that minimizes how much we violate the width constraint. elif not cur_line: cur_line.append(chunks.pop(0)) # If we're not allowed to break long words, and there's already # text on the current line, do nothing. Next time through the # main loop of _wrap_chunks(), we'll wind up here again, but # cur_len will be zero, so the next line will be entirely # devoted to the long word that we can't handle right now. def _wrap_chunks(self, chunks): """_wrap_chunks(chunks : [string]) -> [string] Wrap a sequence of text chunks and return a list of lines of length 'self.width' or less. (If 'break_long_words' is false, some lines may be longer than this.) Chunks correspond roughly to words and the whitespace between them: each chunk is indivisible (modulo 'break_long_words'), but a line break can come between any two chunks. Chunks should not have internal whitespace; ie. a chunk is either all whitespace or a "word". Whitespace chunks will be removed from the beginning and end of lines, but apart from that whitespace is preserved. """ lines = [] if self.width <= 0: raise ValueError("invalid width %r (must be > 0)" % self.width) while chunks: # Start the list of chunks that will make up the current line. # cur_len is just the length of all the chunks in cur_line. cur_line = [] cur_len = 0 # Figure out which static string will prefix this line. if lines: indent = self.subsequent_indent else: indent = self.initial_indent # Maximum width for this line. width = self.width - len(indent) # First chunk on line is whitespace -- drop it, unless this # is the very beginning of the text (ie. no lines started yet). if string.strip(chunks[0]) == '' and lines: del chunks[0] while chunks: l = len(chunks[0]) # Can at least squeeze this chunk onto the current line. if cur_len + l <= width: cur_line.append(chunks.pop(0)) cur_len = cur_len + l # Nope, this line is full. else: break # The current line is full, and the next chunk is too big to # fit on *any* line (not just this one). if chunks and len(chunks[0]) > width: self._handle_long_word(chunks, cur_line, cur_len, width) # If the last chunk on this line is all whitespace, drop it. if cur_line and string.strip(cur_line[-1]) == '': del cur_line[-1] # Convert current line back to a string and store it in list # of all lines (return value). if cur_line: lines.append(indent + string.join(cur_line, '')) return lines # -- Public interface ---------------------------------------------- def wrap(self, text): """wrap(text : string) -> [string] Reformat the single paragraph in 'text' so it fits in lines of no more than 'self.width' columns, and return a list of wrapped lines. Tabs in 'text' are expanded with string.expandtabs(), and all other whitespace characters (including newline) are converted to space. """ text = self._munge_whitespace(text) indent = self.initial_indent chunks = self._split(text) if self.fix_sentence_endings: self._fix_sentence_endings(chunks) return self._wrap_chunks(chunks) def fill(self, text): """fill(text : string) -> string Reformat the single paragraph in 'text' to fit in lines of no more than 'self.width' columns, and return a new string containing the entire wrapped paragraph. """ return string.join(self.wrap(text), "\n") # -- Convenience interface --------------------------------------------- def wrap(text, width=70, **kwargs): """Wrap a single paragraph of text, returning a list of wrapped lines. Reformat the single paragraph in 'text' so it fits in lines of no more than 'width' columns, and return a list of wrapped lines. By default, tabs in 'text' are expanded with string.expandtabs(), and all other whitespace characters (including newline) are converted to space. See TextWrapper class for available keyword args to customize wrapping behaviour. """ kw = kwargs.copy() kw['width'] = width w = TextWrapper(*(), **kw) return w.wrap(text) def fill(text, width=70, **kwargs): """Fill a single paragraph of text, returning a new string. Reformat the single paragraph in 'text' to fit in lines of no more than 'width' columns, and return a new string containing the entire wrapped paragraph. As with wrap(), tabs are expanded and other whitespace characters converted to space. See TextWrapper class for available keyword args to customize wrapping behaviour. """ kw = kwargs.copy() kw['width'] = width w = TextWrapper(*(), **kw) return w.fill(text) # -- Loosely related functionality ------------------------------------- def dedent(text): """dedent(text : string) -> string Remove any whitespace than can be uniformly removed from the left of every line in `text`. This can be used e.g. to make triple-quoted strings line up with the left edge of screen/whatever, while still presenting it in the source code in indented form. For example: def test(): # end first line with \ to avoid the empty line! s = '''\ hello world ''' print repr(s) # prints ' hello\n world\n ' print repr(dedent(s)) # prints 'hello\n world\n' """ lines = text.expandtabs().split('\n') margin = None for line in lines: content = line.lstrip() if not content: continue indent = len(line) - len(content) if margin is None: margin = indent else: margin = min(margin, indent) if margin is not None and margin > 0: for i in range(len(lines)): lines[i] = lines[i][margin:] return string.join(lines, '\n') # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_optparse.py0000644000175000017500000016734613606712377024443 0ustar kurtkurt"""optparse - a powerful, extensible, and easy-to-use option parser. By Greg Ward Originally distributed as Optik; see http://optik.sourceforge.net/ . If you have problems with this module, please do not file bugs, patches, or feature requests with Python; instead, use Optik's SourceForge project page: http://sourceforge.net/projects/optik For support, use the optik-users@lists.sourceforge.net mailing list (http://lists.sourceforge.net/lists/listinfo/optik-users). """ # Python developers: please do not make changes to this file, since # it is automatically generated from the Optik source code. __version__ = "1.5.3" __all__ = ['Option', 'SUPPRESS_HELP', 'SUPPRESS_USAGE', 'Values', 'OptionContainer', 'OptionGroup', 'OptionParser', 'HelpFormatter', 'IndentedHelpFormatter', 'TitledHelpFormatter', 'OptParseError', 'OptionError', 'OptionConflictError', 'OptionValueError', 'BadOptionError'] __copyright__ = """ Copyright (c) 2001-2006 Gregory P. Ward. All rights reserved. Copyright (c) 2002-2006 Python Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ import string import sys, os import types import textwrap def _repr(self): return "<%s at 0x%x: %s>" % (self.__class__.__name__, id(self), self) try: sys.getdefaultencoding except AttributeError: def fake_getdefaultencoding(): return None sys.getdefaultencoding = fake_getdefaultencoding try: ''.encode except AttributeError: def encode_wrapper(s, encoding, replacement): return s else: def encode_wrapper(s, encoding, replacement): return s.encode(encoding, replacement) # This file was generated from: # Id: option_parser.py 527 2006-07-23 15:21:30Z greg # Id: option.py 522 2006-06-11 16:22:03Z gward # Id: help.py 527 2006-07-23 15:21:30Z greg # Id: errors.py 509 2006-04-20 00:58:24Z gward try: from gettext import gettext except ImportError: def gettext(message): return message _ = gettext class OptParseError (Exception): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg class OptionError (OptParseError): """ Raised if an Option instance is created with invalid or inconsistent arguments. """ def __init__(self, msg, option): self.msg = msg self.option_id = str(option) def __str__(self): if self.option_id: return "option %s: %s" % (self.option_id, self.msg) else: return self.msg class OptionConflictError (OptionError): """ Raised if conflicting options are added to an OptionParser. """ class OptionValueError (OptParseError): """ Raised if an invalid option value is encountered on the command line. """ class BadOptionError (OptParseError): """ Raised if an invalid option is seen on the command line. """ def __init__(self, opt_str): self.opt_str = opt_str def __str__(self): return _("no such option: %s") % self.opt_str class AmbiguousOptionError (BadOptionError): """ Raised if an ambiguous option is seen on the command line. """ def __init__(self, opt_str, possibilities): BadOptionError.__init__(self, opt_str) self.possibilities = possibilities def __str__(self): return (_("ambiguous option: %s (%s?)") % (self.opt_str, string.join(self.possibilities, ", "))) class HelpFormatter: """ Abstract base class for formatting option help. OptionParser instances should use one of the HelpFormatter subclasses for formatting help; by default IndentedHelpFormatter is used. Instance attributes: parser : OptionParser the controlling OptionParser instance indent_increment : int the number of columns to indent per nesting level max_help_position : int the maximum starting column for option help text help_position : int the calculated starting column for option help text; initially the same as the maximum width : int total number of columns for output (pass None to constructor for this value to be taken from the $COLUMNS environment variable) level : int current indentation level current_indent : int current indentation level (in columns) help_width : int number of columns available for option help text (calculated) default_tag : str text to replace with each option's default value, "%default" by default. Set to false value to disable default value expansion. option_strings : { Option : str } maps Option instances to the snippet of help text explaining the syntax of that option, e.g. "-h, --help" or "-fFILE, --file=FILE" _short_opt_fmt : str format string controlling how short options with values are printed in help text. Must be either "%s%s" ("-fFILE") or "%s %s" ("-f FILE"), because those are the two syntaxes that Optik supports. _long_opt_fmt : str similar but for long options; must be either "%s %s" ("--file FILE") or "%s=%s" ("--file=FILE"). """ NO_DEFAULT_VALUE = "none" def __init__(self, indent_increment, max_help_position, width, short_first): self.parser = None self.indent_increment = indent_increment self.help_position = self.max_help_position = max_help_position if width is None: try: width = int(os.environ['COLUMNS']) except (KeyError, ValueError): width = 80 width = width - 2 self.width = width self.current_indent = 0 self.level = 0 self.help_width = None # computed later self.short_first = short_first self.default_tag = "%default" self.option_strings = {} self._short_opt_fmt = "%s %s" self._long_opt_fmt = "%s=%s" def set_parser(self, parser): self.parser = parser def set_short_opt_delimiter(self, delim): if delim not in ("", " "): raise ValueError( "invalid metavar delimiter for short options: %r" % delim) self._short_opt_fmt = "%s" + delim + "%s" def set_long_opt_delimiter(self, delim): if delim not in ("=", " "): raise ValueError( "invalid metavar delimiter for long options: %r" % delim) self._long_opt_fmt = "%s" + delim + "%s" def indent(self): self.current_indent = self.current_indent + self.indent_increment self.level = self.level + 1 def dedent(self): self.current_indent = self.current_indent - self.indent_increment assert self.current_indent >= 0, "Indent decreased below 0." self.level = self.level - 1 def format_usage(self, usage): raise NotImplementedError("subclasses must implement") def format_heading(self, heading): raise NotImplementedError("subclasses must implement") def _format_text(self, text): """ Format a paragraph of free-form text for inclusion in the help output at the current indentation level. """ text_width = self.width - self.current_indent indent = " "*self.current_indent return textwrap.fill(text, text_width, initial_indent=indent, subsequent_indent=indent) def format_description(self, description): if description: return self._format_text(description) + "\n" else: return "" def format_epilog(self, epilog): if epilog: return "\n" + self._format_text(epilog) + "\n" else: return "" def expand_default(self, option): if self.parser is None or not self.default_tag: return option.help default_value = self.parser.defaults.get(option.dest) if default_value is NO_DEFAULT or default_value is None: default_value = self.NO_DEFAULT_VALUE return string.replace(option.help, self.default_tag, str(default_value)) def format_option(self, option): # The help for each option consists of two parts: # * the opt strings and metavars # eg. ("-x", or "-fFILENAME, --file=FILENAME") # * the user-supplied help string # eg. ("turn on expert mode", "read data from FILENAME") # # If possible, we write both of these on the same line: # -x turn on expert mode # # But if the opt string list is too long, we put the help # string on a second line, indented to the same column it would # start in if it fit on the first line. # -fFILENAME, --file=FILENAME # read data from FILENAME result = [] opts = self.option_strings[option] opt_width = self.help_position - self.current_indent - 2 if len(opts) > opt_width: opts = "%*s%s\n" % (self.current_indent, "", opts) indent_first = self.help_position else: # start help on same line as opts opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) indent_first = 0 result.append(opts) if option.help: help_text = self.expand_default(option) help_lines = textwrap.wrap(help_text, self.help_width) result.append("%*s%s\n" % (indent_first, "", help_lines[0])) for line in help_lines[1:]: result.append("%*s%s\n" % (self.help_position, "", line)) elif opts[-1] != "\n": result.append("\n") return string.join(result, "") def store_option_strings(self, parser): self.indent() max_len = 0 for opt in parser.option_list: strings = self.format_option_strings(opt) self.option_strings[opt] = strings max_len = max(max_len, len(strings) + self.current_indent) self.indent() for group in parser.option_groups: for opt in group.option_list: strings = self.format_option_strings(opt) self.option_strings[opt] = strings max_len = max(max_len, len(strings) + self.current_indent) self.dedent() self.dedent() self.help_position = min(max_len + 2, self.max_help_position) self.help_width = self.width - self.help_position def format_option_strings(self, option): """Return a comma-separated list of option strings & metavariables.""" if option.takes_value(): metavar = option.metavar or string.upper(option.dest) short_opts = [] for sopt in option._short_opts: short_opts.append(self._short_opt_fmt % (sopt, metavar)) long_opts = [] for lopt in option._long_opts: long_opts.append(self._long_opt_fmt % (lopt, metavar)) else: short_opts = option._short_opts long_opts = option._long_opts if self.short_first: opts = short_opts + long_opts else: opts = long_opts + short_opts return string.join(opts, ", ") class IndentedHelpFormatter (HelpFormatter): """Format help with indented section bodies. """ def __init__(self, indent_increment=2, max_help_position=24, width=None, short_first=1): HelpFormatter.__init__( self, indent_increment, max_help_position, width, short_first) def format_usage(self, usage): return _("Usage: %s\n") % usage def format_heading(self, heading): return "%*s%s:\n" % (self.current_indent, "", heading) class TitledHelpFormatter (HelpFormatter): """Format help with underlined section headers. """ def __init__(self, indent_increment=0, max_help_position=24, width=None, short_first=0): HelpFormatter.__init__ ( self, indent_increment, max_help_position, width, short_first) def format_usage(self, usage): return "%s %s\n" % (self.format_heading(_("Usage")), usage) def format_heading(self, heading): return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading)) def _parse_num(val, type): if string.lower(val[:2]) == "0x": # hexadecimal radix = 16 elif string.lower(val[:2]) == "0b": # binary radix = 2 val = val[2:] or "0" # have to remove "0b" prefix elif val[:1] == "0": # octal radix = 8 else: # decimal radix = 10 return type(val, radix) def _parse_int(val): return _parse_num(val, int) def _parse_long(val): return _parse_num(val, long) try: int('0', 10) except TypeError: # Python 1.5.2 doesn't allow a radix value to be passed to int(). _parse_int = int try: long('0', 10) except TypeError: # Python 1.5.2 doesn't allow a radix value to be passed to long(). _parse_long = long _builtin_cvt = { "int" : (_parse_int, _("integer")), "long" : (_parse_long, _("long integer")), "float" : (float, _("floating-point")), "complex" : (complex, _("complex")) } def check_builtin(option, opt, value): (cvt, what) = _builtin_cvt[option.type] try: return cvt(value) except ValueError: raise OptionValueError( _("option %s: invalid %s value: %r") % (opt, what, value)) def check_choice(option, opt, value): if value in option.choices: return value else: choices = string.join(map(repr, option.choices), ", ") raise OptionValueError( _("option %s: invalid choice: %r (choose from %s)") % (opt, value, choices)) # Not supplying a default is different from a default of None, # so we need an explicit "not supplied" value. NO_DEFAULT = ("NO", "DEFAULT") class Option: """ Instance attributes: _short_opts : [string] _long_opts : [string] action : string type : string dest : string default : any nargs : int const : any choices : [string] callback : function callback_args : (any*) callback_kwargs : { string : any } help : string metavar : string """ # The list of instance attributes that may be set through # keyword args to the constructor. ATTRS = ['action', 'type', 'dest', 'default', 'nargs', 'const', 'choices', 'callback', 'callback_args', 'callback_kwargs', 'help', 'metavar'] # The set of actions allowed by option parsers. Explicitly listed # here so the constructor can validate its arguments. ACTIONS = ("store", "store_const", "store_true", "store_false", "append", "append_const", "count", "callback", "help", "version") # The set of actions that involve storing a value somewhere; # also listed just for constructor argument validation. (If # the action is one of these, there must be a destination.) STORE_ACTIONS = ("store", "store_const", "store_true", "store_false", "append", "append_const", "count") # The set of actions for which it makes sense to supply a value # type, ie. which may consume an argument from the command line. TYPED_ACTIONS = ("store", "append", "callback") # The set of actions which *require* a value type, ie. that # always consume an argument from the command line. ALWAYS_TYPED_ACTIONS = ("store", "append") # The set of actions which take a 'const' attribute. CONST_ACTIONS = ("store_const", "append_const") # The set of known types for option parsers. Again, listed here for # constructor argument validation. TYPES = ("string", "int", "long", "float", "complex", "choice") # Dictionary of argument checking functions, which convert and # validate option arguments according to the option type. # # Signature of checking functions is: # check(option : Option, opt : string, value : string) -> any # where # option is the Option instance calling the checker # opt is the actual option seen on the command-line # (eg. "-a", "--file") # value is the option argument seen on the command-line # # The return value should be in the appropriate Python type # for option.type -- eg. an integer if option.type == "int". # # If no checker is defined for a type, arguments will be # unchecked and remain strings. TYPE_CHECKER = { "int" : check_builtin, "long" : check_builtin, "float" : check_builtin, "complex": check_builtin, "choice" : check_choice, } # CHECK_METHODS is a list of unbound method objects; they are called # by the constructor, in order, after all attributes are # initialized. The list is created and filled in later, after all # the methods are actually defined. (I just put it here because I # like to define and document all class attributes in the same # place.) Subclasses that add another _check_*() method should # define their own CHECK_METHODS list that adds their check method # to those from this class. CHECK_METHODS = None # -- Constructor/initialization methods ---------------------------- def __init__(self, *opts, **attrs): # Set _short_opts, _long_opts attrs from 'opts' tuple. # Have to be set now, in case no option strings are supplied. self._short_opts = [] self._long_opts = [] opts = self._check_opt_strings(opts) self._set_opt_strings(opts) # Set all other attrs (action, type, etc.) from 'attrs' dict self._set_attrs(attrs) # Check all the attributes we just set. There are lots of # complicated interdependencies, but luckily they can be farmed # out to the _check_*() methods listed in CHECK_METHODS -- which # could be handy for subclasses! The one thing these all share # is that they raise OptionError if they discover a problem. for checker in self.CHECK_METHODS: checker(self) def _check_opt_strings(self, opts): # Filter out None because early versions of Optik had exactly # one short option and one long option, either of which # could be None. opts = filter(None, opts) if not opts: raise TypeError("at least one option string must be supplied") return opts def _set_opt_strings(self, opts): for opt in opts: if len(opt) < 2: raise OptionError( "invalid option string %r: " "must be at least two characters long" % opt, self) elif len(opt) == 2: if not (opt[0] == "-" and opt[1] != "-"): raise OptionError( "invalid short option string %r: " "must be of the form -x, (x any non-dash char)" % opt, self) self._short_opts.append(opt) else: if not (opt[0:2] == "--" and opt[2] != "-"): raise OptionError( "invalid long option string %r: " "must start with --, followed by non-dash" % opt, self) self._long_opts.append(opt) def _set_attrs(self, attrs): for attr in self.ATTRS: if attr in attrs: setattr(self, attr, attrs[attr]) del attrs[attr] else: if attr == 'default': setattr(self, attr, NO_DEFAULT) else: setattr(self, attr, None) if attrs: attrs = sorted(attrs.keys()) raise OptionError( "invalid keyword arguments: %s" % string.join(attrs, ", "), self) # -- Constructor validation methods -------------------------------- def _check_action(self): if self.action is None: self.action = "store" elif self.action not in self.ACTIONS: raise OptionError("invalid action: %r" % self.action, self) def _check_type(self): if self.type is None: if self.action in self.ALWAYS_TYPED_ACTIONS: if self.choices is not None: # The "choices" attribute implies "choice" type. self.type = "choice" else: # No type given? "string" is the most sensible default. self.type = "string" else: # Allow type objects or builtin type conversion functions # (int, str, etc.) as an alternative to their names. (The # complicated check of __builtin__ is only necessary for # Python 2.1 and earlier, and is short-circuited by the # first check on modern Pythons.) import __builtin__ if ( isinstance(self.type, type) or (hasattr(self.type, "__name__") and getattr(__builtin__, self.type.__name__, None) is self.type) ): self.type = self.type.__name__ if self.type == "str": self.type = "string" if self.type not in self.TYPES: raise OptionError("invalid option type: %r" % self.type, self) if self.action not in self.TYPED_ACTIONS: raise OptionError( "must not supply a type for action %r" % self.action, self) def _check_choice(self): if self.type == "choice": if self.choices is None: raise OptionError( "must supply a list of choices for type 'choice'", self) elif type(self.choices) not in (tuple, list): raise OptionError( "choices must be a list of strings ('%s' supplied)" % string.split(str(type(self.choices)), "'")[1], self) elif self.choices is not None: raise OptionError( "must not supply choices for type %r" % self.type, self) def _check_dest(self): # No destination given, and we need one for this action. The # self.type check is for callbacks that take a value. takes_value = (self.action in self.STORE_ACTIONS or self.type is not None) if self.dest is None and takes_value: # Glean a destination from the first long option string, # or from the first short option string if no long options. if self._long_opts: # eg. "--foo-bar" -> "foo_bar" self.dest = string.replace(self._long_opts[0][2:], '-', '_') else: self.dest = self._short_opts[0][1] def _check_const(self): if self.action not in self.CONST_ACTIONS and self.const is not None: raise OptionError( "'const' must not be supplied for action %r" % self.action, self) def _check_nargs(self): if self.action in self.TYPED_ACTIONS: if self.nargs is None: self.nargs = 1 elif self.nargs is not None: raise OptionError( "'nargs' must not be supplied for action %r" % self.action, self) def _check_callback(self): if self.action == "callback": if not callable(self.callback): raise OptionError( "callback not callable: %r" % self.callback, self) if (self.callback_args is not None and not isinstance(self.callback_args, tuple)): raise OptionError( "callback_args, if supplied, must be a tuple: not %r" % self.callback_args, self) if (self.callback_kwargs is not None and not isinstance(self.callback_kwargs, dict)): raise OptionError( "callback_kwargs, if supplied, must be a dict: not %r" % self.callback_kwargs, self) else: if self.callback is not None: raise OptionError( "callback supplied (%r) for non-callback option" % self.callback, self) if self.callback_args is not None: raise OptionError( "callback_args supplied for non-callback option", self) if self.callback_kwargs is not None: raise OptionError( "callback_kwargs supplied for non-callback option", self) CHECK_METHODS = [_check_action, _check_type, _check_choice, _check_dest, _check_const, _check_nargs, _check_callback] # -- Miscellaneous methods ----------------------------------------- def __str__(self): return string.join(self._short_opts + self._long_opts, "/") __repr__ = _repr def takes_value(self): return self.type is not None def get_opt_string(self): if self._long_opts: return self._long_opts[0] else: return self._short_opts[0] # -- Processing methods -------------------------------------------- def check_value(self, opt, value): checker = self.TYPE_CHECKER.get(self.type) if checker is None: return value else: return checker(self, opt, value) def convert_value(self, opt, value): if value is not None: if self.nargs == 1: return self.check_value(opt, value) else: return tuple(map(lambda v, o=opt, s=self: s.check_value(o, v), value)) def process(self, opt, value, values, parser): # First, convert the value(s) to the right type. Howl if any # value(s) are bogus. value = self.convert_value(opt, value) # And then take whatever action is expected of us. # This is a separate method to make life easier for # subclasses to add new actions. return self.take_action( self.action, self.dest, opt, value, values, parser) def take_action(self, action, dest, opt, value, values, parser): if action == "store": setattr(values, dest, value) elif action == "store_const": setattr(values, dest, self.const) elif action == "store_true": setattr(values, dest, True) elif action == "store_false": setattr(values, dest, False) elif action == "append": values.ensure_value(dest, []).append(value) elif action == "append_const": values.ensure_value(dest, []).append(self.const) elif action == "count": setattr(values, dest, values.ensure_value(dest, 0) + 1) elif action == "callback": args = self.callback_args or () kwargs = self.callback_kwargs or {} self.callback(*(self, opt, value, parser,) + args, **kwargs) elif action == "help": parser.print_help() parser.exit() elif action == "version": parser.print_version() parser.exit() else: raise RuntimeError("unknown action %r" % self.action) return 1 # class Option SUPPRESS_HELP = "SUPPRESS"+"HELP" SUPPRESS_USAGE = "SUPPRESS"+"USAGE" try: str except AttributeError: def isbasestring(x): return isinstance(x, bytes) else: def isbasestring(x): return isinstance(x, (bytes, str)) class Values: def __init__(self, defaults=None): if defaults: for (attr, val) in defaults.items(): setattr(self, attr, val) def __str__(self): return str(self.__dict__) __repr__ = _repr def __cmp__(self, other): if isinstance(other, Values): return cmp(self.__dict__, other.__dict__) elif isinstance(other, dict): return cmp(self.__dict__, other) else: return -1 def _update_careful(self, dict): """ Update the option values from an arbitrary dictionary, but only use keys from dict that already have a corresponding attribute in self. Any keys in dict without a corresponding attribute are silently ignored. """ for attr in dir(self): if attr in dict: dval = dict[attr] if dval is not None: setattr(self, attr, dval) def _update_loose(self, dict): """ Update the option values from an arbitrary dictionary, using all keys from the dictionary regardless of whether they have a corresponding attribute in self or not. """ self.__dict__.update(dict) def _update(self, dict, mode): if mode == "careful": self._update_careful(dict) elif mode == "loose": self._update_loose(dict) else: raise ValueError("invalid update mode: %r" % mode) def read_module(self, modname, mode="careful"): __import__(modname) mod = sys.modules[modname] self._update(vars(mod), mode) def read_file(self, filename, mode="careful"): vars = {} exec(open(filename, 'rU').read(), vars) self._update(vars, mode) def ensure_value(self, attr, value): if not hasattr(self, attr) or getattr(self, attr) is None: setattr(self, attr, value) return getattr(self, attr) class OptionContainer: """ Abstract base class. Class attributes: standard_option_list : [Option] list of standard options that will be accepted by all instances of this parser class (intended to be overridden by subclasses). Instance attributes: option_list : [Option] the list of Option objects contained by this OptionContainer _short_opt : { string : Option } dictionary mapping short option strings, eg. "-f" or "-X", to the Option instances that implement them. If an Option has multiple short option strings, it will appears in this dictionary multiple times. [1] _long_opt : { string : Option } dictionary mapping long option strings, eg. "--file" or "--exclude", to the Option instances that implement them. Again, a given Option can occur multiple times in this dictionary. [1] defaults : { string : any } dictionary mapping option destination names to default values for each destination [1] [1] These mappings are common to (shared by) all components of the controlling OptionParser, where they are initially created. """ def __init__(self, option_class, conflict_handler, description): # Initialize the option list and related data structures. # This method must be provided by subclasses, and it must # initialize at least the following instance attributes: # option_list, _short_opt, _long_opt, defaults. self._create_option_list() self.option_class = option_class self.set_conflict_handler(conflict_handler) self.set_description(description) def _create_option_mappings(self): # For use by OptionParser constructor -- create the master # option mappings used by this OptionParser and all # OptionGroups that it owns. self._short_opt = {} # single letter -> Option instance self._long_opt = {} # long option -> Option instance self.defaults = {} # maps option dest -> default value def _share_option_mappings(self, parser): # For use by OptionGroup constructor -- use shared option # mappings from the OptionParser that owns this OptionGroup. self._short_opt = parser._short_opt self._long_opt = parser._long_opt self.defaults = parser.defaults def set_conflict_handler(self, handler): if handler not in ("error", "resolve"): raise ValueError("invalid conflict_resolution value %r" % handler) self.conflict_handler = handler def set_description(self, description): self.description = description def get_description(self): return self.description def destroy(self): """see OptionParser.destroy().""" del self._short_opt del self._long_opt del self.defaults # -- Option-adding methods ----------------------------------------- def _check_conflict(self, option): conflict_opts = [] for opt in option._short_opts: if opt in self._short_opt: conflict_opts.append((opt, self._short_opt[opt])) for opt in option._long_opts: if opt in self._long_opt: conflict_opts.append((opt, self._long_opt[opt])) if conflict_opts: handler = self.conflict_handler if handler == "error": raise OptionConflictError( "conflicting option string(s): %s" % string.join(map(lambda co: co[0], conflict_opts), ", "), option) elif handler == "resolve": for (opt, c_option) in conflict_opts: if opt[:2] == "--": c_option._long_opts.remove(opt) del self._long_opt[opt] else: c_option._short_opts.remove(opt) del self._short_opt[opt] if not (c_option._short_opts or c_option._long_opts): c_option.container.option_list.remove(c_option) def add_option(self, *args, **kwargs): """add_option(Option) add_option(opt_str, ..., kwarg=val, ...) """ if isinstance(args[0], bytes): option = self.option_class(*args, **kwargs) elif len(args) == 1 and not kwargs: option = args[0] if not isinstance(option, Option): raise TypeError("not an Option instance: %r" % option) else: raise TypeError("invalid arguments") self._check_conflict(option) self.option_list.append(option) option.container = self for opt in option._short_opts: self._short_opt[opt] = option for opt in option._long_opts: self._long_opt[opt] = option if option.dest is not None: # option has a dest, we need a default if option.default is not NO_DEFAULT: self.defaults[option.dest] = option.default elif option.dest not in self.defaults: self.defaults[option.dest] = None return option def add_options(self, option_list): for option in option_list: self.add_option(option) # -- Option query/removal methods ---------------------------------- def get_option(self, opt_str): return (self._short_opt.get(opt_str) or self._long_opt.get(opt_str)) def has_option(self, opt_str): return (opt_str in self._short_opt or opt_str in self._long_opt) def remove_option(self, opt_str): option = self._short_opt.get(opt_str) if option is None: option = self._long_opt.get(opt_str) if option is None: raise ValueError("no such option %r" % opt_str) for opt in option._short_opts: del self._short_opt[opt] for opt in option._long_opts: del self._long_opt[opt] option.container.option_list.remove(option) # -- Help-formatting methods --------------------------------------- def format_option_help(self, formatter): if not self.option_list: return "" result = [] for option in self.option_list: if not option.help is SUPPRESS_HELP: result.append(formatter.format_option(option)) return string.join(result, "") def format_description(self, formatter): return formatter.format_description(self.get_description()) def format_help(self, formatter): result = [] if self.description: result.append(self.format_description(formatter)) if self.option_list: result.append(self.format_option_help(formatter)) return string.join(result, "\n") class OptionGroup (OptionContainer): def __init__(self, parser, title, description=None): self.parser = parser OptionContainer.__init__( self, parser.option_class, parser.conflict_handler, description) self.title = title def _create_option_list(self): self.option_list = [] self._share_option_mappings(self.parser) def set_title(self, title): self.title = title def destroy(self): """see OptionParser.destroy().""" OptionContainer.destroy(self) del self.option_list # -- Help-formatting methods --------------------------------------- def format_help(self, formatter): result = formatter.format_heading(self.title) formatter.indent() result = result + OptionContainer.format_help(self, formatter) formatter.dedent() return result class OptionParser (OptionContainer): """ Class attributes: standard_option_list : [Option] list of standard options that will be accepted by all instances of this parser class (intended to be overridden by subclasses). Instance attributes: usage : string a usage string for your program. Before it is displayed to the user, "%prog" will be expanded to the name of your program (self.prog or os.path.basename(sys.argv[0])). prog : string the name of the current program (to override os.path.basename(sys.argv[0])). epilog : string paragraph of help text to print after option help option_groups : [OptionGroup] list of option groups in this parser (option groups are irrelevant for parsing the command-line, but very useful for generating help) allow_interspersed_args : bool = true if true, positional arguments may be interspersed with options. Assuming -a and -b each take a single argument, the command-line -ablah foo bar -bboo baz will be interpreted the same as -ablah -bboo -- foo bar baz If this flag were false, that command line would be interpreted as -ablah -- foo bar -bboo baz -- ie. we stop processing options as soon as we see the first non-option argument. (This is the tradition followed by Python's getopt module, Perl's Getopt::Std, and other argument- parsing libraries, but it is generally annoying to users.) process_default_values : bool = true if true, option default values are processed similarly to option values from the command line: that is, they are passed to the type-checking function for the option's type (as long as the default value is a string). (This really only matters if you have defined custom types; see SF bug #955889.) Set it to false to restore the behaviour of Optik 1.4.1 and earlier. rargs : [string] the argument list currently being parsed. Only set when parse_args() is active, and continually trimmed down as we consume arguments. Mainly there for the benefit of callback options. largs : [string] the list of leftover arguments that we have skipped while parsing options. If allow_interspersed_args is false, this list is always empty. values : Values the set of option values currently being accumulated. Only set when parse_args() is active. Also mainly for callbacks. Because of the 'rargs', 'largs', and 'values' attributes, OptionParser is not thread-safe. If, for some perverse reason, you need to parse command-line arguments simultaneously in different threads, use different OptionParser instances. """ standard_option_list = [] def __init__(self, usage=None, option_list=None, option_class=Option, version=None, conflict_handler="error", description=None, formatter=None, add_help_option=True, prog=None, epilog=None): OptionContainer.__init__( self, option_class, conflict_handler, description) self.set_usage(usage) self.prog = prog self.version = version self.allow_interspersed_args = True self.process_default_values = True if formatter is None: formatter = IndentedHelpFormatter() self.formatter = formatter self.formatter.set_parser(self) self.epilog = epilog # Populate the option list; initial sources are the # standard_option_list class attribute, the 'option_list' # argument, and (if applicable) the _add_version_option() and # _add_help_option() methods. self._populate_option_list(option_list, add_help=add_help_option) self._init_parsing_state() def destroy(self): """ Declare that you are done with this OptionParser. This cleans up reference cycles so the OptionParser (and all objects referenced by it) can be garbage-collected promptly. After calling destroy(), the OptionParser is unusable. """ OptionContainer.destroy(self) for group in self.option_groups: group.destroy() del self.option_list del self.option_groups del self.formatter # -- Private methods ----------------------------------------------- # (used by our or OptionContainer's constructor) def _create_option_list(self): self.option_list = [] self.option_groups = [] self._create_option_mappings() def _add_help_option(self): self.add_option("-h", "--help", action="help", help=_("show this help message and exit")) def _add_version_option(self): self.add_option("--version", action="version", help=_("show program's version number and exit")) def _populate_option_list(self, option_list, add_help=True): if self.standard_option_list: self.add_options(self.standard_option_list) if option_list: self.add_options(option_list) if self.version: self._add_version_option() if add_help: self._add_help_option() def _init_parsing_state(self): # These are set in parse_args() for the convenience of callbacks. self.rargs = None self.largs = None self.values = None # -- Simple modifier methods --------------------------------------- def set_usage(self, usage): if usage is None: self.usage = _("%prog [options]") elif usage is SUPPRESS_USAGE: self.usage = None # For backwards compatibility with Optik 1.3 and earlier. elif string.lower(usage)[:7] == "usage: ": self.usage = usage[7:] else: self.usage = usage def enable_interspersed_args(self): self.allow_interspersed_args = True def disable_interspersed_args(self): self.allow_interspersed_args = False def set_process_default_values(self, process): self.process_default_values = process def set_default(self, dest, value): self.defaults[dest] = value def set_defaults(self, **kwargs): self.defaults.update(kwargs) def _get_all_options(self): options = self.option_list[:] for group in self.option_groups: options.extend(group.option_list) return options def get_default_values(self): if not self.process_default_values: # Old, pre-Optik 1.5 behaviour. return Values(self.defaults) defaults = self.defaults.copy() for option in self._get_all_options(): default = defaults.get(option.dest) if isbasestring(default): opt_str = option.get_opt_string() defaults[option.dest] = option.check_value(opt_str, default) return Values(defaults) # -- OptionGroup methods ------------------------------------------- def add_option_group(self, *args, **kwargs): # XXX lots of overlap with OptionContainer.add_option() if isinstance(args[0], bytes): group = OptionGroup(*(self,) + args, **kwargs) elif len(args) == 1 and not kwargs: group = args[0] if not isinstance(group, OptionGroup): raise TypeError("not an OptionGroup instance: %r" % group) if group.parser is not self: raise ValueError("invalid OptionGroup (wrong parser)") else: raise TypeError("invalid arguments") self.option_groups.append(group) return group def get_option_group(self, opt_str): option = (self._short_opt.get(opt_str) or self._long_opt.get(opt_str)) if option and option.container is not self: return option.container return None # -- Option-parsing methods ---------------------------------------- def _get_args(self, args): if args is None: return sys.argv[1:] else: return args[:] # don't modify caller's list def parse_args(self, args=None, values=None): """ parse_args(args : [string] = sys.argv[1:], values : Values = None) -> (values : Values, args : [string]) Parse the command-line options found in 'args' (default: sys.argv[1:]). Any errors result in a call to 'error()', which by default prints the usage message to stderr and calls sys.exit() with an error message. On success returns a pair (values, args) where 'values' is an Values instance (with all your option values) and 'args' is the list of arguments left over after parsing options. """ rargs = self._get_args(args) if values is None: values = self.get_default_values() # Store the halves of the argument list as attributes for the # convenience of callbacks: # rargs # the rest of the command-line (the "r" stands for # "remaining" or "right-hand") # largs # the leftover arguments -- ie. what's left after removing # options and their arguments (the "l" stands for "leftover" # or "left-hand") self.rargs = rargs self.largs = largs = [] self.values = values try: stop = self._process_args(largs, rargs, values) except (BadOptionError, OptionValueError) as err: self.error(str(err)) args = largs + rargs return self.check_values(values, args) def check_values(self, values, args): """ check_values(values : Values, args : [string]) -> (values : Values, args : [string]) Check that the supplied option values and leftover arguments are valid. Returns the option values and leftover arguments (possibly adjusted, possibly completely new -- whatever you like). Default implementation just returns the passed-in values; subclasses may override as desired. """ return (values, args) def _process_args(self, largs, rargs, values): """_process_args(largs : [string], rargs : [string], values : Values) Process command-line arguments and populate 'values', consuming options and arguments from 'rargs'. If 'allow_interspersed_args' is false, stop at the first non-option argument. If true, accumulate any interspersed non-option arguments in 'largs'. """ while rargs: arg = rargs[0] # We handle bare "--" explicitly, and bare "-" is handled by the # standard arg handler since the short arg case ensures that the # len of the opt string is greater than 1. if arg == "--": del rargs[0] return elif arg[0:2] == "--": # process a single long option (possibly with value(s)) self._process_long_opt(rargs, values) elif arg[:1] == "-" and len(arg) > 1: # process a cluster of short options (possibly with # value(s) for the last one only) self._process_short_opts(rargs, values) elif self.allow_interspersed_args: largs.append(arg) del rargs[0] else: return # stop now, leave this arg in rargs # Say this is the original argument list: # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] # ^ # (we are about to process arg(i)). # # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of # [arg0, ..., arg(i-1)] (any options and their arguments will have # been removed from largs). # # The while loop will usually consume 1 or more arguments per pass. # If it consumes 1 (eg. arg is an option that takes no arguments), # then after _process_arg() is done the situation is: # # largs = subset of [arg0, ..., arg(i)] # rargs = [arg(i+1), ..., arg(N-1)] # # If allow_interspersed_args is false, largs will always be # *empty* -- still a subset of [arg0, ..., arg(i-1)], but # not a very interesting subset! def _match_long_opt(self, opt): """_match_long_opt(opt : string) -> string Determine which long option string 'opt' matches, ie. which one it is an unambiguous abbrevation for. Raises BadOptionError if 'opt' doesn't unambiguously match any long option string. """ return _match_abbrev(opt, self._long_opt) def _process_long_opt(self, rargs, values): arg = rargs.pop(0) # Value explicitly attached to arg? Pretend it's the next # argument. if "=" in arg: (opt, next_arg) = string.split(arg, "=", 1) rargs.insert(0, next_arg) had_explicit_value = True else: opt = arg had_explicit_value = False opt = self._match_long_opt(opt) option = self._long_opt[opt] if option.takes_value(): nargs = option.nargs if len(rargs) < nargs: if nargs == 1: self.error(_("%s option requires an argument") % opt) else: self.error(_("%s option requires %d arguments") % (opt, nargs)) elif nargs == 1: value = rargs.pop(0) else: value = tuple(rargs[0:nargs]) del rargs[0:nargs] elif had_explicit_value: self.error(_("%s option does not take a value") % opt) else: value = None option.process(opt, value, values, self) def _process_short_opts(self, rargs, values): arg = rargs.pop(0) stop = False i = 1 for ch in arg[1:]: opt = "-" + ch option = self._short_opt.get(opt) i = i + 1 # we have consumed a character if not option: raise BadOptionError(opt) if option.takes_value(): # Any characters left in arg? Pretend they're the # next arg, and stop consuming characters of arg. if i < len(arg): rargs.insert(0, arg[i:]) stop = True nargs = option.nargs if len(rargs) < nargs: if nargs == 1: self.error(_("%s option requires an argument") % opt) else: self.error(_("%s option requires %d arguments") % (opt, nargs)) elif nargs == 1: value = rargs.pop(0) else: value = tuple(rargs[0:nargs]) del rargs[0:nargs] else: # option doesn't take a value value = None option.process(opt, value, values, self) if stop: break # -- Feedback methods ---------------------------------------------- def get_prog_name(self): if self.prog is None: return os.path.basename(sys.argv[0]) else: return self.prog def expand_prog_name(self, s): return string.replace(s, "%prog", self.get_prog_name()) def get_description(self): return self.expand_prog_name(self.description) def exit(self, status=0, msg=None): if msg: sys.stderr.write(msg) sys.exit(status) def error(self, msg): """error(msg : string) Print a usage message incorporating 'msg' to stderr and exit. If you override this in a subclass, it should not return -- it should either exit or raise an exception. """ self.print_usage(sys.stderr) self.exit(2, "%s: error: %s\n" % (self.get_prog_name(), msg)) def get_usage(self): if self.usage: return self.formatter.format_usage( self.expand_prog_name(self.usage)) else: return "" def print_usage(self, file=None): """print_usage(file : file = stdout) Print the usage message for the current program (self.usage) to 'file' (default stdout). Any occurence of the string "%prog" in self.usage is replaced with the name of the current program (basename of sys.argv[0]). Does nothing if self.usage is empty or not defined. """ if self.usage: file.write(self.get_usage() + '\n') def get_version(self): if self.version: return self.expand_prog_name(self.version) else: return "" def print_version(self, file=None): """print_version(file : file = stdout) Print the version message for this program (self.version) to 'file' (default stdout). As with print_usage(), any occurence of "%prog" in self.version is replaced by the current program's name. Does nothing if self.version is empty or undefined. """ if self.version: file.write(self.get_version() + '\n') def format_option_help(self, formatter=None): if formatter is None: formatter = self.formatter formatter.store_option_strings(self) result = [] result.append(formatter.format_heading(_("Options"))) formatter.indent() if self.option_list: result.append(OptionContainer.format_option_help(self, formatter)) result.append("\n") for group in self.option_groups: result.append(group.format_help(formatter)) result.append("\n") formatter.dedent() # Drop the last "\n", or the header if no options or option groups: return string.join(result[:-1], "") def format_epilog(self, formatter): return formatter.format_epilog(self.epilog) def format_help(self, formatter=None): if formatter is None: formatter = self.formatter result = [] if self.usage: result.append(self.get_usage() + "\n") if self.description: result.append(self.format_description(formatter) + "\n") result.append(self.format_option_help(formatter)) result.append(self.format_epilog(formatter)) return string.join(result, "") # used by test suite def _get_encoding(self, file): encoding = getattr(file, "encoding", None) if not encoding: encoding = sys.getdefaultencoding() return encoding def print_help(self, file=None): """print_help(file : file = stdout) Print an extended help message, listing all options and any help text provided with them, to 'file' (default stdout). """ if file is None: file = sys.stdout encoding = self._get_encoding(file) file.write(encode_wrapper(self.format_help(), encoding, "replace")) # class OptionParser def _match_abbrev(s, wordmap): """_match_abbrev(s : string, wordmap : {string : Option}) -> string Return the string key in 'wordmap' for which 's' is an unambiguous abbreviation. If 's' is found to be ambiguous or doesn't match any of 'words', raise BadOptionError. """ # Is there an exact match? if s in wordmap: return s else: # Isolate all words with s as a prefix. possibilities = filter(lambda w, s=s: w[:len(s)] == s, wordmap.keys()) # No exact match, so there had better be just one possibility. if len(possibilities) == 1: return possibilities[0] elif not possibilities: raise BadOptionError(s) else: # More than one possible completion: ambiguous prefix. possibilities.sort() raise AmbiguousOptionError(s, possibilities) # Some day, there might be many Option classes. As of Optik 1.3, the # preferred way to instantiate Options is indirectly, via make_option(), # which will become a factory function when there are many Option # classes. make_option = Option # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_sets15.py0000644000175000017500000001225713606712377023720 0ustar kurtkurt# # A Set class that works all the way back to Python 1.5. From: # # Python Cookbook: Yet another Set class for Python # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/106469 # Goncalo Rodriques # # This is a pure Pythonic implementation of a set class. The syntax # and methods implemented are, for the most part, borrowed from # PEP 218 by Greg Wilson. # # Note that this class violates the formal definition of a set() by adding # a __getitem__() method so we can iterate over a set's elements under # Python 1.5 and 2.1, which don't support __iter__() and iterator types. # import string class Set: """The set class. It can contain mutable objects.""" def __init__(self, seq = None): """The constructor. It can take any object giving an iterator as an optional argument to populate the new set.""" self.elems = [] if seq: for elem in seq: if elem not in self.elems: hash(elem) self.elems.append(elem) def __str__(self): return "set([%s])" % string.join(map(str, self.elems), ", ") def copy(self): """Shallow copy of a set object.""" return Set(self.elems) def __contains__(self, elem): return elem in self.elems def __len__(self): return len(self.elems) def __getitem__(self, index): # Added so that Python 1.5 can iterate over the elements. # The cookbook recipe's author didn't like this because there # really isn't any order in a set object, but this is necessary # to make the class work well enough for our purposes. return self.elems[index] def items(self): """Returns a list of the elements in the set.""" return self.elems def add(self, elem): """Add one element to the set.""" if elem not in self.elems: hash(elem) self.elems.append(elem) def remove(self, elem): """Remove an element from the set. Return an error if elem is not in the set.""" try: self.elems.remove(elem) except ValueError: raise LookupError("Object %s is not a member of the set." % str(elem)) def discard(self, elem): """Remove an element from the set. Do nothing if elem is not in the set.""" try: self.elems.remove(elem) except ValueError: pass def sort(self, func=cmp): self.elems.sort(func) #Define an iterator for a set. def __iter__(self): return iter(self.elems) #The basic binary operations with sets. def __or__(self, other): """Union of two sets.""" ret = self.copy() for elem in other.elems: if elem not in ret: ret.elems.append(elem) return ret def __sub__(self, other): """Difference of two sets.""" ret = self.copy() for elem in other.elems: ret.discard(elem) return ret def __and__(self, other): """Intersection of two sets.""" ret = Set() for elem in self.elems: if elem in other.elems: ret.elems.append(elem) return ret def __add__(self, other): """Symmetric difference of two sets.""" ret = Set() temp = other.copy() for elem in self.elems: if elem in temp.elems: temp.elems.remove(elem) else: ret.elems.append(elem) #Add remaining elements. for elem in temp.elems: ret.elems.append(elem) return ret def __mul__(self, other): """Cartesian product of two sets.""" ret = Set() for elemself in self.elems: x = map(lambda other, s=elemself: (s, other), other.elems) ret.elems.extend(x) return ret #Some of the binary comparisons. def __lt__(self, other): """Returns 1 if the lhs set is contained but not equal to the rhs set.""" if len(self.elems) < len(other.elems): temp = other.copy() for elem in self.elems: if elem in temp.elems: temp.remove(elem) else: return 0 return len(temp.elems) == 0 else: return 0 def __le__(self, other): """Returns 1 if the lhs set is contained in the rhs set.""" if len(self.elems) <= len(other.elems): ret = 1 for elem in self.elems: if elem not in other.elems: ret = 0 break return ret else: return 0 def __eq__(self, other): """Returns 1 if the sets are equal.""" if len(self.elems) != len(other.elems): return 0 else: return len(self - other) == 0 def __cmp__(self, other): """Returns 1 if the sets are equal.""" if self.__lt__(other): return -1 elif other.__lt__(self): return 1 else: return 0 # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_hashlib.py0000644000175000017500000000560613606712377024206 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __doc__ = """ hashlib backwards-compatibility module for older (pre-2.5) Python versions This does not not NOT (repeat, *NOT*) provide complete hashlib functionality. It only wraps the portions of MD5 functionality used by SCons, in an interface that looks like hashlib (or enough for our purposes, anyway). In fact, this module will raise an ImportError if the underlying md5 module isn't available. """ __revision__ = "src/engine/SCons/compat/_scons_hashlib.py 4369 2009/09/19 15:58:29 scons" import md5 import string class md5obj: md5_module = md5 def __init__(self, name, string=''): if not name in ('MD5', 'md5'): raise ValueError("unsupported hash type") self.name = 'md5' self.m = self.md5_module.md5() def __repr__(self): return '<%s HASH object @ %#x>' % (self.name, id(self)) def copy(self): import copy result = copy.copy(self) result.m = self.m.copy() return result def digest(self): return self.m.digest() def update(self, arg): return self.m.update(arg) if hasattr(md5.md5(), 'hexdigest'): def hexdigest(self): return self.m.hexdigest() else: # Objects created by the underlying md5 module have no native # hexdigest() method (*cough* 1.5.2 *cough*), so provide an # equivalent lifted from elsewhere. def hexdigest(self): h = string.hexdigits r = '' for c in self.digest(): i = ord(c) r = r + h[(i >> 4) & 0xF] + h[i & 0xF] return r new = md5obj def md5(string=''): return md5obj('md5', string) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_itertools.py0000644000175000017500000000752013606712377024615 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/compat/_scons_itertools.py 4369 2009/09/19 15:58:29 scons" __doc__ = """ Implementations of itertools functions for Python versions that don't have iterators. These implement the functions by creating the entire list, not returning it element-by-element as the real itertools functions do. This means that early Python versions won't get the performance benefit of using the itertools, but we can still use them so the later Python versions do get the advantages of using iterators. Because we return the entire list, we intentionally do not implement the itertools functions that "return" infinitely-long lists: the count(), cycle() and repeat() functions. Other functions below have remained unimplemented simply because they aren't being used (yet) and it wasn't obvious how to do it. Or, conversely, we only implemented those functions that *were* easy to implement (mostly because the Python documentation contained examples of equivalent code). Note that these do not have independent unit tests, so it's possible that there are bugs. """ def chain(*iterables): result = [] for x in iterables: result.extend(list(x)) return result def count(n=0): # returns infinite length, should not be supported raise NotImplementedError def cycle(iterable): # returns infinite length, should not be supported raise NotImplementedError def dropwhile(predicate, iterable): result = [] for x in iterable: if not predicate(x): result.append(x) break result.extend(iterable) return result def groupby(iterable, *args): raise NotImplementedError def ifilter(predicate, iterable): result = [] if predicate is None: predicate = bool for x in iterable: if predicate(x): result.append(x) return result def ifilterfalse(predicate, iterable): result = [] if predicate is None: predicate = bool for x in iterable: if not predicate(x): result.append(x) return result def imap(function, *iterables): return map(*(function,) + tuple(iterables)) def islice(*args, **kw): raise NotImplementedError def izip(*iterables): return zip(*iterables) def repeat(*args, **kw): # returns infinite length, should not be supported raise NotImplementedError def starmap(*args, **kw): raise NotImplementedError def takewhile(predicate, iterable): result = [] for x in iterable: if predicate(x): result.append(x) else: break return result def tee(*args, **kw): raise NotImplementedError # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_UserString.py0000644000175000017500000000701713606712377024677 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/compat/_scons_UserString.py 4369 2009/09/19 15:58:29 scons" __doc__ = """ A user-defined wrapper around string objects This class is "borrowed" from the Python 2.2 UserString and modified slightly for use with SCons. It is *NOT* guaranteed to be fully compliant with the standard UserString class from all later versions of Python. In particular, it does not necessarily contain all of the methods found in later versions. """ import types StringType = bytes if hasattr(types, 'UnicodeType'): UnicodeType = str def is_String(obj): return type(obj) in (StringType, UnicodeType) else: def is_String(obj): return isinstance(obj, StringType) class UserString: def __init__(self, seq): if is_String(seq): self.data = seq elif isinstance(seq, UserString): self.data = seq.data[:] else: self.data = str(seq) def __str__(self): return str(self.data) def __repr__(self): return repr(self.data) def __int__(self): return int(self.data) def __long__(self): return long(self.data) def __float__(self): return float(self.data) def __complex__(self): return complex(self.data) def __hash__(self): return hash(self.data) def __cmp__(self, string): if isinstance(string, UserString): return cmp(self.data, string.data) else: return cmp(self.data, string) def __contains__(self, char): return char in self.data def __len__(self): return len(self.data) def __getitem__(self, index): return self.__class__(self.data[index]) def __getslice__(self, start, end): start = max(start, 0); end = max(end, 0) return self.__class__(self.data[start:end]) def __add__(self, other): if isinstance(other, UserString): return self.__class__(self.data + other.data) elif is_String(other): return self.__class__(self.data + other) else: return self.__class__(self.data + str(other)) def __radd__(self, other): if is_String(other): return self.__class__(other + self.data) else: return self.__class__(str(other) + self.data) def __mul__(self, n): return self.__class__(self.data*n) __rmul__ = __mul__ # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_subprocess.py0000644000175000017500000012710013606712377024756 0ustar kurtkurt# subprocess - Subprocesses with accessible I/O streams # # For more information about this module, see PEP 324. # # This module should remain compatible with Python 2.2, see PEP 291. # # Copyright (c) 2003-2005 by Peter Astrand # # Licensed to PSF under a Contributor Agreement. # See http://www.python.org/2.4/license for licensing details. r"""subprocess - Subprocesses with accessible I/O streams This module allows you to spawn processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several other, older modules and functions, like: os.system os.spawn* os.popen* popen2.* commands.* Information about how the subprocess module can be used to replace these modules and functions can be found below. Using the subprocess module =========================== This module defines one class called Popen: class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): Arguments are: args should be a string, or a sequence of program arguments. The program to execute is normally the first item in the args sequence or string, but can be explicitly set by using the executable argument. On UNIX, with shell=False (default): In this case, the Popen class uses os.execvp() to execute the child program. args should normally be a sequence. A string will be treated as a sequence with the string as the only item (the program to execute). On UNIX, with shell=True: If args is a string, it specifies the command string to execute through the shell. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional shell arguments. On Windows: the Popen class uses CreateProcess() to execute the child program, which operates on strings. If args is a sequence, it will be converted to a string using the list2cmdline method. Please note that not all MS Windows applications interpret the command line the same way: The list2cmdline is designed for applications using the same rules as the MS C runtime. bufsize, if given, has the same meaning as the corresponding argument to the built-in open() function: 0 means unbuffered, 1 means line buffered, any other positive value means use a buffer of (approximately) that size. A negative bufsize means to use the system default, which usually means fully buffered. The default value for bufsize is 0 (unbuffered). stdin, stdout and stderr specify the executed programs' standard input, standard output and standard error file handles, respectively. Valid values are PIPE, an existing file descriptor (a positive integer), an existing file object, and None. PIPE indicates that a new pipe to the child should be created. With None, no redirection will occur; the child's file handles will be inherited from the parent. Additionally, stderr can be STDOUT, which indicates that the stderr data from the applications should be captured into the same file handle as for stdout. If preexec_fn is set to a callable object, this object will be called in the child process just before the child is executed. If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. if shell is true, the specified command will be executed through the shell. If cwd is not None, the current directory will be changed to cwd before the child is executed. If env is not None, it defines the environment variables for the new process. If universal_newlines is true, the file objects stdout and stderr are opened as a text files, but lines may be terminated by any of '\n', the Unix end-of-line convention, '\r', the Macintosh convention or '\r\n', the Windows convention. All of these external representations are seen as '\n' by the Python program. Note: This feature is only available if Python is built with universal newline support (the default). Also, the newlines attribute of the file objects stdout, stdin and stderr are not updated by the communicate() method. The startupinfo and creationflags, if given, will be passed to the underlying CreateProcess() function. They can specify things such as appearance of the main window and priority for the new process. (Windows only) This module also defines two shortcut functions: call(*popenargs, **kwargs): Run command with arguments. Wait for command to complete, then return the returncode attribute. The arguments are the same as for the Popen constructor. Example: retcode = call(["ls", "-l"]) check_call(*popenargs, **kwargs): Run command with arguments. Wait for command to complete. If the exit code was zero then return, otherwise raise CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute. The arguments are the same as for the Popen constructor. Example: check_call(["ls", "-l"]) Exceptions ---------- Exceptions raised in the child process, before the new program has started to execute, will be re-raised in the parent. Additionally, the exception object will have one extra attribute called 'child_traceback', which is a string containing traceback information from the childs point of view. The most common exception raised is OSError. This occurs, for example, when trying to execute a non-existent file. Applications should prepare for OSErrors. A ValueError will be raised if Popen is called with invalid arguments. check_call() will raise CalledProcessError, if the called process returns a non-zero return code. Security -------- Unlike some other popen functions, this implementation will never call /bin/sh implicitly. This means that all characters, including shell metacharacters, can safely be passed to child processes. Popen objects ============= Instances of the Popen class have the following methods: poll() Check if child process has terminated. Returns returncode attribute. wait() Wait for child process to terminate. Returns returncode attribute. communicate(input=None) Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional stdin argument should be a string to be sent to the child process, or None, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr). Note: The data read is buffered in memory, so do not use this method if the data size is large or unlimited. The following attributes are also available: stdin If the stdin argument is PIPE, this attribute is a file object that provides input to the child process. Otherwise, it is None. stdout If the stdout argument is PIPE, this attribute is a file object that provides output from the child process. Otherwise, it is None. stderr If the stderr argument is PIPE, this attribute is file object that provides error output from the child process. Otherwise, it is None. pid The process ID of the child process. returncode The child return code. A None value indicates that the process hasn't terminated yet. A negative value -N indicates that the child was terminated by signal N (UNIX only). Replacing older functions with the subprocess module ==================================================== In this section, "a ==> b" means that b can be used as a replacement for a. Note: All functions in this section fail (more or less) silently if the executed program cannot be found; this module raises an OSError exception. In the following examples, we assume that the subprocess module is imported with "from subprocess import *". Replacing /bin/sh shell backquote --------------------------------- output=`mycmd myarg` ==> output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] Replacing shell pipe line ------------------------- output=`dmesg | grep hda` ==> p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) output = p2.communicate()[0] Replacing os.system() --------------------- sts = os.system("mycmd" + " myarg") ==> p = Popen("mycmd" + " myarg", shell=True) pid, sts = os.waitpid(p.pid, 0) Note: * Calling the program through the shell is usually not required. * It's easier to look at the returncode attribute than the exitstatus. A more real-world example would look like this: try: retcode = call("mycmd" + " myarg", shell=True) if retcode < 0: print >>sys.stderr, "Child was terminated by signal", -retcode else: print >>sys.stderr, "Child returned", retcode except OSError, e: print >>sys.stderr, "Execution failed:", e Replacing os.spawn* ------------------- P_NOWAIT example: pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") ==> pid = Popen(["/bin/mycmd", "myarg"]).pid P_WAIT example: retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") ==> retcode = call(["/bin/mycmd", "myarg"]) Vector example: os.spawnvp(os.P_NOWAIT, path, args) ==> Popen([path] + args[1:]) Environment example: os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) ==> Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) Replacing os.popen* ------------------- pipe = os.popen(cmd, mode='r', bufsize) ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout pipe = os.popen(cmd, mode='w', bufsize) ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdin, child_stdout) = (p.stdin, p.stdout) (child_stdin, child_stdout, child_stderr) = os.popen3(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) (child_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr) (child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) Replacing popen2.* ------------------ Note: If the cmd argument to popen2 functions is a string, the command is executed through /bin/sh. If it is a list, the command is directly executed. (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) ==> p = Popen(["somestring"], shell=True, bufsize=bufsize stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdout, child_stdin) = (p.stdout, p.stdin) (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) ==> p = Popen(["mycmd", "myarg"], bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdout, child_stdin) = (p.stdout, p.stdin) The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen, except that: * subprocess.Popen raises an exception if the execution fails * the capturestderr argument is replaced with the stderr argument. * stdin=PIPE and stdout=PIPE must be specified. * popen2 closes all filedescriptors by default, but you have to specify close_fds=True with subprocess.Popen. """ from __future__ import print_function import sys mswindows = (sys.platform == "win32") import os import string import types import traceback # Exception classes used by this module. class CalledProcessError(Exception): """This exception is raised when a process run by check_call() returns a non-zero exit status. The exit status will be stored in the returncode attribute.""" def __init__(self, returncode, cmd): self.returncode = returncode self.cmd = cmd def __str__(self): return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) if mswindows: try: import threading except ImportError: # SCons: the threading module is only used by the communicate() # method, which we don't actually use, so don't worry if we # can't import it. pass import msvcrt if 0: # <-- change this to use pywin32 instead of the _subprocess driver import pywintypes from win32api import GetStdHandle, STD_INPUT_HANDLE, \ STD_OUTPUT_HANDLE, STD_ERROR_HANDLE from win32api import GetCurrentProcess, DuplicateHandle, \ GetModuleFileName, GetVersion from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE from win32pipe import CreatePipe from win32process import CreateProcess, STARTUPINFO, \ GetExitCodeProcess, STARTF_USESTDHANDLES, \ STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 else: # SCons: don't die on Python versions that don't have _subprocess. try: from _subprocess import * except ImportError: pass class STARTUPINFO: dwFlags = 0 hStdInput = None hStdOutput = None hStdError = None wShowWindow = 0 class pywintypes: error = IOError else: import select import errno import fcntl import pickle try: fcntl.F_GETFD except AttributeError: fcntl.F_GETFD = 1 try: fcntl.F_SETFD except AttributeError: fcntl.F_SETFD = 2 __all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError"] try: MAXFD = os.sysconf("SC_OPEN_MAX") except KeyboardInterrupt: raise # SCons: don't swallow keyboard interrupts except: MAXFD = 256 try: isinstance(1, int) except TypeError: def is_int(obj): return isinstance(obj, type(1)) def is_int_or_long(obj): return type(obj) in (type(1), type(1)) else: def is_int(obj): return isinstance(obj, int) def is_int_or_long(obj): return isinstance(obj, (int, long)) try: (str,) except AttributeError: try: (str,) = (bytes, str) except AttributeError: (str,) = (bytes,) def is_string(obj): return type(obj) in (str,) else: def is_string(obj): return isinstance(obj, (str,)) _active = [] def _cleanup(): for inst in _active[:]: if inst.poll(_deadstate=sys.maxsize) >= 0: try: _active.remove(inst) except ValueError: # This can happen if two threads create a new Popen instance. # It's harmless that it was already removed, so ignore. pass PIPE = -1 STDOUT = -2 def call(*popenargs, **kwargs): """Run command with arguments. Wait for command to complete, then return the returncode attribute. The arguments are the same as for the Popen constructor. Example: retcode = call(["ls", "-l"]) """ return apply(Popen, popenargs, kwargs).wait() def check_call(*popenargs, **kwargs): """Run command with arguments. Wait for command to complete. If the exit code was zero then return, otherwise raise CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute. The arguments are the same as for the Popen constructor. Example: check_call(["ls", "-l"]) """ retcode = call(*popenargs, **kwargs) cmd = kwargs.get("args") if cmd is None: cmd = popenargs[0] if retcode: raise CalledProcessError(retcode, cmd) return retcode def list2cmdline(seq): """ Translate a sequence of arguments into a command line string, using the same rules as the MS C runtime: 1) Arguments are delimited by white space, which is either a space or a tab. 2) A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument. 3) A double quotation mark preceded by a backslash is interpreted as a literal double quotation mark. 4) Backslashes are interpreted literally, unless they immediately precede a double quotation mark. 5) If backslashes immediately precede a double quotation mark, every pair of backslashes is interpreted as a literal backslash. If the number of backslashes is odd, the last backslash escapes the next double quotation mark as described in rule 3. """ # See # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp result = [] needquote = False for arg in seq: bs_buf = [] # Add a space to separate this argument from the others if result: result.append(' ') needquote = (" " in arg) or ("\t" in arg) if needquote: result.append('"') for c in arg: if c == '\\': # Don't know if we need to double yet. bs_buf.append(c) elif c == '"': # Double backspaces. result.append('\\' * len(bs_buf)*2) bs_buf = [] result.append('\\"') else: # Normal char if bs_buf: result.extend(bs_buf) bs_buf = [] result.append(c) # Add remaining backspaces, if any. if bs_buf: result.extend(bs_buf) if needquote: result.extend(bs_buf) result.append('"') return string.join(result, '') try: object except NameError: class object: pass class Popen(object): def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): """Create new Popen instance.""" _cleanup() self._child_created = False if not is_int_or_long(bufsize): raise TypeError("bufsize must be an integer") if mswindows: if preexec_fn is not None: raise ValueError("preexec_fn is not supported on Windows " "platforms") if close_fds: raise ValueError("close_fds is not supported on Windows " "platforms") else: # POSIX if startupinfo is not None: raise ValueError("startupinfo is only supported on Windows " "platforms") if creationflags != 0: raise ValueError("creationflags is only supported on Windows " "platforms") self.stdin = None self.stdout = None self.stderr = None self.pid = None self.returncode = None self.universal_newlines = universal_newlines # Input and output objects. The general principle is like # this: # # Parent Child # ------ ----- # p2cwrite ---stdin---> p2cread # c2pread <--stdout--- c2pwrite # errread <--stderr--- errwrite # # On POSIX, the child objects are file descriptors. On # Windows, these are Windows file handles. The parent objects # are file descriptors on both platforms. The parent objects # are None when not using PIPEs. The child objects are None # when not redirecting. (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) = self._get_handles(stdin, stdout, stderr) self._execute_child(args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) if p2cwrite: self.stdin = os.fdopen(p2cwrite, 'wb', bufsize) if c2pread: if universal_newlines: self.stdout = os.fdopen(c2pread, 'rU', bufsize) else: self.stdout = os.fdopen(c2pread, 'rb', bufsize) if errread: if universal_newlines: self.stderr = os.fdopen(errread, 'rU', bufsize) else: self.stderr = os.fdopen(errread, 'rb', bufsize) def _translate_newlines(self, data): data = data.replace("\r\n", "\n") data = data.replace("\r", "\n") return data def __del__(self): if not self._child_created: # We didn't get to successfully create a child process. return # In case the child hasn't been waited on, check if it's done. self.poll(_deadstate=sys.maxsize) if self.returncode is None and _active is not None: # Child is still running, keep us alive until we can wait on it. _active.append(self) def communicate(self, input=None): """Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr).""" # Optimization: If we are only using one pipe, or no pipe at # all, using select() or threads is unnecessary. if [self.stdin, self.stdout, self.stderr].count(None) >= 2: stdout = None stderr = None if self.stdin: if input: self.stdin.write(input) self.stdin.close() elif self.stdout: stdout = self.stdout.read() elif self.stderr: stderr = self.stderr.read() self.wait() return (stdout, stderr) return self._communicate(input) if mswindows: # # Windows methods # def _get_handles(self, stdin, stdout, stderr): """Construct and return tupel with IO objects: p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite """ if stdin is None and stdout is None and stderr is None: return (None, None, None, None, None, None) p2cread, p2cwrite = None, None c2pread, c2pwrite = None, None errread, errwrite = None, None if stdin is None: p2cread = GetStdHandle(STD_INPUT_HANDLE) elif stdin == PIPE: p2cread, p2cwrite = CreatePipe(None, 0) # Detach and turn into fd p2cwrite = p2cwrite.Detach() p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0) elif is_int(stdin): p2cread = msvcrt.get_osfhandle(stdin) else: # Assuming file-like object p2cread = msvcrt.get_osfhandle(stdin.fileno()) p2cread = self._make_inheritable(p2cread) if stdout is None: c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE) elif stdout == PIPE: c2pread, c2pwrite = CreatePipe(None, 0) # Detach and turn into fd c2pread = c2pread.Detach() c2pread = msvcrt.open_osfhandle(c2pread, 0) elif is_int(stdout): c2pwrite = msvcrt.get_osfhandle(stdout) else: # Assuming file-like object c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) c2pwrite = self._make_inheritable(c2pwrite) if stderr is None: errwrite = GetStdHandle(STD_ERROR_HANDLE) elif stderr == PIPE: errread, errwrite = CreatePipe(None, 0) # Detach and turn into fd errread = errread.Detach() errread = msvcrt.open_osfhandle(errread, 0) elif stderr == STDOUT: errwrite = c2pwrite elif is_int(stderr): errwrite = msvcrt.get_osfhandle(stderr) else: # Assuming file-like object errwrite = msvcrt.get_osfhandle(stderr.fileno()) errwrite = self._make_inheritable(errwrite) return (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) def _make_inheritable(self, handle): """Return a duplicate of handle, which is inheritable""" return DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), 0, 1, DUPLICATE_SAME_ACCESS) def _find_w9xpopen(self): """Find and return absolut path to w9xpopen.exe""" w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)), "w9xpopen.exe") if not os.path.exists(w9xpopen): # Eeek - file-not-found - possibly an embedding # situation - see if we can locate it in sys.exec_prefix w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), "w9xpopen.exe") if not os.path.exists(w9xpopen): raise RuntimeError("Cannot locate w9xpopen.exe, which is " "needed for Popen to work with your " "shell or platform.") return w9xpopen def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): """Execute program (MS Windows version)""" if not isinstance(args, (str,)): args = list2cmdline(args) # Process startup details if startupinfo is None: startupinfo = STARTUPINFO() if None not in (p2cread, c2pwrite, errwrite): startupinfo.dwFlags = startupinfo.dwFlags | STARTF_USESTDHANDLES startupinfo.hStdInput = p2cread startupinfo.hStdOutput = c2pwrite startupinfo.hStdError = errwrite if shell: startupinfo.dwFlags = startupinfo.dwFlags | STARTF_USESHOWWINDOW startupinfo.wShowWindow = SW_HIDE comspec = os.environ.get("COMSPEC", "cmd.exe") args = comspec + " /c " + args if (GetVersion() >= 0x80000000 or os.path.basename(comspec).lower() == "command.com"): # Win9x, or using command.com on NT. We need to # use the w9xpopen intermediate program. For more # information, see KB Q150956 # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp) w9xpopen = self._find_w9xpopen() args = '"%s" %s' % (w9xpopen, args) # Not passing CREATE_NEW_CONSOLE has been known to # cause random failures on win9x. Specifically a # dialog: "Your program accessed mem currently in # use at xxx" and a hopeful warning about the # stability of your system. Cost is Ctrl+C wont # kill children. creationflags = creationflags | CREATE_NEW_CONSOLE # Start the process try: hp, ht, pid, tid = CreateProcess(executable, args, # no special security None, None, # must inherit handles to pass std # handles 1, creationflags, env, cwd, startupinfo) except pywintypes.error as e: # Translate pywintypes.error to WindowsError, which is # a subclass of OSError. FIXME: We should really # translate errno using _sys_errlist (or simliar), but # how can this be done from Python? raise WindowsError(*e.args) # Retain the process handle, but close the thread handle self._child_created = True self._handle = hp self.pid = pid ht.Close() # Child is launched. Close the parent's copy of those pipe # handles that only the child should have open. You need # to make sure that no handles to the write end of the # output pipe are maintained in this process or else the # pipe will not close when the child process exits and the # ReadFile will hang. if p2cread is not None: p2cread.Close() if c2pwrite is not None: c2pwrite.Close() if errwrite is not None: errwrite.Close() def poll(self, _deadstate=None): """Check if child process has terminated. Returns returncode attribute.""" if self.returncode is None: if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0: self.returncode = GetExitCodeProcess(self._handle) return self.returncode def wait(self): """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode is None: obj = WaitForSingleObject(self._handle, INFINITE) self.returncode = GetExitCodeProcess(self._handle) return self.returncode def _readerthread(self, fh, buffer): buffer.append(fh.read()) def _communicate(self, input): stdout = None # Return stderr = None # Return if self.stdout: stdout = [] stdout_thread = threading.Thread(target=self._readerthread, args=(self.stdout, stdout)) stdout_thread.setDaemon(True) stdout_thread.start() if self.stderr: stderr = [] stderr_thread = threading.Thread(target=self._readerthread, args=(self.stderr, stderr)) stderr_thread.setDaemon(True) stderr_thread.start() if self.stdin: if input is not None: self.stdin.write(input) self.stdin.close() if self.stdout: stdout_thread.join() if self.stderr: stderr_thread.join() # All data exchanged. Translate lists into strings. if stdout is not None: stdout = stdout[0] if stderr is not None: stderr = stderr[0] # Translate newlines, if requested. We cannot let the file # object do the translation: It is based on stdio, which is # impossible to combine with select (unless forcing no # buffering). if self.universal_newlines and hasattr(file, 'newlines'): if stdout: stdout = self._translate_newlines(stdout) if stderr: stderr = self._translate_newlines(stderr) self.wait() return (stdout, stderr) else: # # POSIX methods # def _get_handles(self, stdin, stdout, stderr): """Construct and return tupel with IO objects: p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite """ p2cread, p2cwrite = None, None c2pread, c2pwrite = None, None errread, errwrite = None, None if stdin is None: pass elif stdin == PIPE: p2cread, p2cwrite = os.pipe() elif is_int(stdin): p2cread = stdin else: # Assuming file-like object p2cread = stdin.fileno() if stdout is None: pass elif stdout == PIPE: c2pread, c2pwrite = os.pipe() elif is_int(stdout): c2pwrite = stdout else: # Assuming file-like object c2pwrite = stdout.fileno() if stderr is None: pass elif stderr == PIPE: errread, errwrite = os.pipe() elif stderr == STDOUT: errwrite = c2pwrite elif is_int(stderr): errwrite = stderr else: # Assuming file-like object errwrite = stderr.fileno() return (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) def _set_cloexec_flag(self, fd): try: cloexec_flag = fcntl.FD_CLOEXEC except AttributeError: cloexec_flag = 1 old = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) def _close_fds(self, but): for i in xrange(3, MAXFD): if i == but: continue try: os.close(i) except KeyboardInterrupt: raise # SCons: don't swallow keyboard interrupts except: pass def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): """Execute program (POSIX version)""" if is_string(args): args = [args] if shell: args = ["/bin/sh", "-c"] + args if executable is None: executable = args[0] # For transferring possible exec failure from child to parent # The first char specifies the exception type: 0 means # OSError, 1 means some other error. errpipe_read, errpipe_write = os.pipe() self._set_cloexec_flag(errpipe_write) self.pid = os.fork() self._child_created = True if self.pid == 0: # Child try: # Close parent's pipe ends if p2cwrite: os.close(p2cwrite) if c2pread: os.close(c2pread) if errread: os.close(errread) os.close(errpipe_read) # Dup fds for child if p2cread: os.dup2(p2cread, 0) if c2pwrite: os.dup2(c2pwrite, 1) if errwrite: os.dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the same # fd more than once, or standard fds. try: set except NameError: # Fall-back for earlier Python versions, so epydoc # can use this module directly to execute things. if p2cread: os.close(p2cread) if c2pwrite and c2pwrite not in (p2cread,): os.close(c2pwrite) if errwrite and errwrite not in (p2cread, c2pwrite): os.close(errwrite) else: for fd in set((p2cread, c2pwrite, errwrite))-set((0,1,2)): if fd: os.close(fd) # Close all other fds, if asked for if close_fds: self._close_fds(but=errpipe_write) if cwd is not None: os.chdir(cwd) if preexec_fn: apply(preexec_fn) if env is None: os.execvp(executable, args) else: os.execvpe(executable, args, env) except KeyboardInterrupt: raise # SCons: don't swallow keyboard interrupts except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object exc_lines = traceback.format_exception(exc_type, exc_value, tb) exc_value.child_traceback = string.join(exc_lines, '') os.write(errpipe_write, pickle.dumps(exc_value)) # This exitcode won't be reported to applications, so it # really doesn't matter what we return. os._exit(255) # Parent os.close(errpipe_write) if p2cread and p2cwrite: os.close(p2cread) if c2pwrite and c2pread: os.close(c2pwrite) if errwrite and errread: os.close(errwrite) # Wait for exec to fail or succeed; possibly raising exception data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB os.close(errpipe_read) if data != "": os.waitpid(self.pid, 0) child_exception = pickle.loads(data) raise child_exception def _handle_exitstatus(self, sts): if os.WIFSIGNALED(sts): self.returncode = -os.WTERMSIG(sts) elif os.WIFEXITED(sts): self.returncode = os.WEXITSTATUS(sts) else: # Should never happen raise RuntimeError("Unknown child exit status!") def poll(self, _deadstate=None): """Check if child process has terminated. Returns returncode attribute.""" if self.returncode is None: try: pid, sts = os.waitpid(self.pid, os.WNOHANG) if pid == self.pid: self._handle_exitstatus(sts) except os.error: if _deadstate is not None: self.returncode = _deadstate return self.returncode def wait(self): """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode is None: pid, sts = os.waitpid(self.pid, 0) self._handle_exitstatus(sts) return self.returncode def _communicate(self, input): read_set = [] write_set = [] stdout = None # Return stderr = None # Return if self.stdin: # Flush stdio buffer. This might block, if the user has # been writing to .stdin in an uncontrolled fashion. self.stdin.flush() if input: write_set.append(self.stdin) else: self.stdin.close() if self.stdout: read_set.append(self.stdout) stdout = [] if self.stderr: read_set.append(self.stderr) stderr = [] input_offset = 0 while read_set or write_set: rlist, wlist, xlist = select.select(read_set, write_set, []) if self.stdin in wlist: # When select has indicated that the file is writable, # we can write up to PIPE_BUF bytes without risk # blocking. POSIX defines PIPE_BUF >= 512 bytes_written = os.write(self.stdin.fileno(), buffer(input, input_offset, 512)) input_offset = input_offset + bytes_written if input_offset >= len(input): self.stdin.close() write_set.remove(self.stdin) if self.stdout in rlist: data = os.read(self.stdout.fileno(), 1024) if data == "": self.stdout.close() read_set.remove(self.stdout) stdout.append(data) if self.stderr in rlist: data = os.read(self.stderr.fileno(), 1024) if data == "": self.stderr.close() read_set.remove(self.stderr) stderr.append(data) # All data exchanged. Translate lists into strings. if stdout is not None: stdout = string.join(stdout, '') if stderr is not None: stderr = string.join(stderr, '') # Translate newlines, if requested. We cannot let the file # object do the translation: It is based on stdio, which is # impossible to combine with select (unless forcing no # buffering). if self.universal_newlines and hasattr(file, 'newlines'): if stdout: stdout = self._translate_newlines(stdout) if stderr: stderr = self._translate_newlines(stderr) self.wait() return (stdout, stderr) def _demo_posix(): # # Example 1: Simple redirection: Get process list # plist = Popen(["ps"], stdout=PIPE).communicate()[0] print("Process list:") print(plist) # # Example 2: Change uid before executing child # if os.getuid() == 0: p = Popen(["id"], preexec_fn=lambda: os.setuid(100)) p.wait() # # Example 3: Connecting several subprocesses # print("Looking for 'hda'...") p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) print(repr(p2.communicate()[0])) # # Example 4: Catch execution error # print() print("Trying a weird file...") try: print(Popen(["/this/path/does/not/exist"]).communicate()) except OSError as e: if e.errno == errno.ENOENT: print("The file didn't exist. I thought so...") print("Child traceback:") print(e.child_traceback) else: print("Error", e.errno) else: sys.stderr.write( "Gosh. No error.\n" ) def _demo_windows(): # # Example 1: Connecting several subprocesses # print("Looking for 'PROMPT' in set output...") p1 = Popen("set", stdout=PIPE, shell=True) p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE) print(repr(p2.communicate()[0])) # # Example 2: Simple execution of program # print("Executing calc...") p = Popen("calc") p.wait() if __name__ == "__main__": if mswindows: _demo_windows() else: _demo_posix() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_sets.py0000644000175000017500000004627513606712377023561 0ustar kurtkurt"""Classes to represent arbitrary sets (including sets of sets). This module implements sets using dictionaries whose values are ignored. The usual operations (union, intersection, deletion, etc.) are provided as both methods and operators. Important: sets are not sequences! While they support 'x in s', 'len(s)', and 'for x in s', none of those operations are unique for sequences; for example, mappings support all three as well. The characteristic operation for sequences is subscripting with small integers: s[i], for i in range(len(s)). Sets don't support subscripting at all. Also, sequences allow multiple occurrences and their elements have a definite order; sets on the other hand don't record multiple occurrences and don't remember the order of element insertion (which is why they don't support s[i]). The following classes are provided: BaseSet -- All the operations common to both mutable and immutable sets. This is an abstract class, not meant to be directly instantiated. Set -- Mutable sets, subclass of BaseSet; not hashable. ImmutableSet -- Immutable sets, subclass of BaseSet; hashable. An iterable argument is mandatory to create an ImmutableSet. _TemporarilyImmutableSet -- A wrapper around a Set, hashable, giving the same hash value as the immutable set equivalent would have. Do not use this class directly. Only hashable objects can be added to a Set. In particular, you cannot really add a Set as an element to another Set; if you try, what is actually added is an ImmutableSet built from it (it compares equal to the one you tried adding). When you ask if `x in y' where x is a Set and y is a Set or ImmutableSet, x is wrapped into a _TemporarilyImmutableSet z, and what's tested is actually `z in y'. """ # Code history: # # - Greg V. Wilson wrote the first version, using a different approach # to the mutable/immutable problem, and inheriting from dict. # # - Alex Martelli modified Greg's version to implement the current # Set/ImmutableSet approach, and make the data an attribute. # # - Guido van Rossum rewrote much of the code, made some API changes, # and cleaned up the docstrings. # # - Raymond Hettinger added a number of speedups and other # improvements. from __future__ import generators try: from itertools import ifilter, ifilterfalse except ImportError: # Code to make the module run under Py2.2 def ifilter(predicate, iterable): if predicate is None: def predicate(x): return x for x in iterable: if predicate(x): yield x def ifilterfalse(predicate, iterable): if predicate is None: def predicate(x): return x for x in iterable: if not predicate(x): yield x __all__ = ['BaseSet', 'Set', 'ImmutableSet'] class BaseSet(object): """Common base class for mutable and immutable sets.""" __slots__ = ['_data'] # Constructor def __init__(self): """This is an abstract class.""" # Don't call this from a concrete subclass! if self.__class__ is BaseSet: raise TypeError("BaseSet is an abstract class. " "Use Set or ImmutableSet.") # Standard protocols: __len__, __repr__, __str__, __iter__ def __len__(self): """Return the number of elements of a set.""" return len(self._data) def __repr__(self): """Return string representation of a set. This looks like 'Set([])'. """ return self._repr() # __str__ is the same as __repr__ __str__ = __repr__ def _repr(self, sorted=False): elements = self._data.keys() if sorted: elements.sort() return '%s(%r)' % (self.__class__.__name__, elements) def __iter__(self): """Return an iterator over the elements or a set. This is the keys iterator for the underlying dict. """ return self._data.iterkeys() # Three-way comparison is not supported. However, because __eq__ is # tried before __cmp__, if Set x == Set y, x.__eq__(y) returns True and # then cmp(x, y) returns 0 (Python doesn't actually call __cmp__ in this # case). def __cmp__(self, other): raise TypeError("can't compare sets using cmp()") # Equality comparisons using the underlying dicts. Mixed-type comparisons # are allowed here, where Set == z for non-Set z always returns False, # and Set != z always True. This allows expressions like "x in y" to # give the expected result when y is a sequence of mixed types, not # raising a pointless TypeError just because y contains a Set, or x is # a Set and y contain's a non-set ("in" invokes only __eq__). # Subtle: it would be nicer if __eq__ and __ne__ could return # NotImplemented instead of True or False. Then the other comparand # would get a chance to determine the result, and if the other comparand # also returned NotImplemented then it would fall back to object address # comparison (which would always return False for __eq__ and always # True for __ne__). However, that doesn't work, because this type # *also* implements __cmp__: if, e.g., __eq__ returns NotImplemented, # Python tries __cmp__ next, and the __cmp__ here then raises TypeError. def __eq__(self, other): if isinstance(other, BaseSet): return self._data == other._data else: return False def __ne__(self, other): if isinstance(other, BaseSet): return self._data != other._data else: return True # Copying operations def copy(self): """Return a shallow copy of a set.""" result = self.__class__() result._data.update(self._data) return result __copy__ = copy # For the copy module def __deepcopy__(self, memo): """Return a deep copy of a set; used by copy module.""" # This pre-creates the result and inserts it in the memo # early, in case the deep copy recurses into another reference # to this same set. A set can't be an element of itself, but # it can certainly contain an object that has a reference to # itself. from copy import deepcopy result = self.__class__() memo[id(self)] = result data = result._data value = True for elt in self: data[deepcopy(elt, memo)] = value return result # Standard set operations: union, intersection, both differences. # Each has an operator version (e.g. __or__, invoked with |) and a # method version (e.g. union). # Subtle: Each pair requires distinct code so that the outcome is # correct when the type of other isn't suitable. For example, if # we did "union = __or__" instead, then Set().union(3) would return # NotImplemented instead of raising TypeError (albeit that *why* it # raises TypeError as-is is also a bit subtle). def __or__(self, other): """Return the union of two sets as a new set. (I.e. all elements that are in either set.) """ if not isinstance(other, BaseSet): return NotImplemented return self.union(other) def union(self, other): """Return the union of two sets as a new set. (I.e. all elements that are in either set.) """ result = self.__class__(self) result._update(other) return result def __and__(self, other): """Return the intersection of two sets as a new set. (I.e. all elements that are in both sets.) """ if not isinstance(other, BaseSet): return NotImplemented return self.intersection(other) def intersection(self, other): """Return the intersection of two sets as a new set. (I.e. all elements that are in both sets.) """ if not isinstance(other, BaseSet): other = Set(other) if len(self) <= len(other): little, big = self, other else: little, big = other, self common = ifilter(big._data.has_key, little) return self.__class__(common) def __xor__(self, other): """Return the symmetric difference of two sets as a new set. (I.e. all elements that are in exactly one of the sets.) """ if not isinstance(other, BaseSet): return NotImplemented return self.symmetric_difference(other) def symmetric_difference(self, other): """Return the symmetric difference of two sets as a new set. (I.e. all elements that are in exactly one of the sets.) """ result = self.__class__() data = result._data value = True selfdata = self._data try: otherdata = other._data except AttributeError: otherdata = Set(other)._data for elt in ifilterfalse(otherdata.has_key, selfdata): data[elt] = value for elt in ifilterfalse(selfdata.has_key, otherdata): data[elt] = value return result def __sub__(self, other): """Return the difference of two sets as a new Set. (I.e. all elements that are in this set and not in the other.) """ if not isinstance(other, BaseSet): return NotImplemented return self.difference(other) def difference(self, other): """Return the difference of two sets as a new Set. (I.e. all elements that are in this set and not in the other.) """ result = self.__class__() data = result._data try: otherdata = other._data except AttributeError: otherdata = Set(other)._data value = True for elt in ifilterfalse(otherdata.has_key, self): data[elt] = value return result # Membership test def __contains__(self, element): """Report whether an element is a member of a set. (Called in response to the expression `element in self'.) """ try: return element in self._data except TypeError: transform = getattr(element, "__as_temporarily_immutable__", None) if transform is None: raise # re-raise the TypeError exception we caught return transform() in self._data # Subset and superset test def issubset(self, other): """Report whether another set contains this set.""" self._binary_sanity_check(other) if len(self) > len(other): # Fast check for obvious cases return False for elt in ifilterfalse(other._data.has_key, self): return False return True def issuperset(self, other): """Report whether this set contains another set.""" self._binary_sanity_check(other) if len(self) < len(other): # Fast check for obvious cases return False for elt in ifilterfalse(self._data.has_key, other): return False return True # Inequality comparisons using the is-subset relation. __le__ = issubset __ge__ = issuperset def __lt__(self, other): self._binary_sanity_check(other) return len(self) < len(other) and self.issubset(other) def __gt__(self, other): self._binary_sanity_check(other) return len(self) > len(other) and self.issuperset(other) # Assorted helpers def _binary_sanity_check(self, other): # Check that the other argument to a binary operation is also # a set, raising a TypeError otherwise. if not isinstance(other, BaseSet): raise TypeError("Binary operation only permitted between sets") def _compute_hash(self): # Calculate hash code for a set by xor'ing the hash codes of # the elements. This ensures that the hash code does not depend # on the order in which elements are added to the set. This is # not called __hash__ because a BaseSet should not be hashable; # only an ImmutableSet is hashable. result = 0 for elt in self: result ^= hash(elt) return result def _update(self, iterable): # The main loop for update() and the subclass __init__() methods. data = self._data # Use the fast update() method when a dictionary is available. if isinstance(iterable, BaseSet): data.update(iterable._data) return value = True if type(iterable) in (list, tuple, xrange): # Optimized: we know that __iter__() and next() can't # raise TypeError, so we can move 'try:' out of the loop. it = iter(iterable) while True: try: for element in it: data[element] = value return except TypeError: transform = getattr(element, "__as_immutable__", None) if transform is None: raise # re-raise the TypeError exception we caught data[transform()] = value else: # Safe: only catch TypeError where intended for element in iterable: try: data[element] = value except TypeError: transform = getattr(element, "__as_immutable__", None) if transform is None: raise # re-raise the TypeError exception we caught data[transform()] = value class ImmutableSet(BaseSet): """Immutable set class.""" __slots__ = ['_hashcode'] # BaseSet + hashing def __init__(self, iterable=None): """Construct an immutable set from an optional iterable.""" self._hashcode = None self._data = {} if iterable is not None: self._update(iterable) def __hash__(self): if self._hashcode is None: self._hashcode = self._compute_hash() return self._hashcode def __getstate__(self): return self._data, self._hashcode def __setstate__(self, state): self._data, self._hashcode = state class Set(BaseSet): """ Mutable set class.""" __slots__ = [] # BaseSet + operations requiring mutability; no hashing def __init__(self, iterable=None): """Construct a set from an optional iterable.""" self._data = {} if iterable is not None: self._update(iterable) def __getstate__(self): # getstate's results are ignored if it is not return self._data, def __setstate__(self, data): self._data, = data def __hash__(self): """A Set cannot be hashed.""" # We inherit object.__hash__, so we must deny this explicitly raise TypeError("Can't hash a Set, only an ImmutableSet.") # In-place union, intersection, differences. # Subtle: The xyz_update() functions deliberately return None, # as do all mutating operations on built-in container types. # The __xyz__ spellings have to return self, though. def __ior__(self, other): """Update a set with the union of itself and another.""" self._binary_sanity_check(other) self._data.update(other._data) return self def union_update(self, other): """Update a set with the union of itself and another.""" self._update(other) def __iand__(self, other): """Update a set with the intersection of itself and another.""" self._binary_sanity_check(other) self._data = (self & other)._data return self def intersection_update(self, other): """Update a set with the intersection of itself and another.""" if isinstance(other, BaseSet): self &= other else: self._data = (self.intersection(other))._data def __ixor__(self, other): """Update a set with the symmetric difference of itself and another.""" self._binary_sanity_check(other) self.symmetric_difference_update(other) return self def symmetric_difference_update(self, other): """Update a set with the symmetric difference of itself and another.""" data = self._data value = True if not isinstance(other, BaseSet): other = Set(other) if self is other: self.clear() for elt in other: if elt in data: del data[elt] else: data[elt] = value def __isub__(self, other): """Remove all elements of another set from this set.""" self._binary_sanity_check(other) self.difference_update(other) return self def difference_update(self, other): """Remove all elements of another set from this set.""" data = self._data if not isinstance(other, BaseSet): other = Set(other) if self is other: self.clear() for elt in ifilter(data.has_key, other): del data[elt] # Python dict-like mass mutations: update, clear def update(self, iterable): """Add all values from an iterable (such as a list or file).""" self._update(iterable) def clear(self): """Remove all elements from this set.""" self._data.clear() # Single-element mutations: add, remove, discard def add(self, element): """Add an element to a set. This has no effect if the element is already present. """ try: self._data[element] = True except TypeError: transform = getattr(element, "__as_immutable__", None) if transform is None: raise # re-raise the TypeError exception we caught self._data[transform()] = True def remove(self, element): """Remove an element from a set; it must be a member. If the element is not a member, raise a KeyError. """ try: del self._data[element] except TypeError: transform = getattr(element, "__as_temporarily_immutable__", None) if transform is None: raise # re-raise the TypeError exception we caught del self._data[transform()] def discard(self, element): """Remove an element from a set if it is a member. If the element is not a member, do nothing. """ try: self.remove(element) except KeyError: pass def pop(self): """Remove and return an arbitrary set element.""" return self._data.popitem()[0] def __as_immutable__(self): # Return a copy of self as an immutable set return ImmutableSet(self) def __as_temporarily_immutable__(self): # Return self wrapped in a temporarily immutable set return _TemporarilyImmutableSet(self) class _TemporarilyImmutableSet(BaseSet): # Wrap a mutable set as if it was temporarily immutable. # This only supplies hashing and equality comparisons. def __init__(self, set): self._set = set self._data = set._data # Needed by ImmutableSet.__eq__() def __hash__(self): return self._set._compute_hash() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/compat/_scons_shlex.py0000644000175000017500000002713213606712377023715 0ustar kurtkurt# -*- coding: iso-8859-1 -*- """A lexical analyzer class for simple shell-like syntaxes.""" from __future__ import print_function # Module and documentation by Eric S. Raymond, 21 Dec 1998 # Input stacking and error message cleanup added by ESR, March 2000 # push_source() and pop_source() made explicit by ESR, January 2001. # Posix compliance, split(), string arguments, and # iterator interface by Gustavo Niemeyer, April 2003. import os.path import sys #from collections import deque class deque: def __init__(self): self.data = [] def __len__(self): return len(self.data) def appendleft(self, item): self.data.insert(0, item) def popleft(self): return self.data.pop(0) try: basestring except NameError: import types def is_basestring(s): return isinstance(s, bytes) else: def is_basestring(s): return isinstance(s, basestring) try: from cStringIO import StringIO except ImportError: from StringIO import StringIO __all__ = ["shlex", "split"] class shlex: "A lexical analyzer class for simple shell-like syntaxes." def __init__(self, instream=None, infile=None, posix=False): if is_basestring(instream): instream = StringIO(instream) if instream is not None: self.instream = instream self.infile = infile else: self.instream = sys.stdin self.infile = None self.posix = posix if posix: self.eof = None else: self.eof = '' self.commenters = '#' self.wordchars = ('abcdfeghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_') if self.posix: self.wordchars = self.wordchars + ('' '') self.whitespace = ' \t\r\n' self.whitespace_split = False self.quotes = '\'"' self.escape = '\\' self.escapedquotes = '"' self.state = ' ' self.pushback = deque() self.lineno = 1 self.debug = 0 self.token = '' self.filestack = deque() self.source = None if self.debug: print('shlex: reading from %s, line %d' \ % (self.instream, self.lineno)) def push_token(self, tok): "Push a token onto the stack popped by the get_token method" if self.debug >= 1: print("shlex: pushing token " + repr(tok)) self.pushback.appendleft(tok) def push_source(self, newstream, newfile=None): "Push an input source onto the lexer's input source stack." if is_basestring(newstream): newstream = StringIO(newstream) self.filestack.appendleft((self.infile, self.instream, self.lineno)) self.infile = newfile self.instream = newstream self.lineno = 1 if self.debug: if newfile is not None: print('shlex: pushing to file %s' % (self.infile,)) else: print('shlex: pushing to stream %s' % (self.instream,)) def pop_source(self): "Pop the input source stack." self.instream.close() (self.infile, self.instream, self.lineno) = self.filestack.popleft() if self.debug: print('shlex: popping to %s, line %d' \ % (self.instream, self.lineno)) self.state = ' ' def get_token(self): "Get a token from the input stream (or from stack if it's nonempty)" if self.pushback: tok = self.pushback.popleft() if self.debug >= 1: print("shlex: popping token " + repr(tok)) return tok # No pushback. Get a token. raw = self.read_token() # Handle inclusions if self.source is not None: while raw == self.source: spec = self.sourcehook(self.read_token()) if spec: (newfile, newstream) = spec self.push_source(newstream, newfile) raw = self.get_token() # Maybe we got EOF instead? while raw == self.eof: if not self.filestack: return self.eof else: self.pop_source() raw = self.get_token() # Neither inclusion nor EOF if self.debug >= 1: if raw != self.eof: print("shlex: token=" + repr(raw)) else: print("shlex: token=EOF") return raw def read_token(self): quoted = False escapedstate = ' ' while True: nextchar = self.instream.read(1) if nextchar == '\n': self.lineno = self.lineno + 1 if self.debug >= 3: print("shlex: in state", repr(self.state), \ "I see character:", repr(nextchar)) if self.state is None: self.token = '' # past end of file break elif self.state == ' ': if not nextchar: self.state = None # end of file break elif nextchar in self.whitespace: if self.debug >= 2: print("shlex: I see whitespace in whitespace state") if self.token or (self.posix and quoted): break # emit current token else: continue elif nextchar in self.commenters: self.instream.readline() self.lineno = self.lineno + 1 elif self.posix and nextchar in self.escape: escapedstate = 'a' self.state = nextchar elif nextchar in self.wordchars: self.token = nextchar self.state = 'a' elif nextchar in self.quotes: if not self.posix: self.token = nextchar self.state = nextchar elif self.whitespace_split: self.token = nextchar self.state = 'a' else: self.token = nextchar if self.token or (self.posix and quoted): break # emit current token else: continue elif self.state in self.quotes: quoted = True if not nextchar: # end of file if self.debug >= 2: print("shlex: I see EOF in quotes state") # XXX what error should be raised here? raise ValueError("No closing quotation") if nextchar == self.state: if not self.posix: self.token = self.token + nextchar self.state = ' ' break else: self.state = 'a' elif self.posix and nextchar in self.escape and \ self.state in self.escapedquotes: escapedstate = self.state self.state = nextchar else: self.token = self.token + nextchar elif self.state in self.escape: if not nextchar: # end of file if self.debug >= 2: print("shlex: I see EOF in escape state") # XXX what error should be raised here? raise ValueError("No escaped character") # In posix shells, only the quote itself or the escape # character may be escaped within quotes. if escapedstate in self.quotes and \ nextchar != self.state and nextchar != escapedstate: self.token = self.token + self.state self.token = self.token + nextchar self.state = escapedstate elif self.state == 'a': if not nextchar: self.state = None # end of file break elif nextchar in self.whitespace: if self.debug >= 2: print("shlex: I see whitespace in word state") self.state = ' ' if self.token or (self.posix and quoted): break # emit current token else: continue elif nextchar in self.commenters: self.instream.readline() self.lineno = self.lineno + 1 if self.posix: self.state = ' ' if self.token or (self.posix and quoted): break # emit current token else: continue elif self.posix and nextchar in self.quotes: self.state = nextchar elif self.posix and nextchar in self.escape: escapedstate = 'a' self.state = nextchar elif nextchar in self.wordchars or nextchar in self.quotes \ or self.whitespace_split: self.token = self.token + nextchar else: self.pushback.appendleft(nextchar) if self.debug >= 2: print("shlex: I see punctuation in word state") self.state = ' ' if self.token: break # emit current token else: continue result = self.token self.token = '' if self.posix and not quoted and result == '': result = None if self.debug > 1: if result: print("shlex: raw token=" + repr(result)) else: print("shlex: raw token=EOF") return result def sourcehook(self, newfile): "Hook called on a filename to be sourced." if newfile[0] == '"': newfile = newfile[1:-1] # This implements cpp-like semantics for relative-path inclusion. if is_basestring(self.infile) and not os.path.isabs(newfile): newfile = os.path.join(os.path.dirname(self.infile), newfile) return (newfile, open(newfile, "r")) def error_leader(self, infile=None, lineno=None): "Emit a C-compiler-like, Emacs-friendly error-message leader." if infile is None: infile = self.infile if lineno is None: lineno = self.lineno return "\"%s\", line %d: " % (infile, lineno) def __iter__(self): return self def next(self): token = self.get_token() if token == self.eof: raise StopIteration return token def split(s, comments=False): lex = shlex(s, posix=True) lex.whitespace_split = True if not comments: lex.commenters = '' #return list(lex) result = [] while True: token = lex.get_token() if token == lex.eof: break result.append(token) return result if __name__ == '__main__': if len(sys.argv) == 1: lexer = shlex() else: file = sys.argv[1] lexer = shlex(open(file), file) while True: tt = lexer.get_token() if tt: print("Token: " + repr(tt)) else: break # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Sig.py0000644000175000017500000000444513606712377020467 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Sig.py 4369 2009/09/19 15:58:29 scons" __doc__ = """Place-holder for the old SCons.Sig module hierarchy This is no longer used, but code out there (such as the NSIS module on the SCons wiki) may try to import SCons.Sig. If so, we generate a warning that points them to the line that caused the import, and don't die. If someone actually tried to use the sub-modules or functions within the package (for example, SCons.Sig.MD5.signature()), then they'll still get an AttributeError, but at least they'll know where to start looking. """ import SCons.Util import SCons.Warnings msg = 'The SCons.Sig module no longer exists.\n' \ ' Remove the following "import SCons.Sig" line to eliminate this warning:' SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, msg) default_calc = None default_module = None class MD5Null(SCons.Util.Null): def __repr__(self): return "MD5Null()" class TimeStampNull(SCons.Util.Null): def __repr__(self): return "TimeStampNull()" MD5 = MD5Null() TimeStamp = TimeStampNull() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Defaults.py0000644000175000017500000004103113606712377021504 0ustar kurtkurt"""SCons.Defaults Builders and other things for the local site. Here's where we'll duplicate the functionality of autoconf until we move it into the installation procedure or use something like qmconf. The code that reads the registry to find MSVC components was borrowed from distutils.msvccompiler. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Defaults.py 4369 2009/09/19 15:58:29 scons" import os import os.path import errno import shutil import stat import string import time import types import sys import SCons.Action import SCons.Builder import SCons.CacheDir import SCons.Environment import SCons.PathList import SCons.Subst import SCons.Tool # A placeholder for a default Environment (for fetching source files # from source code management systems and the like). This must be # initialized later, after the top-level directory is set by the calling # interface. _default_env = None # Lazily instantiate the default environment so the overhead of creating # it doesn't apply when it's not needed. def _fetch_DefaultEnvironment(*args, **kw): """ Returns the already-created default construction environment. """ global _default_env return _default_env def DefaultEnvironment(*args, **kw): """ Initial public entry point for creating the default construction Environment. After creating the environment, we overwrite our name (DefaultEnvironment) with the _fetch_DefaultEnvironment() function, which more efficiently returns the initialized default construction environment without checking for its existence. (This function still exists with its _default_check because someone else (*cough* Script/__init__.py *cough*) may keep a reference to this function. So we can't use the fully functional idiom of having the name originally be a something that *only* creates the construction environment and then overwrites the name.) """ global _default_env if not _default_env: import SCons.Util _default_env = SCons.Environment.Environment(*args, **kw) if SCons.Util.md5: _default_env.Decider('MD5') else: _default_env.Decider('timestamp-match') global DefaultEnvironment DefaultEnvironment = _fetch_DefaultEnvironment _default_env._CacheDir_path = None return _default_env # Emitters for setting the shared attribute on object files, # and an action for checking that all of the source files # going into a shared library are, in fact, shared. def StaticObjectEmitter(target, source, env): for tgt in target: tgt.attributes.shared = None return (target, source) def SharedObjectEmitter(target, source, env): for tgt in target: tgt.attributes.shared = 1 return (target, source) def SharedFlagChecker(source, target, env): same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME') if same == '0' or same == '' or same == 'False': for src in source: try: shared = src.attributes.shared except AttributeError: shared = None if not shared: raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])) SharedCheck = SCons.Action.Action(SharedFlagChecker, None) # Some people were using these variable name before we made # SourceFileScanner part of the public interface. Don't break their # SConscript files until we've given them some fair warning and a # transition period. CScan = SCons.Tool.CScanner DScan = SCons.Tool.DScanner LaTeXScan = SCons.Tool.LaTeXScanner ObjSourceScan = SCons.Tool.SourceFileScanner ProgScan = SCons.Tool.ProgramScanner # These aren't really tool scanners, so they don't quite belong with # the rest of those in Tool/__init__.py, but I'm not sure where else # they should go. Leave them here for now. import SCons.Scanner.Dir DirScanner = SCons.Scanner.Dir.DirScanner() DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner() # Actions for common languages. CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR") ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR") CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR") ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR") ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR") ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR") LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR") ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR") LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR") # Common tasks that we allow users to perform in platform-independent # ways by creating ActionFactory instances. ActionFactory = SCons.Action.ActionFactory def get_paths_str(dest): # If dest is a list, we need to manually call str() on each element if SCons.Util.is_List(dest): elem_strs = [] for element in dest: elem_strs.append('"' + str(element) + '"') return '[' + string.join(elem_strs, ', ') + ']' else: return '"' + str(dest) + '"' def chmod_func(dest, mode): SCons.Node.FS.invalidate_node_memos(dest) if not SCons.Util.is_List(dest): dest = [dest] for element in dest: os.chmod(str(element), mode) def chmod_strfunc(dest, mode): return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode) Chmod = ActionFactory(chmod_func, chmod_strfunc) def copy_func(dest, src): SCons.Node.FS.invalidate_node_memos(dest) if SCons.Util.is_List(src) and os.path.isdir(dest): for file in src: shutil.copy2(file, dest) return 0 elif os.path.isfile(src): return shutil.copy2(src, dest) else: return shutil.copytree(src, dest, 1) Copy = ActionFactory(copy_func, lambda dest, src: 'Copy("%s", "%s")' % (dest, src), convert=str) def delete_func(dest, must_exist=0): SCons.Node.FS.invalidate_node_memos(dest) if not SCons.Util.is_List(dest): dest = [dest] for entry in dest: entry = str(entry) if not must_exist and not os.path.exists(entry): continue if not os.path.exists(entry) or os.path.isfile(entry): os.unlink(entry) continue else: shutil.rmtree(entry, 1) continue def delete_strfunc(dest, must_exist=0): return 'Delete(%s)' % get_paths_str(dest) Delete = ActionFactory(delete_func, delete_strfunc) def mkdir_func(dest): SCons.Node.FS.invalidate_node_memos(dest) if not SCons.Util.is_List(dest): dest = [dest] for entry in dest: try: os.makedirs(str(entry)) except os.error as e: p = str(entry) if (e[0] == errno.EEXIST or (sys.platform=='win32' and e[0]==183)) \ and os.path.isdir(str(entry)): pass # not an error if already exists else: raise Mkdir = ActionFactory(mkdir_func, lambda dir: 'Mkdir(%s)' % get_paths_str(dir)) def move_func(dest, src): SCons.Node.FS.invalidate_node_memos(dest) SCons.Node.FS.invalidate_node_memos(src) shutil.move(src, dest) Move = ActionFactory(move_func, lambda dest, src: 'Move("%s", "%s")' % (dest, src), convert=str) def touch_func(dest): SCons.Node.FS.invalidate_node_memos(dest) if not SCons.Util.is_List(dest): dest = [dest] for file in dest: file = str(file) mtime = int(time.time()) if os.path.exists(file): atime = os.path.getatime(file) else: open(file, 'w') atime = mtime os.utime(file, (atime, mtime)) Touch = ActionFactory(touch_func, lambda file: 'Touch(%s)' % get_paths_str(file)) # Internal utility functions def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None): """ Creates a new list from 'list' by first interpolating each element in the list using the 'env' dictionary and then calling f on the list, and finally calling _concat_ixes to concatenate 'prefix' and 'suffix' onto each element of the list. """ if not list: return list l = f(SCons.PathList.PathList(list).subst_path(env, target, source)) if l is not None: list = l return _concat_ixes(prefix, list, suffix, env) def _concat_ixes(prefix, list, suffix, env): """ Creates a new list from 'list' by concatenating the 'prefix' and 'suffix' arguments onto each element of the list. A trailing space on 'prefix' or leading space on 'suffix' will cause them to be put into separate list elements rather than being concatenated. """ result = [] # ensure that prefix and suffix are strings prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW)) suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW)) for x in list: if isinstance(x, SCons.Node.FS.File): result.append(x) continue x = str(x) if x: if prefix: if prefix[-1] == ' ': result.append(prefix[:-1]) elif x[:len(prefix)] != prefix: x = prefix + x result.append(x) if suffix: if suffix[0] == ' ': result.append(suffix[1:]) elif x[-len(suffix):] != suffix: result[-1] = result[-1]+suffix return result def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None): """ This is a wrapper around _concat()/_concat_ixes() that checks for the existence of prefixes or suffixes on list elements and strips them where it finds them. This is used by tools (like the GNU linker) that need to turn something like 'libfoo.a' into '-lfoo'. """ if not list: return list if not callable(c): env_c = env['_concat'] if env_c != _concat and callable(env_c): # There's a custom _concat() method in the construction # environment, and we've allowed people to set that in # the past (see test/custom-concat.py), so preserve the # backwards compatibility. c = env_c else: c = _concat_ixes stripprefixes = map(env.subst, SCons.Util.flatten(stripprefixes)) stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes)) stripped = [] for l in SCons.PathList.PathList(list).subst_path(env, None, None): if isinstance(l, SCons.Node.FS.File): stripped.append(l) continue if not SCons.Util.is_String(l): l = str(l) for stripprefix in stripprefixes: lsp = len(stripprefix) if l[:lsp] == stripprefix: l = l[lsp:] # Do not strip more than one prefix break for stripsuffix in stripsuffixes: lss = len(stripsuffix) if l[-lss:] == stripsuffix: l = l[:-lss] # Do not strip more than one suffix break stripped.append(l) return c(prefix, stripped, suffix, env) def processDefines(defs): """process defines, resolving strings, lists, dictionaries, into a list of strings """ if SCons.Util.is_List(defs): l = [] for d in defs: if SCons.Util.is_List(d) or isinstance(d, tuple): l.append(str(d[0]) + '=' + str(d[1])) else: l.append(str(d)) elif SCons.Util.is_Dict(defs): # The items in a dictionary are stored in random order, but # if the order of the command-line options changes from # invocation to invocation, then the signature of the command # line will change and we'll get random unnecessary rebuilds. # Consequently, we have to sort the keys to ensure a # consistent order... l = [] keys = sorted(defs.keys()) for k in keys: v = defs[k] if v is None: l.append(str(k)) else: l.append(str(k) + '=' + str(v)) else: l = [str(defs)] return l def _defines(prefix, defs, suffix, env, c=_concat_ixes): """A wrapper around _concat_ixes that turns a list or string into a list of C preprocessor command-line definitions. """ return c(prefix, env.subst_path(processDefines(defs)), suffix, env) class NullCmdGenerator: """This is a callable class that can be used in place of other command generators if you don't want them to do anything. The __call__ method for this class simply returns the thing you instantiated it with. Example usage: env["DO_NOTHING"] = NullCmdGenerator env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}" """ def __init__(self, cmd): self.cmd = cmd def __call__(self, target, source, env, for_signature=None): return self.cmd class Variable_Method_Caller: """A class for finding a construction variable on the stack and calling one of its methods. We use this to support "construction variables" in our string eval()s that actually stand in for methods--specifically, use of "RDirs" in call to _concat that should actually execute the "TARGET.RDirs" method. (We used to support this by creating a little "build dictionary" that mapped RDirs to the method, but this got in the way of Memoizing construction environments, because we had to create new environment objects to hold the variables.) """ def __init__(self, variable, method): self.variable = variable self.method = method def __call__(self, *args, **kw): try: 1/0 except ZeroDivisionError: # Don't start iterating with the current stack-frame to # prevent creating reference cycles (f_back is safe). frame = sys.exc_info()[2].tb_frame.f_back variable = self.variable while frame: if variable in frame.f_locals: v = frame.f_locals[variable] if v: method = getattr(v, self.method) return method(*args, **kw) frame = frame.f_back return None ConstructionEnvironment = { 'BUILDERS' : {}, 'SCANNERS' : [], 'CONFIGUREDIR' : '#/.sconf_temp', 'CONFIGURELOG' : '#/config.log', 'CPPSUFFIXES' : SCons.Tool.CSuffixes, 'DSUFFIXES' : SCons.Tool.DSuffixes, 'ENV' : {}, 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes, # 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions '_concat' : _concat, '_defines' : _defines, '_stripixes' : _stripixes, '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', 'TEMPFILE' : NullCmdGenerator, 'Dir' : Variable_Method_Caller('TARGET', 'Dir'), 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'), 'File' : Variable_Method_Caller('TARGET', 'File'), 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'), } # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/exitfuncs.py0000644000175000017500000000455213606712377021754 0ustar kurtkurt"""SCons.exitfuncs Register functions which are executed when SCons exits for any reason. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/exitfuncs.py 4369 2009/09/19 15:58:29 scons" _exithandlers = [] def _run_exitfuncs(): """run any registered exit functions _exithandlers is traversed in reverse order so functions are executed last in, first out. """ while _exithandlers: func, targs, kargs = _exithandlers.pop() func(*targs, **kargs) def register(func, *targs, **kargs): """register a function to be executed upon normal program termination func - function to be called at exit targs - optional arguments to pass to func kargs - optional keyword arguments to pass to func """ _exithandlers.append((func, targs, kargs)) import sys import atexit try: x = sys.exitfunc # if x isn't our own exit func executive, assume it's another # registered exit function - append it to our list... if x != _run_exitfuncs: register(x) except AttributeError: pass # make our exit function get run by python when it exits: atexit.register(_run_exitfuncs) del sys # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Action.py0000644000175000017500000013363413606712377021165 0ustar kurtkurt"""SCons.Action This encapsulates information about executing any sort of action that can build one or more target Nodes (typically files) from one or more source Nodes (also typically files) given a specific Environment. The base class here is ActionBase. The base class supplies just a few OO utility methods and some generic methods for displaying information about an Action in response to the various commands that control printing. A second-level base class is _ActionAction. This extends ActionBase by providing the methods that can be used to show and perform an action. True Action objects will subclass _ActionAction; Action factory class objects will subclass ActionBase. The heavy lifting is handled by subclasses for the different types of actions we might execute: CommandAction CommandGeneratorAction FunctionAction ListAction The subclasses supply the following public interface methods used by other modules: __call__() THE public interface, "calling" an Action object executes the command or Python function. This also takes care of printing a pre-substitution command for debugging purposes. get_contents() Fetches the "contents" of an Action for signature calculation plus the varlist. This is what gets MD5 checksummed to decide if a target needs to be rebuilt because its action changed. genstring() Returns a string representation of the Action *without* command substitution, but allows a CommandGeneratorAction to generate the right action based on the specified target, source and env. This is used by the Signature subsystem (through the Executor) to obtain an (imprecise) representation of the Action operation for informative purposes. Subclasses also supply the following methods for internal use within this module: __str__() Returns a string approximation of the Action; no variable substitution is performed. execute() The internal method that really, truly, actually handles the execution of a command or Python function. This is used so that the __call__() methods can take care of displaying any pre-substitution representations, and *then* execute an action without worrying about the specific Actions involved. get_presig() Fetches the "contents" of a subclass for signature calculation. The varlist is added to this to produce the Action's contents. strfunction() Returns a substituted string representation of the Action. This is used by the _ActionAction.show() command to display the command/function that will be executed to generate the target(s). There is a related independent ActionCaller class that looks like a regular Action, and which serves as a wrapper for arbitrary functions that we want to let the user specify the arguments to now, but actually execute later (when an out-of-date check determines that it's needed to be executed, for example). Objects of this class are returned by an ActionFactory class that provides a __call__() method as a convenient way for wrapping up the functions. """ # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. __revision__ = "src/engine/SCons/Action.py 4369 2009/09/19 15:58:29 scons" import cPickle import dis import os import re import string import sys import subprocess from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Executor import SCons.Util import SCons.Subst # we use these a lot, so try to optimize them is_String = SCons.Util.is_String is_List = SCons.Util.is_List class _null: pass print_actions = 1 execute_actions = 1 print_actions_presub = 0 def rfile(n): try: return n.rfile() except AttributeError: return n def default_exitstatfunc(s): return s try: SET_LINENO = dis.SET_LINENO HAVE_ARGUMENT = dis.HAVE_ARGUMENT except AttributeError: remove_set_lineno_codes = lambda x: x else: def remove_set_lineno_codes(code): result = [] n = len(code) i = 0 while i < n: c = code[i] op = ord(c) if op >= HAVE_ARGUMENT: if op != SET_LINENO: result.append(code[i:i+3]) i = i+3 else: result.append(c) i = i+1 return string.join(result, '') strip_quotes = re.compile('^[\'"](.*)[\'"]$') def _callable_contents(obj): """Return the signature contents of a callable Python object. """ try: # Test if obj is a method. return _function_contents(obj.__func__) except AttributeError: try: # Test if obj is a callable object. return _function_contents(obj.__call__.__func__) except AttributeError: try: # Test if obj is a code object. return _code_contents(obj) except AttributeError: # Test if obj is a function object. return _function_contents(obj) def _object_contents(obj): """Return the signature contents of any Python object. We have to handle the case where object contains a code object since it can be pickled directly. """ try: # Test if obj is a method. return _function_contents(obj.__func__) except AttributeError: try: # Test if obj is a callable object. return _function_contents(obj.__call__.__func__) except AttributeError: try: # Test if obj is a code object. return _code_contents(obj) except AttributeError: try: # Test if obj is a function object. return _function_contents(obj) except AttributeError: # Should be a pickable Python object. try: return cPickle.dumps(obj) except (cPickle.PicklingError, TypeError): # This is weird, but it seems that nested classes # are unpickable. The Python docs say it should # always be a PicklingError, but some Python # versions seem to return TypeError. Just do # the best we can. return str(obj) def _code_contents(code): """Return the signature contents of a code object. By providing direct access to the code object of the function, Python makes this extremely easy. Hooray! Unfortunately, older versions of Python include line number indications in the compiled byte code. Boo! So we remove the line number byte codes to prevent recompilations from moving a Python function. """ contents = [] # The code contents depends on the number of local variables # but not their actual names. contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames))) try: contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars))) except AttributeError: # Older versions of Python do not support closures. contents.append(",0,0") # The code contents depends on any constants accessed by the # function. Note that we have to call _object_contents on each # constants because the code object of nested functions can # show-up among the constants. # # Note that we also always ignore the first entry of co_consts # which contains the function doc string. We assume that the # function does not access its doc string. contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),',') + ')') # The code contents depends on the variable names used to # accessed global variable, as changing the variable name changes # the variable actually accessed and therefore changes the # function result. contents.append(',(' + string.join(map(_object_contents,code.co_names),',') + ')') # The code contents depends on its actual code!!! contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')') return string.join(contents, '') def _function_contents(func): """Return the signature contents of a function.""" contents = [_code_contents(func.__code__)] # The function contents depends on the value of defaults arguments if func.__defaults__: contents.append(',(' + string.join(map(_object_contents,func.__defaults__),',') + ')') else: contents.append(',()') # The function contents depends on the closure captured cell values. try: closure = func.__closure__ or [] except AttributeError: # Older versions of Python do not support closures. closure = [] #xxx = [_object_contents(x.cell_contents) for x in closure] try: xxx = map(lambda x: _object_contents(x.cell_contents), closure) except AttributeError: xxx = [] contents.append(',(' + string.join(xxx, ',') + ')') return string.join(contents, '') def _actionAppend(act1, act2): # This function knows how to slap two actions together. # Mainly, it handles ListActions by concatenating into # a single ListAction. a1 = Action(act1) a2 = Action(act2) if a1 is None or a2 is None: raise TypeError("Cannot append %s to %s" % (type(act1), type(act2))) if isinstance(a1, ListAction): if isinstance(a2, ListAction): return ListAction(a1.list + a2.list) else: return ListAction(a1.list + [ a2 ]) else: if isinstance(a2, ListAction): return ListAction([ a1 ] + a2.list) else: return ListAction([ a1, a2 ]) def _do_create_keywords(args, kw): """This converts any arguments after the action argument into their equivalent keywords and adds them to the kw argument. """ v = kw.get('varlist', ()) # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O'] if is_String(v): v = (v,) kw['varlist'] = tuple(v) if args: # turn positional args into equivalent keywords cmdstrfunc = args[0] if cmdstrfunc is None or is_String(cmdstrfunc): kw['cmdstr'] = cmdstrfunc elif callable(cmdstrfunc): kw['strfunction'] = cmdstrfunc else: raise SCons.Errors.UserError( 'Invalid command display variable type. ' 'You must either pass a string or a callback which ' 'accepts (target, source, env) as parameters.') if len(args) > 1: kw['varlist'] = args[1:] + kw['varlist'] if kw.get('strfunction', _null) is not _null \ and kw.get('cmdstr', _null) is not _null: raise SCons.Errors.UserError( 'Cannot have both strfunction and cmdstr args to Action()') def _do_create_action(act, kw): """This is the actual "implementation" for the Action factory method, below. This handles the fact that passing lists to Action() itself has different semantics than passing lists as elements of lists. The former will create a ListAction, the latter will create a CommandAction by converting the inner list elements to strings.""" if isinstance(act, ActionBase): return act if is_List(act): #TODO(1.5) return CommandAction(act, **kw) return CommandAction(*(act,), **kw) if callable(act): try: gen = kw['generator'] del kw['generator'] except KeyError: gen = 0 if gen: action_type = CommandGeneratorAction else: action_type = FunctionAction return action_type(act, kw) if is_String(act): var=SCons.Util.get_environment_var(act) if var: # This looks like a string that is purely an Environment # variable reference, like "$FOO" or "${FOO}". We do # something special here...we lazily evaluate the contents # of that Environment variable, so a user could put something # like a function or a CommandGenerator in that variable # instead of a string. return LazyAction(var, kw) commands = string.split(str(act), '\n') if len(commands) == 1: #TODO(1.5) return CommandAction(commands[0], **kw) return CommandAction(*(commands[0],), **kw) # The list of string commands may include a LazyAction, so we # reprocess them via _do_create_list_action. return _do_create_list_action(commands, kw) return None def _do_create_list_action(act, kw): """A factory for list actions. Convert the input list into Actions and then wrap them in a ListAction.""" acts = [] for a in act: aa = _do_create_action(a, kw) if aa is not None: acts.append(aa) if not acts: return ListAction([]) elif len(acts) == 1: return acts[0] else: return ListAction(acts) def Action(act, *args, **kw): """A factory for action objects.""" # Really simple: the _do_create_* routines do the heavy lifting. _do_create_keywords(args, kw) if is_List(act): return _do_create_list_action(act, kw) return _do_create_action(act, kw) class ActionBase: """Base class for all types of action objects that can be held by other objects (Builders, Executors, etc.) This provides the common methods for manipulating and combining those actions.""" def __cmp__(self, other): return cmp(self.__dict__, other) def no_batch_key(self, env, target, source): return None batch_key = no_batch_key def genstring(self, target, source, env): return str(self) def get_contents(self, target, source, env): result = [ self.get_presig(target, source, env) ] # This should never happen, as the Action() factory should wrap # the varlist, but just in case an action is created directly, # we duplicate this check here. vl = self.varlist if is_String(vl): vl = (vl,) for v in vl: result.append(env.subst('${'+v+'}')) return string.join(result, '') def __add__(self, other): return _actionAppend(self, other) def __radd__(self, other): return _actionAppend(other, self) def presub_lines(self, env): # CommandGeneratorAction needs a real environment # in order to return the proper string here, since # it may call LazyAction, which looks up a key # in that env. So we temporarily remember the env here, # and CommandGeneratorAction will use this env # when it calls its _generate method. self.presub_env = env lines = string.split(str(self), '\n') self.presub_env = None # don't need this any more return lines def get_targets(self, env, executor): """ Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used by this action. """ return self.targets class _ActionAction(ActionBase): """Base class for actions that create output objects.""" def __init__(self, cmdstr=_null, strfunction=_null, varlist=(), presub=_null, chdir=None, exitstatfunc=None, batch_key=None, targets='$TARGETS', **kw): self.cmdstr = cmdstr if strfunction is not _null: if strfunction is None: self.cmdstr = None else: self.strfunction = strfunction self.varlist = varlist self.presub = presub self.chdir = chdir if not exitstatfunc: exitstatfunc = default_exitstatfunc self.exitstatfunc = exitstatfunc self.targets = targets if batch_key: if not callable(batch_key): # They have set batch_key, but not to their own # callable. The default behavior here will batch # *all* targets+sources using this action, separated # for each construction environment. def default_batch_key(self, env, target, source): return (id(self), id(env)) batch_key = default_batch_key SCons.Util.AddMethod(self, batch_key, 'batch_key') def print_cmd_line(self, s, target, source, env): sys.stdout.write(s + "\n") def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, show=_null, execute=_null, chdir=_null, executor=None): if not is_List(target): target = [target] if not is_List(source): source = [source] if presub is _null: presub = self.presub if presub is _null: presub = print_actions_presub if exitstatfunc is _null: exitstatfunc = self.exitstatfunc if show is _null: show = print_actions if execute is _null: execute = execute_actions if chdir is _null: chdir = self.chdir save_cwd = None if chdir: save_cwd = os.getcwd() try: chdir = str(chdir.abspath) except AttributeError: if not is_String(chdir): if executor: chdir = str(executor.batches[0].targets[0].dir) else: chdir = str(target[0].dir) if presub: if executor: target = executor.get_all_targets() source = executor.get_all_sources() t = string.join(map(str, target), ' and ') l = string.join(self.presub_lines(env), '\n ') out = "Building %s with action:\n %s\n" % (t, l) sys.stdout.write(out) cmd = None if show and self.strfunction: if executor: target = executor.get_all_targets() source = executor.get_all_sources() try: cmd = self.strfunction(target, source, env, executor) except TypeError: cmd = self.strfunction(target, source, env) if cmd: if chdir: cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd try: get = env.get except AttributeError: print_func = self.print_cmd_line else: print_func = get('PRINT_CMD_LINE_FUNC') if not print_func: print_func = self.print_cmd_line print_func(cmd, target, source, env) stat = 0 if execute: if chdir: os.chdir(chdir) try: stat = self.execute(target, source, env, executor=executor) if isinstance(stat, SCons.Errors.BuildError): s = exitstatfunc(stat.status) if s: stat.status = s else: stat = s else: stat = exitstatfunc(stat) finally: if save_cwd: os.chdir(save_cwd) if cmd and save_cwd: print_func('os.chdir(%s)' % repr(save_cwd), target, source, env) return stat def _string_from_cmd_list(cmd_list): """Takes a list of command line arguments and returns a pretty representation for printing.""" cl = [] for arg in map(str, cmd_list): if ' ' in arg or '\t' in arg: arg = '"' + arg + '"' cl.append(arg) return string.join(cl) # A fiddlin' little function that has an 'import SCons.Environment' which # can't be moved to the top level without creating an import loop. Since # this import creates a local variable named 'SCons', it blocks access to # the global variable, so we move it here to prevent complaints about local # variables being used uninitialized. default_ENV = None def get_default_ENV(env): global default_ENV try: return env['ENV'] except KeyError: if not default_ENV: import SCons.Environment # This is a hideously expensive way to get a default shell # environment. What it really should do is run the platform # setup to get the default ENV. Fortunately, it's incredibly # rare for an Environment not to have a shell environment, so # we're not going to worry about it overmuch. default_ENV = SCons.Environment.Environment()['ENV'] return default_ENV # This function is still in draft mode. We're going to need something like # it in the long run as more and more places use subprocess, but I'm sure # it'll have to be tweaked to get the full desired functionality. # one special arg (so far?), 'error', to tell what to do with exceptions. def _subproc(env, cmd, error = 'ignore', **kw): """Do common setup for a subprocess.Popen() call""" # allow std{in,out,err} to be "'devnull'" io = kw.get('stdin') if is_String(io) and io == 'devnull': kw['stdin'] = open(os.devnull) io = kw.get('stdout') if is_String(io) and io == 'devnull': kw['stdout'] = open(os.devnull, 'w') io = kw.get('stderr') if is_String(io) and io == 'devnull': kw['stderr'] = open(os.devnull, 'w') # Figure out what shell environment to use ENV = kw.get('env', None) if ENV is None: ENV = get_default_ENV(env) # Ensure that the ENV values are all strings: new_env = {} for key, value in ENV.items(): if is_List(value): # If the value is a list, then we assume it is a path list, # because that's a pretty common list-like value to stick # in an environment variable: value = SCons.Util.flatten_sequence(value) new_env[key] = string.join(map(str, value), os.pathsep) else: # It's either a string or something else. If it's a string, # we still want to call str() because it might be a *Unicode* # string, which makes subprocess.Popen() gag. If it isn't a # string or a list, then we just coerce it to a string, which # is the proper way to handle Dir and File instances and will # produce something reasonable for just about everything else: new_env[key] = str(value) kw['env'] = new_env try: #FUTURE return subprocess.Popen(cmd, **kw) return subprocess.Popen(*(cmd,), **kw) except EnvironmentError as e: if error == 'raise': raise # return a dummy Popen instance that only returns error class dummyPopen: def __init__(self, e): self.exception = e def communicate(self): return ('','') def wait(self): return -self.exception.errno stdin = None class f: def read(self): return '' def readline(self): return '' stdout = stderr = f() return dummyPopen(e) class CommandAction(_ActionAction): """Class for command-execution actions.""" def __init__(self, cmd, **kw): # Cmd can actually be a list or a single item; if it's a # single item it should be the command string to execute; if a # list then it should be the words of the command string to # execute. Only a single command should be executed by this # object; lists of commands should be handled by embedding # these objects in a ListAction object (which the Action() # factory above does). cmd will be passed to # Environment.subst_list() for substituting environment # variables. if __debug__: logInstanceCreation(self, 'Action.CommandAction') #TODO(1.5) _ActionAction.__init__(self, **kw) _ActionAction.__init__(*(self,), **kw) if is_List(cmd): if filter(is_List, cmd): raise TypeError("CommandAction should be given only " \ "a single command") self.cmd_list = cmd def __str__(self): if is_List(self.cmd_list): return string.join(map(str, self.cmd_list), ' ') return str(self.cmd_list) def process(self, target, source, env, executor=None): if executor: result = env.subst_list(self.cmd_list, 0, executor=executor) else: result = env.subst_list(self.cmd_list, 0, target, source) silent = None ignore = None while True: try: c = result[0][0][0] except IndexError: c = None if c == '@': silent = 1 elif c == '-': ignore = 1 else: break result[0][0] = result[0][0][1:] try: if not result[0][0]: result[0] = result[0][1:] except IndexError: pass return result, ignore, silent def strfunction(self, target, source, env, executor=None): if self.cmdstr is None: return None if self.cmdstr is not _null: from SCons.Subst import SUBST_RAW if executor: c = env.subst(self.cmdstr, SUBST_RAW, executor=executor) else: c = env.subst(self.cmdstr, SUBST_RAW, target, source) if c: return c cmd_list, ignore, silent = self.process(target, source, env, executor) if silent: return '' return _string_from_cmd_list(cmd_list[0]) def execute(self, target, source, env, executor=None): """Execute a command action. This will handle lists of commands as well as individual commands, because construction variable substitution may turn a single "command" into a list. This means that this class can actually handle lists of commands, even though that's not how we use it externally. """ escape_list = SCons.Subst.escape_list flatten_sequence = SCons.Util.flatten_sequence try: shell = env['SHELL'] except KeyError: raise SCons.Errors.UserError('Missing SHELL construction variable.') try: spawn = env['SPAWN'] except KeyError: raise SCons.Errors.UserError('Missing SPAWN construction variable.') else: if is_String(spawn): spawn = env.subst(spawn, raw=1, conv=lambda x: x) escape = env.get('ESCAPE', lambda x: x) ENV = get_default_ENV(env) # Ensure that the ENV values are all strings: for key, value in ENV.items(): if not is_String(value): if is_List(value): # If the value is a list, then we assume it is a # path list, because that's a pretty common list-like # value to stick in an environment variable: value = flatten_sequence(value) ENV[key] = string.join(map(str, value), os.pathsep) else: # If it isn't a string or a list, then we just coerce # it to a string, which is the proper way to handle # Dir and File instances and will produce something # reasonable for just about everything else: ENV[key] = str(value) if executor: target = executor.get_all_targets() source = executor.get_all_sources() cmd_list, ignore, silent = self.process(target, map(rfile, source), env, executor) # Use len() to filter out any "command" that's zero-length. for cmd_line in filter(len, cmd_list): # Escape the command line for the interpreter we are using. cmd_line = escape_list(cmd_line, escape) result = spawn(shell, escape, cmd_line[0], cmd_line, ENV) if not ignore and result: msg = "Error %s" % result return SCons.Errors.BuildError(errstr=msg, status=result, action=self, command=cmd_line) return 0 def get_presig(self, target, source, env, executor=None): """Return the signature contents of this action's command line. This strips $(-$) and everything in between the string, since those parts don't affect signatures. """ from SCons.Subst import SUBST_SIG cmd = self.cmd_list if is_List(cmd): cmd = string.join(map(str, cmd)) else: cmd = str(cmd) if executor: return env.subst_target_source(cmd, SUBST_SIG, executor=executor) else: return env.subst_target_source(cmd, SUBST_SIG, target, source) def get_implicit_deps(self, target, source, env, executor=None): icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True) if is_String(icd) and icd[:1] == '$': icd = env.subst(icd) if not icd or icd in ('0', 'None'): return [] from SCons.Subst import SUBST_SIG if executor: cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor) else: cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source) res = [] for cmd_line in cmd_list: if cmd_line: d = str(cmd_line[0]) m = strip_quotes.match(d) if m: d = m.group(1) d = env.WhereIs(d) if d: res.append(env.fs.File(d)) return res class CommandGeneratorAction(ActionBase): """Class for command-generator actions.""" def __init__(self, generator, kw): if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction') self.generator = generator self.gen_kw = kw self.varlist = kw.get('varlist', ()) self.targets = kw.get('targets', '$TARGETS') def _generate(self, target, source, env, for_signature, executor=None): # ensure that target is a list, to make it easier to write # generator functions: if not is_List(target): target = [target] if executor: target = executor.get_all_targets() source = executor.get_all_sources() ret = self.generator(target=target, source=source, env=env, for_signature=for_signature) #TODO(1.5) gen_cmd = Action(ret, **self.gen_kw) gen_cmd = Action(*(ret,), **self.gen_kw) if not gen_cmd: raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret)) return gen_cmd def __str__(self): try: env = self.presub_env except AttributeError: env = None if env is None: env = SCons.Defaults.DefaultEnvironment() act = self._generate([], [], env, 1) return str(act) def batch_key(self, env, target, source): return self._generate(target, source, env, 1).batch_key(env, target, source) def genstring(self, target, source, env, executor=None): return self._generate(target, source, env, 1, executor).genstring(target, source, env) def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, show=_null, execute=_null, chdir=_null, executor=None): act = self._generate(target, source, env, 0, executor) if act is None: raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source)))) return act(target, source, env, exitstatfunc, presub, show, execute, chdir, executor) def get_presig(self, target, source, env, executor=None): """Return the signature contents of this action's command line. This strips $(-$) and everything in between the string, since those parts don't affect signatures. """ return self._generate(target, source, env, 1, executor).get_presig(target, source, env) def get_implicit_deps(self, target, source, env, executor=None): return self._generate(target, source, env, 1, executor).get_implicit_deps(target, source, env) def get_targets(self, env, executor): return self._generate(None, None, env, 1, executor).get_targets(env, executor) # A LazyAction is a kind of hybrid generator and command action for # strings of the form "$VAR". These strings normally expand to other # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also # want to be able to replace them with functions in the construction # environment. Consequently, we want lazy evaluation and creation of # an Action in the case of the function, but that's overkill in the more # normal case of expansion to other strings. # # So we do this with a subclass that's both a generator *and* # a command action. The overridden methods all do a quick check # of the construction variable, and if it's a string we just call # the corresponding CommandAction method to do the heavy lifting. # If not, then we call the same-named CommandGeneratorAction method. # The CommandGeneratorAction methods work by using the overridden # _generate() method, that is, our own way of handling "generation" of # an action based on what's in the construction variable. class LazyAction(CommandGeneratorAction, CommandAction): def __init__(self, var, kw): if __debug__: logInstanceCreation(self, 'Action.LazyAction') #FUTURE CommandAction.__init__(self, '${'+var+'}', **kw) CommandAction.__init__(*(self, '${'+var+'}'), **kw) self.var = SCons.Util.to_String(var) self.gen_kw = kw def get_parent_class(self, env): c = env.get(self.var) if is_String(c) and not '\n' in c: return CommandAction return CommandGeneratorAction def _generate_cache(self, env): if env: c = env.get(self.var, '') else: c = '' #TODO(1.5) gen_cmd = Action(c, **self.gen_kw) gen_cmd = Action(*(c,), **self.gen_kw) if not gen_cmd: raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c))) return gen_cmd def _generate(self, target, source, env, for_signature, executor=None): return self._generate_cache(env) def __call__(self, target, source, env, *args, **kw): args = (self, target, source, env) + args c = self.get_parent_class(env) #TODO(1.5) return c.__call__(*args, **kw) return c.__call__(*args, **kw) def get_presig(self, target, source, env): c = self.get_parent_class(env) return c.get_presig(self, target, source, env) class FunctionAction(_ActionAction): """Class for Python function actions.""" def __init__(self, execfunction, kw): if __debug__: logInstanceCreation(self, 'Action.FunctionAction') self.execfunction = execfunction try: self.funccontents = _callable_contents(execfunction) except AttributeError: try: # See if execfunction will do the heavy lifting for us. self.gc = execfunction.get_contents except AttributeError: # This is weird, just do the best we can. self.funccontents = _object_contents(execfunction) #TODO(1.5) _ActionAction.__init__(self, **kw) _ActionAction.__init__(*(self,), **kw) def function_name(self): try: return self.execfunction.__name__ except AttributeError: try: return self.execfunction.__class__.__name__ except AttributeError: return "unknown_python_function" def strfunction(self, target, source, env, executor=None): if self.cmdstr is None: return None if self.cmdstr is not _null: from SCons.Subst import SUBST_RAW if executor: c = env.subst(self.cmdstr, SUBST_RAW, executor=executor) else: c = env.subst(self.cmdstr, SUBST_RAW, target, source) if c: return c def array(a): def quote(s): try: str_for_display = s.str_for_display except AttributeError: s = repr(s) else: s = str_for_display() return s return '[' + string.join(map(quote, a), ", ") + ']' try: strfunc = self.execfunction.strfunction except AttributeError: pass else: if strfunc is None: return None if callable(strfunc): return strfunc(target, source, env) name = self.function_name() tstr = array(target) sstr = array(source) return "%s(%s, %s)" % (name, tstr, sstr) def __str__(self): name = self.function_name() if name == 'ActionCaller': return str(self.execfunction) return "%s(target, source, env)" % name def execute(self, target, source, env, executor=None): exc_info = (None,None,None) try: if executor: target = executor.get_all_targets() source = executor.get_all_sources() rsources = map(rfile, source) try: result = self.execfunction(target=target, source=rsources, env=env) except KeyboardInterrupt as e: raise except SystemExit as e: raise except Exception as e: result = e exc_info = sys.exc_info() if result: result = SCons.Errors.convert_to_BuildError(result, exc_info) result.node=target result.action=self try: result.command=self.strfunction(target, source, env, executor) except TypeError: result.command=self.strfunction(target, source, env) # FIXME: This maintains backward compatibility with respect to # which type of exceptions were returned by raising an # exception and which ones were returned by value. It would # probably be best to always return them by value here, but # some codes do not check the return value of Actions and I do # not have the time to modify them at this point. if (exc_info[1] and not isinstance(exc_info[1],EnvironmentError)): raise result return result finally: # Break the cycle between the traceback object and this # function stack frame. See the sys.exc_info() doc info for # more information about this issue. del exc_info def get_presig(self, target, source, env): """Return the signature contents of this callable action.""" try: return self.gc(target, source, env) except AttributeError: return self.funccontents def get_implicit_deps(self, target, source, env): return [] class ListAction(ActionBase): """Class for lists of other actions.""" def __init__(self, list): if __debug__: logInstanceCreation(self, 'Action.ListAction') def list_of_actions(x): if isinstance(x, ActionBase): return x return Action(x) self.list = map(list_of_actions, list) # our children will have had any varlist # applied; we don't need to do it again self.varlist = () self.targets = '$TARGETS' def genstring(self, target, source, env): return string.join(map(lambda a, t=target, s=source, e=env: a.genstring(t, s, e), self.list), '\n') def __str__(self): return string.join(map(str, self.list), '\n') def presub_lines(self, env): return SCons.Util.flatten_sequence( map(lambda a, env=env: a.presub_lines(env), self.list)) def get_presig(self, target, source, env): """Return the signature contents of this action list. Simple concatenation of the signatures of the elements. """ return string.join(map(lambda x, t=target, s=source, e=env: x.get_contents(t, s, e), self.list), "") def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, show=_null, execute=_null, chdir=_null, executor=None): if executor: target = executor.get_all_targets() source = executor.get_all_sources() for act in self.list: stat = act(target, source, env, exitstatfunc, presub, show, execute, chdir, executor) if stat: return stat return 0 def get_implicit_deps(self, target, source, env): result = [] for act in self.list: result.extend(act.get_implicit_deps(target, source, env)) return result class ActionCaller: """A class for delaying calling an Action function with specific (positional and keyword) arguments until the Action is actually executed. This class looks to the rest of the world like a normal Action object, but what it's really doing is hanging on to the arguments until we have a target, source and env to use for the expansion. """ def __init__(self, parent, args, kw): self.parent = parent self.args = args self.kw = kw def get_contents(self, target, source, env): actfunc = self.parent.actfunc try: # "self.actfunc" is a function. contents = str(actfunc.__code__.co_code) except AttributeError: # "self.actfunc" is a callable object. try: contents = str(actfunc.__call__.__func__.__code__.co_code) except AttributeError: # No __call__() method, so it might be a builtin # or something like that. Do the best we can. contents = str(actfunc) contents = remove_set_lineno_codes(contents) return contents def subst(self, s, target, source, env): # If s is a list, recursively apply subst() # to every element in the list if is_List(s): result = [] for elem in s: result.append(self.subst(elem, target, source, env)) return self.parent.convert(result) # Special-case hack: Let a custom function wrapped in an # ActionCaller get at the environment through which the action # was called by using this hard-coded value as a special return. if s == '$__env__': return env elif is_String(s): return env.subst(s, 1, target, source) return self.parent.convert(s) def subst_args(self, target, source, env): return map(lambda x, self=self, t=target, s=source, e=env: self.subst(x, t, s, e), self.args) def subst_kw(self, target, source, env): kw = {} for key in self.kw.keys(): kw[key] = self.subst(self.kw[key], target, source, env) return kw def __call__(self, target, source, env, executor=None): args = self.subst_args(target, source, env) kw = self.subst_kw(target, source, env) #TODO(1.5) return self.parent.actfunc(*args, **kw) return self.parent.actfunc(*args, **kw) def strfunction(self, target, source, env): args = self.subst_args(target, source, env) kw = self.subst_kw(target, source, env) #TODO(1.5) return self.parent.strfunc(*args, **kw) return self.parent.strfunc(*args, **kw) def __str__(self): #TODO(1.5) return self.parent.strfunc(*self.args, **self.kw) return self.parent.strfunc(*self.args, **self.kw) class ActionFactory: """A factory class that will wrap up an arbitrary function as an SCons-executable Action object. The real heavy lifting here is done by the ActionCaller class. We just collect the (positional and keyword) arguments that we're called with and give them to the ActionCaller object we create, so it can hang onto them until it needs them. """ def __init__(self, actfunc, strfunc, convert=lambda x: x): self.actfunc = actfunc self.strfunc = strfunc self.convert = convert def __call__(self, *args, **kw): ac = ActionCaller(self, args, kw) action = Action(ac, strfunction=ac.strfunction) return action # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Conftest.py0000644000175000017500000006614013606712377021532 0ustar kurtkurt"""SCons.Conftest Autoconf-like configuration support; low level implementation of tests. """ # # Copyright (c) 2003 Stichting NLnet Labs # Copyright (c) 2001, 2002, 2003 Steven Knight # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # # The purpose of this module is to define how a check is to be performed. # Use one of the Check...() functions below. # # # A context class is used that defines functions for carrying out the tests, # logging and messages. The following methods and members must be present: # # context.Display(msg) Function called to print messages that are normally # displayed for the user. Newlines are explicitly used. # The text should also be written to the logfile! # # context.Log(msg) Function called to write to a log file. # # context.BuildProg(text, ext) # Function called to build a program, using "ext" for the # file extention. Must return an empty string for # success, an error message for failure. # For reliable test results building should be done just # like an actual program would be build, using the same # command and arguments (including configure results so # far). # # context.CompileProg(text, ext) # Function called to compile a program, using "ext" for # the file extention. Must return an empty string for # success, an error message for failure. # For reliable test results compiling should be done just # like an actual source file would be compiled, using the # same command and arguments (including configure results # so far). # # context.AppendLIBS(lib_name_list) # Append "lib_name_list" to the value of LIBS. # "lib_namelist" is a list of strings. # Return the value of LIBS before changing it (any type # can be used, it is passed to SetLIBS() later.) # # context.PrependLIBS(lib_name_list) # Prepend "lib_name_list" to the value of LIBS. # "lib_namelist" is a list of strings. # Return the value of LIBS before changing it (any type # can be used, it is passed to SetLIBS() later.) # # context.SetLIBS(value) # Set LIBS to "value". The type of "value" is what # AppendLIBS() returned. # Return the value of LIBS before changing it (any type # can be used, it is passed to SetLIBS() later.) # # context.headerfilename # Name of file to append configure results to, usually # "confdefs.h". # The file must not exist or be empty when starting. # Empty or None to skip this (some tests will not work!). # # context.config_h (may be missing). If present, must be a string, which # will be filled with the contents of a config_h file. # # context.vardict Dictionary holding variables used for the tests and # stores results from the tests, used for the build # commands. # Normally contains "CC", "LIBS", "CPPFLAGS", etc. # # context.havedict Dictionary holding results from the tests that are to # be used inside a program. # Names often start with "HAVE_". These are zero # (feature not present) or one (feature present). Other # variables may have any value, e.g., "PERLVERSION" can # be a number and "SYSTEMNAME" a string. # import re import string from types import IntType # # PUBLIC VARIABLES # LogInputFiles = 1 # Set that to log the input files in case of a failed test LogErrorMessages = 1 # Set that to log Conftest-generated error messages # # PUBLIC FUNCTIONS # # Generic remarks: # - When a language is specified which is not supported the test fails. The # message is a bit different, because not all the arguments for the normal # message are available yet (chicken-egg problem). def CheckBuilder(context, text = None, language = None): """ Configure check to see if the compiler works. Note that this uses the current value of compiler and linker flags, make sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. "language" should be "C" or "C++" and is used to select the compiler. Default is "C". "text" may be used to specify the code to be build. Returns an empty string for success, an error message for failure. """ lang, suffix, msg = _lang2suffix(language) if msg: context.Display("%s\n" % msg) return msg if not text: text = """ int main() { return 0; } """ context.Display("Checking if building a %s file works... " % lang) ret = context.BuildProg(text, suffix) _YesNoResult(context, ret, None, text) return ret def CheckCC(context): """ Configure check for a working C compiler. This checks whether the C compiler, as defined in the $CC construction variable, can compile a C source file. It uses the current $CCCOM value too, so that it can test against non working flags. """ context.Display("Checking whether the C compiler works") text = """ int main() { return 0; } """ ret = _check_empty_program(context, 'CC', text, 'C') _YesNoResult(context, ret, None, text) return ret def CheckSHCC(context): """ Configure check for a working shared C compiler. This checks whether the C compiler, as defined in the $SHCC construction variable, can compile a C source file. It uses the current $SHCCCOM value too, so that it can test against non working flags. """ context.Display("Checking whether the (shared) C compiler works") text = """ int foo() { return 0; } """ ret = _check_empty_program(context, 'SHCC', text, 'C', use_shared = True) _YesNoResult(context, ret, None, text) return ret def CheckCXX(context): """ Configure check for a working CXX compiler. This checks whether the CXX compiler, as defined in the $CXX construction variable, can compile a CXX source file. It uses the current $CXXCOM value too, so that it can test against non working flags. """ context.Display("Checking whether the C++ compiler works") text = """ int main() { return 0; } """ ret = _check_empty_program(context, 'CXX', text, 'C++') _YesNoResult(context, ret, None, text) return ret def CheckSHCXX(context): """ Configure check for a working shared CXX compiler. This checks whether the CXX compiler, as defined in the $SHCXX construction variable, can compile a CXX source file. It uses the current $SHCXXCOM value too, so that it can test against non working flags. """ context.Display("Checking whether the (shared) C++ compiler works") text = """ int main() { return 0; } """ ret = _check_empty_program(context, 'SHCXX', text, 'C++', use_shared = True) _YesNoResult(context, ret, None, text) return ret def _check_empty_program(context, comp, text, language, use_shared = False): """Return 0 on success, 1 otherwise.""" if comp not in context.env or not context.env[comp]: # The compiler construction variable is not set or empty return 1 lang, suffix, msg = _lang2suffix(language) if msg: return 1 if use_shared: return context.CompileSharedObject(text, suffix) else: return context.CompileProg(text, suffix) def CheckFunc(context, function_name, header = None, language = None): """ Configure check for a function "function_name". "language" should be "C" or "C++" and is used to select the compiler. Default is "C". Optional "header" can be defined to define a function prototype, include a header file or anything else that comes before main(). Sets HAVE_function_name in context.havedict according to the result. Note that this uses the current value of compiler and linker flags, make sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. Returns an empty string for success, an error message for failure. """ # Remarks from autoconf: # - Don't include because on OSF/1 3.0 it includes # which includes which contains a prototype for select. # Similarly for bzero. # - assert.h is included to define __stub macros and hopefully few # prototypes, which can conflict with char $1(); below. # - Override any gcc2 internal prototype to avoid an error. # - We use char for the function declaration because int might match the # return type of a gcc2 builtin and then its argument prototype would # still apply. # - The GNU C library defines this for functions which it implements to # always fail with ENOSYS. Some functions are actually named something # starting with __ and the normal name is an alias. if context.headerfilename: includetext = '#include "%s"' % context.headerfilename else: includetext = '' if not header: header = """ #ifdef __cplusplus extern "C" #endif char %s();""" % function_name lang, suffix, msg = _lang2suffix(language) if msg: context.Display("Cannot check for %s(): %s\n" % (function_name, msg)) return msg text = """ %(include)s #include %(hdr)s int main() { #if defined (__stub_%(name)s) || defined (__stub___%(name)s) fail fail fail #else %(name)s(); #endif return 0; } """ % { 'name': function_name, 'include': includetext, 'hdr': header } context.Display("Checking for %s function %s()... " % (lang, function_name)) ret = context.BuildProg(text, suffix) _YesNoResult(context, ret, "HAVE_" + function_name, text, "Define to 1 if the system has the function `%s'." %\ function_name) return ret def CheckHeader(context, header_name, header = None, language = None, include_quotes = None): """ Configure check for a C or C++ header file "header_name". Optional "header" can be defined to do something before including the header file (unusual, supported for consistency). "language" should be "C" or "C++" and is used to select the compiler. Default is "C". Sets HAVE_header_name in context.havedict according to the result. Note that this uses the current value of compiler and linker flags, make sure $CFLAGS and $CPPFLAGS are set correctly. Returns an empty string for success, an error message for failure. """ # Why compile the program instead of just running the preprocessor? # It is possible that the header file exists, but actually using it may # fail (e.g., because it depends on other header files). Thus this test is # more strict. It may require using the "header" argument. # # Use <> by default, because the check is normally used for system header # files. SCons passes '""' to overrule this. # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. if context.headerfilename: includetext = '#include "%s"\n' % context.headerfilename else: includetext = '' if not header: header = "" lang, suffix, msg = _lang2suffix(language) if msg: context.Display("Cannot check for header file %s: %s\n" % (header_name, msg)) return msg if not include_quotes: include_quotes = "<>" text = "%s%s\n#include %s%s%s\n\n" % (includetext, header, include_quotes[0], header_name, include_quotes[1]) context.Display("Checking for %s header file %s... " % (lang, header_name)) ret = context.CompileProg(text, suffix) _YesNoResult(context, ret, "HAVE_" + header_name, text, "Define to 1 if you have the <%s> header file." % header_name) return ret def CheckType(context, type_name, fallback = None, header = None, language = None): """ Configure check for a C or C++ type "type_name". Optional "header" can be defined to include a header file. "language" should be "C" or "C++" and is used to select the compiler. Default is "C". Sets HAVE_type_name in context.havedict according to the result. Note that this uses the current value of compiler and linker flags, make sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. Returns an empty string for success, an error message for failure. """ # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. if context.headerfilename: includetext = '#include "%s"' % context.headerfilename else: includetext = '' if not header: header = "" lang, suffix, msg = _lang2suffix(language) if msg: context.Display("Cannot check for %s type: %s\n" % (type_name, msg)) return msg # Remarks from autoconf about this test: # - Grepping for the type in include files is not reliable (grep isn't # portable anyway). # - Using "TYPE my_var;" doesn't work for const qualified types in C++. # Adding an initializer is not valid for some C++ classes. # - Using the type as parameter to a function either fails for K&$ C or for # C++. # - Using "TYPE *my_var;" is valid in C for some types that are not # declared (struct something). # - Using "sizeof(TYPE)" is valid when TYPE is actually a variable. # - Using the previous two together works reliably. text = """ %(include)s %(header)s int main() { if ((%(name)s *) 0) return 0; if (sizeof (%(name)s)) return 0; } """ % { 'include': includetext, 'header': header, 'name': type_name } context.Display("Checking for %s type %s... " % (lang, type_name)) ret = context.BuildProg(text, suffix) _YesNoResult(context, ret, "HAVE_" + type_name, text, "Define to 1 if the system has the type `%s'." % type_name) if ret and fallback and context.headerfilename: f = open(context.headerfilename, "a") f.write("typedef %s %s;\n" % (fallback, type_name)) f.close() return ret def CheckTypeSize(context, type_name, header = None, language = None, expect = None): """This check can be used to get the size of a given type, or to check whether the type is of expected size. Arguments: - type : str the type to check - includes : sequence list of headers to include in the test code before testing the type - language : str 'C' or 'C++' - expect : int if given, will test wether the type has the given number of bytes. If not given, will automatically find the size. Returns: status : int 0 if the check failed, or the found size of the type if the check succeeded.""" # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. if context.headerfilename: includetext = '#include "%s"' % context.headerfilename else: includetext = '' if not header: header = "" lang, suffix, msg = _lang2suffix(language) if msg: context.Display("Cannot check for %s type: %s\n" % (type_name, msg)) return msg src = includetext + header if not expect is None: # Only check if the given size is the right one context.Display('Checking %s is %d bytes... ' % (type_name, expect)) # test code taken from autoconf: this is a pretty clever hack to find that # a type is of a given size using only compilation. This speeds things up # quite a bit compared to straightforward code using TryRun src = src + r""" typedef %s scons_check_type; int main() { static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)]; test_array[0] = 0; return 0; } """ st = context.CompileProg(src % (type_name, expect), suffix) if not st: context.Display("yes\n") _Have(context, "SIZEOF_%s" % type_name, expect, "The size of `%s', as computed by sizeof." % type_name) return expect else: context.Display("no\n") _LogFailed(context, src, st) return 0 else: # Only check if the given size is the right one context.Message('Checking size of %s ... ' % type_name) # We have to be careful with the program we wish to test here since # compilation will be attempted using the current environment's flags. # So make sure that the program will compile without any warning. For # example using: 'int main(int argc, char** argv)' will fail with the # '-Wall -Werror' flags since the variables argc and argv would not be # used in the program... # src = src + """ #include #include int main() { printf("%d", (int)sizeof(""" + type_name + """)); return 0; } """ st, out = context.RunProg(src, suffix) try: size = int(out) except ValueError: # If cannot convert output of test prog to an integer (the size), # something went wront, so just fail st = 1 size = 0 if not st: context.Display("yes\n") _Have(context, "SIZEOF_%s" % type_name, size, "The size of `%s', as computed by sizeof." % type_name) return size else: context.Display("no\n") _LogFailed(context, src, st) return 0 return 0 def CheckDeclaration(context, symbol, includes = None, language = None): """Checks whether symbol is declared. Use the same test as autoconf, that is test whether the symbol is defined as a macro or can be used as an r-value. Arguments: symbol : str the symbol to check includes : str Optional "header" can be defined to include a header file. language : str only C and C++ supported. Returns: status : bool True if the check failed, False if succeeded.""" # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. if context.headerfilename: includetext = '#include "%s"' % context.headerfilename else: includetext = '' if not includes: includes = "" lang, suffix, msg = _lang2suffix(language) if msg: context.Display("Cannot check for declaration %s: %s\n" % (type_name, msg)) return msg src = includetext + includes context.Display('Checking whether %s is declared... ' % symbol) src = src + r""" int main() { #ifndef %s (void) %s; #endif ; return 0; } """ % (symbol, symbol) st = context.CompileProg(src, suffix) _YesNoResult(context, st, "HAVE_DECL_" + symbol, src, "Set to 1 if %s is defined." % symbol) return st def CheckLib(context, libs, func_name = None, header = None, extra_libs = None, call = None, language = None, autoadd = 1, append = True): """ Configure check for a C or C++ libraries "libs". Searches through the list of libraries, until one is found where the test succeeds. Tests if "func_name" or "call" exists in the library. Note: if it exists in another library the test succeeds anyway! Optional "header" can be defined to include a header file. If not given a default prototype for "func_name" is added. Optional "extra_libs" is a list of library names to be added after "lib_name" in the build command. To be used for libraries that "lib_name" depends on. Optional "call" replaces the call to "func_name" in the test code. It must consist of complete C statements, including a trailing ";". Both "func_name" and "call" arguments are optional, and in that case, just linking against the libs is tested. "language" should be "C" or "C++" and is used to select the compiler. Default is "C". Note that this uses the current value of compiler and linker flags, make sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly. Returns an empty string for success, an error message for failure. """ # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H. if context.headerfilename: includetext = '#include "%s"' % context.headerfilename else: includetext = '' if not header: header = "" text = """ %s %s""" % (includetext, header) # Add a function declaration if needed. if func_name and func_name != "main": if not header: text = text + """ #ifdef __cplusplus extern "C" #endif char %s(); """ % func_name # The actual test code. if not call: call = "%s();" % func_name # if no function to test, leave main() blank text = text + """ int main() { %s return 0; } """ % (call or "") if call: i = string.find(call, "\n") if i > 0: calltext = call[:i] + ".." elif call[-1] == ';': calltext = call[:-1] else: calltext = call for lib_name in libs: lang, suffix, msg = _lang2suffix(language) if msg: context.Display("Cannot check for library %s: %s\n" % (lib_name, msg)) return msg # if a function was specified to run in main(), say it if call: context.Display("Checking for %s in %s library %s... " % (calltext, lang, lib_name)) # otherwise, just say the name of library and language else: context.Display("Checking for %s library %s... " % (lang, lib_name)) if lib_name: l = [ lib_name ] if extra_libs: l.extend(extra_libs) if append: oldLIBS = context.AppendLIBS(l) else: oldLIBS = context.PrependLIBS(l) sym = "HAVE_LIB" + lib_name else: oldLIBS = -1 sym = None ret = context.BuildProg(text, suffix) _YesNoResult(context, ret, sym, text, "Define to 1 if you have the `%s' library." % lib_name) if oldLIBS != -1 and (ret or not autoadd): context.SetLIBS(oldLIBS) if not ret: return ret return ret # # END OF PUBLIC FUNCTIONS # def _YesNoResult(context, ret, key, text, comment = None): """ Handle the result of a test with a "yes" or "no" result. "ret" is the return value: empty if OK, error message when not. "key" is the name of the symbol to be defined (HAVE_foo). "text" is the source code of the program used for testing. "comment" is the C comment to add above the line defining the symbol (the comment is automatically put inside a /* */). If None, no comment is added. """ if key: _Have(context, key, not ret, comment) if ret: context.Display("no\n") _LogFailed(context, text, ret) else: context.Display("yes\n") def _Have(context, key, have, comment = None): """ Store result of a test in context.havedict and context.headerfilename. "key" is a "HAVE_abc" name. It is turned into all CAPITALS and non- alphanumerics are replaced by an underscore. The value of "have" can be: 1 - Feature is defined, add "#define key". 0 - Feature is not defined, add "/* #undef key */". Adding "undef" is what autoconf does. Not useful for the compiler, but it shows that the test was done. number - Feature is defined to this number "#define key have". Doesn't work for 0 or 1, use a string then. string - Feature is defined to this string "#define key have". Give "have" as is should appear in the header file, include quotes when desired and escape special characters! """ key_up = string.upper(key) key_up = re.sub('[^A-Z0-9_]', '_', key_up) context.havedict[key_up] = have if have == 1: line = "#define %s 1\n" % key_up elif have == 0: line = "/* #undef %s */\n" % key_up elif isinstance(have, IntType): line = "#define %s %d\n" % (key_up, have) else: line = "#define %s %s\n" % (key_up, str(have)) if comment is not None: lines = "\n/* %s */\n" % comment + line else: lines = "\n" + line if context.headerfilename: f = open(context.headerfilename, "a") f.write(lines) f.close() elif hasattr(context,'config_h'): context.config_h = context.config_h + lines def _LogFailed(context, text, msg): """ Write to the log about a failed program. Add line numbers, so that error messages can be understood. """ if LogInputFiles: context.Log("Failed program was:\n") lines = string.split(text, '\n') if len(lines) and lines[-1] == '': lines = lines[:-1] # remove trailing empty line n = 1 for line in lines: context.Log("%d: %s\n" % (n, line)) n = n + 1 if LogErrorMessages: context.Log("Error message: %s\n" % msg) def _lang2suffix(lang): """ Convert a language name to a suffix. When "lang" is empty or None C is assumed. Returns a tuple (lang, suffix, None) when it works. For an unrecognized language returns (None, None, msg). Where: lang = the unified language name suffix = the suffix, including the leading dot msg = an error message """ if not lang or lang in ["C", "c"]: return ("C", ".c", None) if lang in ["c++", "C++", "cpp", "CXX", "cxx"]: return ("C++", ".cpp", None) return None, None, "Unsupported language: %s" % lang # vim: set sw=4 et sts=4 tw=79 fo+=l: # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Environment.py0000644000175000017500000026335213606712377022255 0ustar kurtkurt"""SCons.Environment Base class for construction Environments. These are the primary objects used to communicate dependency and construction information to the build engine. Keyword arguments supplied when the construction Environment is created are construction variables used to initialize the Environment """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Environment.py 4369 2009/09/19 15:58:29 scons" import copy import os import sys import re import shlex import string from UserDict import UserDict import SCons.Action import SCons.Builder from SCons.Debug import logInstanceCreation import SCons.Defaults import SCons.Errors import SCons.Memoize import SCons.Node import SCons.Node.Alias import SCons.Node.FS import SCons.Node.Python import SCons.Platform import SCons.SConf import SCons.SConsign import SCons.Subst import SCons.Tool import SCons.Util import SCons.Warnings from functools import reduce class _Null: pass _null = _Null _warn_copy_deprecated = True _warn_source_signatures_deprecated = True _warn_target_signatures_deprecated = True CleanTargets = {} CalculatorArgs = {} semi_deepcopy = SCons.Util.semi_deepcopy # Pull UserError into the global name space for the benefit of # Environment().SourceSignatures(), which has some import statements # which seem to mess up its ability to reference SCons directly. UserError = SCons.Errors.UserError def alias_builder(env, target, source): pass AliasBuilder = SCons.Builder.Builder(action = alias_builder, target_factory = SCons.Node.Alias.default_ans.Alias, source_factory = SCons.Node.FS.Entry, multi = 1, is_explicit = None, name='AliasBuilder') def apply_tools(env, tools, toolpath): # Store the toolpath in the Environment. if toolpath is not None: env['toolpath'] = toolpath if not tools: return # Filter out null tools from the list. for tool in filter(None, tools): if SCons.Util.is_List(tool) or isinstance(tool, type(())): toolname = tool[0] toolargs = tool[1] # should be a dict of kw args tool = env.Tool(*[toolname], **toolargs) else: env.Tool(tool) # These names are (or will be) controlled by SCons; users should never # set or override them. This warning can optionally be turned off, # but scons will still ignore the illegal variable names even if it's off. reserved_construction_var_names = [ 'CHANGED_SOURCES', 'CHANGED_TARGETS', 'SOURCE', 'SOURCES', 'TARGET', 'TARGETS', 'UNCHANGED_SOURCES', 'UNCHANGED_TARGETS', ] future_reserved_construction_var_names = [ #'HOST_OS', #'HOST_ARCH', #'HOST_CPU', ] def copy_non_reserved_keywords(dict): result = semi_deepcopy(dict) for k in result.keys(): if k in reserved_construction_var_names: msg = "Ignoring attempt to set reserved variable `$%s'" SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k) del result[k] return result def _set_reserved(env, key, value): msg = "Ignoring attempt to set reserved variable `$%s'" SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % key) def _set_future_reserved(env, key, value): env._dict[key] = value msg = "`$%s' will be reserved in a future release and setting it will become ignored" SCons.Warnings.warn(SCons.Warnings.FutureReservedVariableWarning, msg % key) def _set_BUILDERS(env, key, value): try: bd = env._dict[key] for k in bd.keys(): del bd[k] except KeyError: bd = BuilderDict(kwbd, env) env._dict[key] = bd bd.update(value) def _del_SCANNERS(env, key): del env._dict[key] env.scanner_map_delete() def _set_SCANNERS(env, key, value): env._dict[key] = value env.scanner_map_delete() def _delete_duplicates(l, keep_last): """Delete duplicates from a sequence, keeping the first or last.""" seen={} result=[] if keep_last: # reverse in & out, then keep first l.reverse() for i in l: try: if i not in seen: result.append(i) seen[i]=1 except TypeError: # probably unhashable. Just keep it. result.append(i) if keep_last: result.reverse() return result # The following is partly based on code in a comment added by Peter # Shannon at the following page (there called the "transplant" class): # # ASPN : Python Cookbook : Dynamically added methods to a class # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 # # We had independently been using the idiom as BuilderWrapper, but # factoring out the common parts into this base class, and making # BuilderWrapper a subclass that overrides __call__() to enforce specific # Builder calling conventions, simplified some of our higher-layer code. class MethodWrapper: """ A generic Wrapper class that associates a method (which can actually be any callable) with an object. As part of creating this MethodWrapper object an attribute with the specified (by default, the name of the supplied method) is added to the underlying object. When that new "method" is called, our __call__() method adds the object as the first argument, simulating the Python behavior of supplying "self" on method calls. We hang on to the name by which the method was added to the underlying base class so that we can provide a method to "clone" ourselves onto a new underlying object being copied (without which we wouldn't need to save that info). """ def __init__(self, object, method, name=None): if name is None: name = method.__name__ self.object = object self.method = method self.name = name setattr(self.object, name, self) def __call__(self, *args, **kwargs): nargs = (self.object,) + args return self.method(*nargs, **kwargs) def clone(self, new_object): """ Returns an object that re-binds the underlying "method" to the specified new object. """ return self.__class__(new_object, self.method, self.name) class BuilderWrapper(MethodWrapper): """ A MethodWrapper subclass that that associates an environment with a Builder. This mainly exists to wrap the __call__() function so that all calls to Builders can have their argument lists massaged in the same way (treat a lone argument as the source, treat two arguments as target then source, make sure both target and source are lists) without having to have cut-and-paste code to do it. As a bit of obsessive backwards compatibility, we also intercept attempts to get or set the "env" or "builder" attributes, which were the names we used before we put the common functionality into the MethodWrapper base class. We'll keep this around for a while in case people shipped Tool modules that reached into the wrapper (like the Tool/qt.py module does, or did). There shouldn't be a lot attribute fetching or setting on these, so a little extra work shouldn't hurt. """ def __call__(self, target=None, source=_null, *args, **kw): if source is _null: source = target target = None if target is not None and not SCons.Util.is_List(target): target = [target] if source is not None and not SCons.Util.is_List(source): source = [source] return MethodWrapper.__call__(*(self, target, source) + args, **kw) def __repr__(self): return '' % repr(self.name) def __str__(self): return self.__repr__() def __getattr__(self, name): if name == 'env': return self.object elif name == 'builder': return self.method else: raise AttributeError(name) def __setattr__(self, name, value): if name == 'env': self.object = value elif name == 'builder': self.method = value else: self.__dict__[name] = value # This allows a Builder to be executed directly # through the Environment to which it's attached. # In practice, we shouldn't need this, because # builders actually get executed through a Node. # But we do have a unit test for this, and can't # yet rule out that it would be useful in the # future, so leave it for now. #def execute(self, **kw): # kw['env'] = self.env # apply(self.builder.execute, (), kw) class BuilderDict(UserDict): """This is a dictionary-like class used by an Environment to hold the Builders. We need to do this because every time someone changes the Builders in the Environment's BUILDERS dictionary, we must update the Environment's attributes.""" def __init__(self, dict, env): # Set self.env before calling the superclass initialization, # because it will end up calling our other methods, which will # need to point the values in this dictionary to self.env. self.env = env UserDict.__init__(self, dict) def __semi_deepcopy__(self): return self.__class__(self.data, self.env) def __setitem__(self, item, val): try: method = getattr(self.env, item).method except AttributeError: pass else: self.env.RemoveMethod(method) UserDict.__setitem__(self, item, val) BuilderWrapper(self.env, val, item) def __delitem__(self, item): UserDict.__delitem__(self, item) delattr(self.env, item) def update(self, dict): for i, v in dict.items(): self.__setitem__(i, v) _is_valid_var = re.compile(r'[_a-zA-Z]\w*$') def is_valid_construction_var(varstr): """Return if the specified string is a legitimate construction variable. """ return _is_valid_var.match(varstr) class SubstitutionEnvironment: """Base class for different flavors of construction environments. This class contains a minimal set of methods that handle contruction variable expansion and conversion of strings to Nodes, which may or may not be actually useful as a stand-alone class. Which methods ended up in this class is pretty arbitrary right now. They're basically the ones which we've empirically determined are common to the different construction environment subclasses, and most of the others that use or touch the underlying dictionary of construction variables. Eventually, this class should contain all the methods that we determine are necessary for a "minimal" interface to the build engine. A full "native Python" SCons environment has gotten pretty heavyweight with all of the methods and Tools and construction variables we've jammed in there, so it would be nice to have a lighter weight alternative for interfaces that don't need all of the bells and whistles. (At some point, we'll also probably rename this class "Base," since that more reflects what we want this class to become, but because we've released comments that tell people to subclass Environment.Base to create their own flavors of construction environment, we'll save that for a future refactoring when this class actually becomes useful.) """ if SCons.Memoize.use_memoizer: __metaclass__ = SCons.Memoize.Memoized_Metaclass def __init__(self, **kw): """Initialization of an underlying SubstitutionEnvironment class. """ if __debug__: logInstanceCreation(self, 'Environment.SubstitutionEnvironment') self.fs = SCons.Node.FS.get_default_fs() self.ans = SCons.Node.Alias.default_ans self.lookup_list = SCons.Node.arg2nodes_lookups self._dict = kw.copy() self._init_special() self.added_methods = [] #self._memo = {} def _init_special(self): """Initial the dispatch tables for special handling of special construction variables.""" self._special_del = {} self._special_del['SCANNERS'] = _del_SCANNERS self._special_set = {} for key in reserved_construction_var_names: self._special_set[key] = _set_reserved for key in future_reserved_construction_var_names: self._special_set[key] = _set_future_reserved self._special_set['BUILDERS'] = _set_BUILDERS self._special_set['SCANNERS'] = _set_SCANNERS # Freeze the keys of self._special_set in a list for use by # methods that need to check. (Empirically, list scanning has # gotten better than dict.has_key() in Python 2.5.) self._special_set_keys = self._special_set.keys() def __cmp__(self, other): return cmp(self._dict, other._dict) def __delitem__(self, key): special = self._special_del.get(key) if special: special(self, key) else: del self._dict[key] def __getitem__(self, key): return self._dict[key] def __setitem__(self, key, value): # This is heavily used. This implementation is the best we have # according to the timings in bench/env.__setitem__.py. # # The "key in self._special_set_keys" test here seems to perform # pretty well for the number of keys we have. A hard-coded # list works a little better in Python 2.5, but that has the # disadvantage of maybe getting out of sync if we ever add more # variable names. Using self._special_set.has_key() works a # little better in Python 2.4, but is worse then this test. # So right now it seems like a good trade-off, but feel free to # revisit this with bench/env.__setitem__.py as needed (and # as newer versions of Python come out). if key in self._special_set_keys: self._special_set[key](self, key, value) else: # If we already have the entry, then it's obviously a valid # key and we don't need to check. If we do check, using a # global, pre-compiled regular expression directly is more # efficient than calling another function or a method. if key not in self._dict \ and not _is_valid_var.match(key): raise SCons.Errors.UserError("Illegal construction variable `%s'" % key) self._dict[key] = value def get(self, key, default=None): """Emulates the get() method of dictionaries.""" return self._dict.get(key, default) def has_key(self, key): return key in self._dict def __contains__(self, key): return self._dict.__contains__(key) def items(self): return self._dict.items() def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw): if node_factory is _null: node_factory = self.fs.File if lookup_list is _null: lookup_list = self.lookup_list if not args: return [] args = SCons.Util.flatten(args) nodes = [] for v in args: if SCons.Util.is_String(v): n = None for l in lookup_list: n = l(v) if n is not None: break if n is not None: if SCons.Util.is_String(n): # n = self.subst(n, raw=1, **kw) kw['raw'] = 1 n = self.subst(*(n,), **kw) if node_factory: n = node_factory(n) if SCons.Util.is_List(n): nodes.extend(n) else: nodes.append(n) elif node_factory: # v = node_factory(self.subst(v, raw=1, **kw)) kw['raw'] = 1 v = node_factory(self.subst(*(v,), **kw)) if SCons.Util.is_List(v): nodes.extend(v) else: nodes.append(v) else: nodes.append(v) return nodes def gvars(self): return self._dict def lvars(self): return {} def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None): """Recursively interpolates construction variables from the Environment into the specified string, returning the expanded result. Construction variables are specified by a $ prefix in the string and begin with an initial underscore or alphabetic character followed by any number of underscores or alphanumeric characters. The construction variable names may be surrounded by curly braces to separate the name from trailing characters. """ gvars = self.gvars() lvars = self.lvars() lvars['__env__'] = self if executor: lvars.update(executor.get_lvars()) return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv) def subst_kw(self, kw, raw=0, target=None, source=None): nkw = {} for k, v in kw.items(): k = self.subst(k, raw, target, source) if SCons.Util.is_String(v): v = self.subst(v, raw, target, source) nkw[k] = v return nkw def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None): """Calls through to SCons.Subst.scons_subst_list(). See the documentation for that function.""" gvars = self.gvars() lvars = self.lvars() lvars['__env__'] = self if executor: lvars.update(executor.get_lvars()) return SCons.Subst.scons_subst_list(string, self, raw, target, source, gvars, lvars, conv) def subst_path(self, path, target=None, source=None): """Substitute a path list, turning EntryProxies into Nodes and leaving Nodes (and other objects) as-is.""" if not SCons.Util.is_List(path): path = [path] def s(obj): """This is the "string conversion" routine that we have our substitutions use to return Nodes, not strings. This relies on the fact that an EntryProxy object has a get() method that returns the underlying Node that it wraps, which is a bit of architectural dependence that we might need to break or modify in the future in response to additional requirements.""" try: get = obj.get except AttributeError: obj = SCons.Util.to_String_for_subst(obj) else: obj = get() return obj r = [] for p in path: if SCons.Util.is_String(p): p = self.subst(p, target=target, source=source, conv=s) if SCons.Util.is_List(p): if len(p) == 1: p = p[0] else: # We have an object plus a string, or multiple # objects that we need to smush together. No choice # but to make them into a string. p = string.join(map(SCons.Util.to_String_for_subst, p), '') else: p = s(p) r.append(p) return r subst_target_source = subst def backtick(self, command): import subprocess # common arguments kw = { 'stdin' : 'devnull', 'stdout' : subprocess.PIPE, 'stderr' : subprocess.PIPE, 'universal_newlines' : True, } # if the command is a list, assume it's been quoted # othewise force a shell if not SCons.Util.is_List(command): kw['shell'] = True # run constructed command #TODO(1.5) p = SCons.Action._subproc(self, command, **kw) p = SCons.Action._subproc(*(self, command), **kw) out,err = p.communicate() status = p.wait() if err: sys.stderr.write(err) if status: raise OSError("'%s' exited %d" % (command, status)) return out def AddMethod(self, function, name=None): """ Adds the specified function as a method of this construction environment with the specified name. If the name is omitted, the default name is the name of the function itself. """ method = MethodWrapper(self, function, name) self.added_methods.append(method) def RemoveMethod(self, function): """ Removes the specified function's MethodWrapper from the added_methods list, so we don't re-bind it when making a clone. """ is_not_func = lambda dm, f=function: not dm.method is f self.added_methods = filter(is_not_func, self.added_methods) def Override(self, overrides): """ Produce a modified environment whose variables are overriden by the overrides dictionaries. "overrides" is a dictionary that will override the variables of this environment. This function is much more efficient than Clone() or creating a new Environment because it doesn't copy the construction environment dictionary, it just wraps the underlying construction environment, and doesn't even create a wrapper object if there are no overrides. """ if not overrides: return self o = copy_non_reserved_keywords(overrides) if not o: return self overrides = {} merges = None for key, value in o.items(): if key == 'parse_flags': merges = value else: overrides[key] = SCons.Subst.scons_subst_once(value, self, key) env = OverrideEnvironment(self, overrides) if merges: env.MergeFlags(merges) return env def ParseFlags(self, *flags): """ Parse the set of flags and return a dict with the flags placed in the appropriate entry. The flags are treated as a typical set of command-line flags for a GNU-like toolchain and used to populate the entries in the dict immediately below. If one of the flag strings begins with a bang (exclamation mark), it is assumed to be a command and the rest of the string is executed; the result of that evaluation is then added to the dict. """ dict = { 'ASFLAGS' : SCons.Util.CLVar(''), 'CFLAGS' : SCons.Util.CLVar(''), 'CCFLAGS' : SCons.Util.CLVar(''), 'CPPDEFINES' : [], 'CPPFLAGS' : SCons.Util.CLVar(''), 'CPPPATH' : [], 'FRAMEWORKPATH' : SCons.Util.CLVar(''), 'FRAMEWORKS' : SCons.Util.CLVar(''), 'LIBPATH' : [], 'LIBS' : [], 'LINKFLAGS' : SCons.Util.CLVar(''), 'RPATH' : [], } # The use of the "me" parameter to provide our own name for # recursion is an egregious hack to support Python 2.1 and before. def do_parse(arg, me, self = self, dict = dict): # if arg is a sequence, recurse with each element if not arg: return if not SCons.Util.is_String(arg): for t in arg: me(t, me) return # if arg is a command, execute it if arg[0] == '!': arg = self.backtick(arg[1:]) # utility function to deal with -D option def append_define(name, dict = dict): t = string.split(name, '=') if len(t) == 1: dict['CPPDEFINES'].append(name) else: dict['CPPDEFINES'].append([t[0], string.join(t[1:], '=')]) # Loop through the flags and add them to the appropriate option. # This tries to strike a balance between checking for all possible # flags and keeping the logic to a finite size, so it doesn't # check for some that don't occur often. It particular, if the # flag is not known to occur in a config script and there's a way # of passing the flag to the right place (by wrapping it in a -W # flag, for example) we don't check for it. Note that most # preprocessor options are not handled, since unhandled options # are placed in CCFLAGS, so unless the preprocessor is invoked # separately, these flags will still get to the preprocessor. # Other options not currently handled: # -iqoutedir (preprocessor search path) # -u symbol (linker undefined symbol) # -s (linker strip files) # -static* (linker static binding) # -shared* (linker dynamic binding) # -symbolic (linker global binding) # -R dir (deprecated linker rpath) # IBM compilers may also accept -qframeworkdir=foo params = shlex.split(arg) append_next_arg_to = None # for multi-word args for arg in params: if append_next_arg_to: if append_next_arg_to == 'CPPDEFINES': append_define(arg) elif append_next_arg_to == '-include': t = ('-include', self.fs.File(arg)) dict['CCFLAGS'].append(t) elif append_next_arg_to == '-isysroot': t = ('-isysroot', arg) dict['CCFLAGS'].append(t) dict['LINKFLAGS'].append(t) elif append_next_arg_to == '-arch': t = ('-arch', arg) dict['CCFLAGS'].append(t) dict['LINKFLAGS'].append(t) else: dict[append_next_arg_to].append(arg) append_next_arg_to = None elif not arg[0] in ['-', '+']: dict['LIBS'].append(self.fs.File(arg)) elif arg[:2] == '-L': if arg[2:]: dict['LIBPATH'].append(arg[2:]) else: append_next_arg_to = 'LIBPATH' elif arg[:2] == '-l': if arg[2:]: dict['LIBS'].append(arg[2:]) else: append_next_arg_to = 'LIBS' elif arg[:2] == '-I': if arg[2:]: dict['CPPPATH'].append(arg[2:]) else: append_next_arg_to = 'CPPPATH' elif arg[:4] == '-Wa,': dict['ASFLAGS'].append(arg[4:]) dict['CCFLAGS'].append(arg) elif arg[:4] == '-Wl,': if arg[:11] == '-Wl,-rpath=': dict['RPATH'].append(arg[11:]) elif arg[:7] == '-Wl,-R,': dict['RPATH'].append(arg[7:]) elif arg[:6] == '-Wl,-R': dict['RPATH'].append(arg[6:]) else: dict['LINKFLAGS'].append(arg) elif arg[:4] == '-Wp,': dict['CPPFLAGS'].append(arg) elif arg[:2] == '-D': if arg[2:]: append_define(arg[2:]) else: append_next_arg_to = 'CPPDEFINES' elif arg == '-framework': append_next_arg_to = 'FRAMEWORKS' elif arg[:14] == '-frameworkdir=': dict['FRAMEWORKPATH'].append(arg[14:]) elif arg[:2] == '-F': if arg[2:]: dict['FRAMEWORKPATH'].append(arg[2:]) else: append_next_arg_to = 'FRAMEWORKPATH' elif arg == '-mno-cygwin': dict['CCFLAGS'].append(arg) dict['LINKFLAGS'].append(arg) elif arg == '-mwindows': dict['LINKFLAGS'].append(arg) elif arg == '-pthread': dict['CCFLAGS'].append(arg) dict['LINKFLAGS'].append(arg) elif arg[:5] == '-std=': dict['CFLAGS'].append(arg) # C only elif arg[0] == '+': dict['CCFLAGS'].append(arg) dict['LINKFLAGS'].append(arg) elif arg in ['-include', '-isysroot', '-arch']: append_next_arg_to = arg else: dict['CCFLAGS'].append(arg) for arg in flags: do_parse(arg, do_parse) return dict def MergeFlags(self, args, unique=1, dict=None): """ Merge the dict in args into the construction variables of this env, or the passed-in dict. If args is not a dict, it is converted into a dict using ParseFlags. If unique is not set, the flags are appended rather than merged. """ if dict is None: dict = self if not SCons.Util.is_Dict(args): args = self.ParseFlags(args) if not unique: self.Append(*(), **args) return self for key, value in args.items(): if not value: continue try: orig = self[key] except KeyError: orig = value else: if not orig: orig = value elif value: # Add orig and value. The logic here was lifted from # part of env.Append() (see there for a lot of comments # about the order in which things are tried) and is # used mainly to handle coercion of strings to CLVar to # "do the right thing" given (e.g.) an original CCFLAGS # string variable like '-pipe -Wall'. try: orig = orig + value except (KeyError, TypeError): try: add_to_orig = orig.append except AttributeError: value.insert(0, orig) orig = value else: add_to_orig(value) t = [] if key[-4:] == 'PATH': ### keep left-most occurence for v in orig: if v not in t: t.append(v) else: ### keep right-most occurence orig.reverse() for v in orig: if v not in t: t.insert(0, v) self[key] = t return self # def MergeShellPaths(self, args, prepend=1): # """ # Merge the dict in args into the shell environment in env['ENV']. # Shell path elements are appended or prepended according to prepend. # Uses Pre/AppendENVPath, so it always appends or prepends uniquely. # Example: env.MergeShellPaths({'LIBPATH': '/usr/local/lib'}) # prepends /usr/local/lib to env['ENV']['LIBPATH']. # """ # for pathname, pathval in args.items(): # if not pathval: # continue # if prepend: # apply(self.PrependENVPath, (pathname, pathval)) # else: # apply(self.AppendENVPath, (pathname, pathval)) # Used by the FindSourceFiles() method, below. # Stuck here for support of pre-2.2 Python versions. def build_source(ss, result): for s in ss: if isinstance(s, SCons.Node.FS.Dir): build_source(s.all_children(), result) elif s.has_builder(): build_source(s.sources, result) elif isinstance(s.disambiguate(), SCons.Node.FS.File): result.append(s) def default_decide_source(dependency, target, prev_ni): f = SCons.Defaults.DefaultEnvironment().decide_source return f(dependency, target, prev_ni) def default_decide_target(dependency, target, prev_ni): f = SCons.Defaults.DefaultEnvironment().decide_target return f(dependency, target, prev_ni) def default_copy_from_cache(src, dst): f = SCons.Defaults.DefaultEnvironment().copy_from_cache return f(src, dst) class Base(SubstitutionEnvironment): """Base class for "real" construction Environments. These are the primary objects used to communicate dependency and construction information to the build engine. Keyword arguments supplied when the construction Environment is created are construction variables used to initialize the Environment. """ memoizer_counters = [] ####################################################################### # This is THE class for interacting with the SCons build engine, # and it contains a lot of stuff, so we're going to try to keep this # a little organized by grouping the methods. ####################################################################### ####################################################################### # Methods that make an Environment act like a dictionary. These have # the expected standard names for Python mapping objects. Note that # we don't actually make an Environment a subclass of UserDict for # performance reasons. Note also that we only supply methods for # dictionary functionality that we actually need and use. ####################################################################### def __init__(self, platform=None, tools=None, toolpath=None, variables=None, parse_flags = None, **kw): """ Initialization of a basic SCons construction environment, including setting up special construction variables like BUILDER, PLATFORM, etc., and searching for and applying available Tools. Note that we do *not* call the underlying base class (SubsitutionEnvironment) initialization, because we need to initialize things in a very specific order that doesn't work with the much simpler base class initialization. """ if __debug__: logInstanceCreation(self, 'Environment.Base') self._memo = {} self.fs = SCons.Node.FS.get_default_fs() self.ans = SCons.Node.Alias.default_ans self.lookup_list = SCons.Node.arg2nodes_lookups self._dict = semi_deepcopy(SCons.Defaults.ConstructionEnvironment) self._init_special() self.added_methods = [] # We don't use AddMethod, or define these as methods in this # class, because we *don't* want these functions to be bound # methods. They need to operate independently so that the # settings will work properly regardless of whether a given # target ends up being built with a Base environment or an # OverrideEnvironment or what have you. self.decide_target = default_decide_target self.decide_source = default_decide_source self.copy_from_cache = default_copy_from_cache self._dict['BUILDERS'] = BuilderDict(self._dict['BUILDERS'], self) if platform is None: platform = self._dict.get('PLATFORM', None) if platform is None: platform = SCons.Platform.Platform() if SCons.Util.is_String(platform): platform = SCons.Platform.Platform(platform) self._dict['PLATFORM'] = str(platform) platform(self) self._dict['HOST_OS'] = self._dict.get('HOST_OS',None) self._dict['HOST_ARCH'] = self._dict.get('HOST_ARCH',None) # Now set defaults for TARGET_{OS|ARCH} self._dict['TARGET_OS'] = self._dict.get('HOST_OS',None) self._dict['TARGET_ARCH'] = self._dict.get('HOST_ARCH',None) # Apply the passed-in and customizable variables to the # environment before calling the tools, because they may use # some of them during initialization. if 'options' in kw: # Backwards compatibility: they may stll be using the # old "options" keyword. variables = kw['options'] del kw['options'] self.Replace(*(), **kw) keys = kw.keys() if variables: keys = keys + variables.keys() variables.Update(self) save = {} for k in keys: try: save[k] = self._dict[k] except KeyError: # No value may have been set if they tried to pass in a # reserved variable name like TARGETS. pass SCons.Tool.Initializers(self) if tools is None: tools = self._dict.get('TOOLS', None) if tools is None: tools = ['default'] apply_tools(self, tools, toolpath) # Now restore the passed-in and customized variables # to the environment, since the values the user set explicitly # should override any values set by the tools. for key, val in save.items(): self._dict[key] = val # Finally, apply any flags to be merged in if parse_flags: self.MergeFlags(parse_flags) ####################################################################### # Utility methods that are primarily for internal use by SCons. # These begin with lower-case letters. ####################################################################### def get_builder(self, name): """Fetch the builder with the specified name from the environment. """ try: return self._dict['BUILDERS'][name] except KeyError: return None def get_CacheDir(self): try: path = self._CacheDir_path except AttributeError: path = SCons.Defaults.DefaultEnvironment()._CacheDir_path try: if path == self._last_CacheDir_path: return self._last_CacheDir except AttributeError: pass cd = SCons.CacheDir.CacheDir(path) self._last_CacheDir_path = path self._last_CacheDir = cd return cd def get_factory(self, factory, default='File'): """Return a factory function for creating Nodes for this construction environment. """ name = default try: is_node = issubclass(factory, SCons.Node.FS.Base) except TypeError: # The specified factory isn't a Node itself--it's # most likely None, or possibly a callable. pass else: if is_node: # The specified factory is a Node (sub)class. Try to # return the FS method that corresponds to the Node's # name--that is, we return self.fs.Dir if they want a Dir, # self.fs.File for a File, etc. try: name = factory.__name__ except AttributeError: pass else: factory = None if not factory: # They passed us None, or we picked up a name from a specified # class, so return the FS method. (Note that we *don't* # use our own self.{Dir,File} methods because that would # cause env.subst() to be called twice on the file name, # interfering with files that have $$ in them.) factory = getattr(self.fs, name) return factory memoizer_counters.append(SCons.Memoize.CountValue('_gsm')) def _gsm(self): try: return self._memo['_gsm'] except KeyError: pass result = {} try: scanners = self._dict['SCANNERS'] except KeyError: pass else: # Reverse the scanner list so that, if multiple scanners # claim they can scan the same suffix, earlier scanners # in the list will overwrite later scanners, so that # the result looks like a "first match" to the user. if not SCons.Util.is_List(scanners): scanners = [scanners] else: scanners = scanners[:] # copy so reverse() doesn't mod original scanners.reverse() for scanner in scanners: for k in scanner.get_skeys(self): if k and self['PLATFORM'] == 'win32': k = string.lower(k) result[k] = scanner self._memo['_gsm'] = result return result def get_scanner(self, skey): """Find the appropriate scanner given a key (usually a file suffix). """ if skey and self['PLATFORM'] == 'win32': skey = string.lower(skey) return self._gsm().get(skey) def scanner_map_delete(self, kw=None): """Delete the cached scanner map (if we need to). """ try: del self._memo['_gsm'] except KeyError: pass def _update(self, dict): """Update an environment's values directly, bypassing the normal checks that occur when users try to set items. """ self._dict.update(dict) def get_src_sig_type(self): try: return self.src_sig_type except AttributeError: t = SCons.Defaults.DefaultEnvironment().src_sig_type self.src_sig_type = t return t def get_tgt_sig_type(self): try: return self.tgt_sig_type except AttributeError: t = SCons.Defaults.DefaultEnvironment().tgt_sig_type self.tgt_sig_type = t return t ####################################################################### # Public methods for manipulating an Environment. These begin with # upper-case letters. The essential characteristic of methods in # this section is that they do *not* have corresponding same-named # global functions. For example, a stand-alone Append() function # makes no sense, because Append() is all about appending values to # an Environment's construction variables. ####################################################################### def Append(self, **kw): """Append values to existing construction variables in an Environment. """ kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): # It would be easier on the eyes to write this using # "continue" statements whenever we finish processing an item, # but Python 1.5.2 apparently doesn't let you use "continue" # within try:-except: blocks, so we have to nest our code. try: orig = self._dict[key] except KeyError: # No existing variable in the environment, so just set # it to the new value. self._dict[key] = val else: try: # Check if the original looks like a dictionary. # If it is, we can't just try adding the value because # dictionaries don't have __add__() methods, and # things like UserList will incorrectly coerce the # original dict to a list (which we don't want). update_dict = orig.update except AttributeError: try: # Most straightforward: just try to add them # together. This will work in most cases, when the # original and new values are of compatible types. self._dict[key] = orig + val except (KeyError, TypeError): try: # Check if the original is a list. add_to_orig = orig.append except AttributeError: # The original isn't a list, but the new # value is (by process of elimination), # so insert the original in the new value # (if there's one to insert) and replace # the variable with it. if orig: val.insert(0, orig) self._dict[key] = val else: # The original is a list, so append the new # value to it (if there's a value to append). if val: add_to_orig(val) else: # The original looks like a dictionary, so update it # based on what we think the value looks like. if SCons.Util.is_List(val): for v in val: orig[v] = None else: try: update_dict(val) except (AttributeError, TypeError, ValueError): if SCons.Util.is_Dict(val): for k, v in val.items(): orig[k] = v else: orig[val] = None self.scanner_map_delete(kw) # allow Dirs and strings beginning with # for top-relative # Note this uses the current env's fs (in self). def _canonicalize(self, path): if not SCons.Util.is_String(path): # typically a Dir path = str(path) if path and path[0] == '#': path = str(self.fs.Dir(path)) return path def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, delete_existing=1): """Append path elements to the path 'name' in the 'ENV' dictionary for this environment. Will only add any particular path once, and will normpath and normcase all paths to help assure this. This can also handle the case where the env variable is a list instead of a string. If delete_existing is 0, a newpath which is already in the path will not be moved to the end (it will be left where it is). """ orig = '' if envname in self._dict and name in self._dict[envname]: orig = self._dict[envname][name] nv = SCons.Util.AppendPath(orig, newpath, sep, delete_existing, canonicalize=self._canonicalize) if envname not in self._dict: self._dict[envname] = {} self._dict[envname][name] = nv def AppendUnique(self, delete_existing=0, **kw): """Append values to existing construction variables in an Environment, if they're not already there. If delete_existing is 1, removes existing values first, so values move to end. """ kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): if SCons.Util.is_List(val): val = _delete_duplicates(val, delete_existing) if key not in self._dict or self._dict[key] in ('', None): self._dict[key] = val elif SCons.Util.is_Dict(self._dict[key]) and \ SCons.Util.is_Dict(val): self._dict[key].update(val) elif SCons.Util.is_List(val): dk = self._dict[key] if not SCons.Util.is_List(dk): dk = [dk] if delete_existing: dk = filter(lambda x, val=val: x not in val, dk) else: val = filter(lambda x, dk=dk: x not in dk, val) self._dict[key] = dk + val else: dk = self._dict[key] if SCons.Util.is_List(dk): # By elimination, val is not a list. Since dk is a # list, wrap val in a list first. if delete_existing: dk = filter(lambda x, val=val: x not in val, dk) self._dict[key] = dk + [val] else: if not val in dk: self._dict[key] = dk + [val] else: if delete_existing: dk = filter(lambda x, val=val: x not in val, dk) self._dict[key] = dk + val self.scanner_map_delete(kw) def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw): """Return a copy of a construction Environment. The copy is like a Python "deep copy"--that is, independent copies are made recursively of each objects--except that a reference is copied when an object is not deep-copyable (like a function). There are no references to any mutable objects in the original Environment. """ clone = copy.copy(self) clone._dict = semi_deepcopy(self._dict) try: cbd = clone._dict['BUILDERS'] except KeyError: pass else: clone._dict['BUILDERS'] = BuilderDict(cbd, clone) # Check the methods added via AddMethod() and re-bind them to # the cloned environment. Only do this if the attribute hasn't # been overwritten by the user explicitly and still points to # the added method. clone.added_methods = [] for mw in self.added_methods: if mw == getattr(self, mw.name): clone.added_methods.append(mw.clone(clone)) clone._memo = {} # Apply passed-in variables before the tools # so the tools can use the new variables kw = copy_non_reserved_keywords(kw) new = {} for key, value in kw.items(): new[key] = SCons.Subst.scons_subst_once(value, self, key) clone.Replace(*(), **new) apply_tools(clone, tools, toolpath) # apply them again in case the tools overwrote them clone.Replace(*(), **new) # Finally, apply any flags to be merged in if parse_flags: clone.MergeFlags(parse_flags) if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone') return clone def Copy(self, *args, **kw): global _warn_copy_deprecated if _warn_copy_deprecated: msg = "The env.Copy() method is deprecated; use the env.Clone() method instead." SCons.Warnings.warn(SCons.Warnings.DeprecatedCopyWarning, msg) _warn_copy_deprecated = False return self.Clone(*args, **kw) def _changed_build(self, dependency, target, prev_ni): if dependency.changed_state(target, prev_ni): return 1 return self.decide_source(dependency, target, prev_ni) def _changed_content(self, dependency, target, prev_ni): return dependency.changed_content(target, prev_ni) def _changed_source(self, dependency, target, prev_ni): target_env = dependency.get_build_env() type = target_env.get_tgt_sig_type() if type == 'source': return target_env.decide_source(dependency, target, prev_ni) else: return target_env.decide_target(dependency, target, prev_ni) def _changed_timestamp_then_content(self, dependency, target, prev_ni): return dependency.changed_timestamp_then_content(target, prev_ni) def _changed_timestamp_newer(self, dependency, target, prev_ni): return dependency.changed_timestamp_newer(target, prev_ni) def _changed_timestamp_match(self, dependency, target, prev_ni): return dependency.changed_timestamp_match(target, prev_ni) def _copy_from_cache(self, src, dst): return self.fs.copy(src, dst) def _copy2_from_cache(self, src, dst): return self.fs.copy2(src, dst) def Decider(self, function): copy_function = self._copy2_from_cache if function in ('MD5', 'content'): if not SCons.Util.md5: raise UserError("MD5 signatures are not available in this version of Python.") function = self._changed_content elif function == 'MD5-timestamp': function = self._changed_timestamp_then_content elif function in ('timestamp-newer', 'make'): function = self._changed_timestamp_newer copy_function = self._copy_from_cache elif function == 'timestamp-match': function = self._changed_timestamp_match elif not callable(function): raise UserError("Unknown Decider value %s" % repr(function)) # We don't use AddMethod because we don't want to turn the # function, which only expects three arguments, into a bound # method, which would add self as an initial, fourth argument. self.decide_target = function self.decide_source = function self.copy_from_cache = copy_function def Detect(self, progs): """Return the first available program in progs. """ if not SCons.Util.is_List(progs): progs = [ progs ] for prog in progs: path = self.WhereIs(prog) if path: return prog return None def Dictionary(self, *args): if not args: return self._dict dlist = map(lambda x, s=self: s._dict[x], args) if len(dlist) == 1: dlist = dlist[0] return dlist def Dump(self, key = None): """ Using the standard Python pretty printer, dump the contents of the scons build environment to stdout. If the key passed in is anything other than None, then that will be used as an index into the build environment dictionary and whatever is found there will be fed into the pretty printer. Note that this key is case sensitive. """ import pprint pp = pprint.PrettyPrinter(indent=2) if key: dict = self.Dictionary(key) else: dict = self.Dictionary() return pp.pformat(dict) def FindIxes(self, paths, prefix, suffix): """ Search a list of paths for something that matches the prefix and suffix. paths - the list of paths or nodes. prefix - construction variable for the prefix. suffix - construction variable for the suffix. """ suffix = self.subst('$'+suffix) prefix = self.subst('$'+prefix) for path in paths: dir,name = os.path.split(str(path)) if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix: return path def ParseConfig(self, command, function=None, unique=1): """ Use the specified function to parse the output of the command in order to modify the current environment. The 'command' can be a string or a list of strings representing a command and its arguments. 'Function' is an optional argument that takes the environment, the output of the command, and the unique flag. If no function is specified, MergeFlags, which treats the output as the result of a typical 'X-config' command (i.e. gtk-config), will merge the output into the appropriate variables. """ if function is None: def parse_conf(env, cmd, unique=unique): return env.MergeFlags(cmd, unique) function = parse_conf if SCons.Util.is_List(command): command = string.join(command) command = self.subst(command) return function(self, self.backtick(command)) def ParseDepends(self, filename, must_exist=None, only_one=0): """ Parse a mkdep-style file for explicit dependencies. This is completely abusable, and should be unnecessary in the "normal" case of proper SCons configuration, but it may help make the transition from a Make hierarchy easier for some people to swallow. It can also be genuinely useful when using a tool that can write a .d file, but for which writing a scanner would be too complicated. """ filename = self.subst(filename) try: fp = open(filename, 'r') except IOError: if must_exist: raise return lines = SCons.Util.LogicalLines(fp).readlines() lines = filter(lambda l: l[0] != '#', lines) tdlist = [] for line in lines: try: target, depends = string.split(line, ':', 1) except (AttributeError, TypeError, ValueError): # Python 1.5.2 throws TypeError if line isn't a string, # Python 2.x throws AttributeError because it tries # to call line.split(). Either can throw ValueError # if the line doesn't split into two or more elements. pass else: tdlist.append((string.split(target), string.split(depends))) if only_one: targets = reduce(lambda x, y: x+y, map(lambda p: p[0], tdlist)) if len(targets) > 1: raise SCons.Errors.UserError("More than one dependency target found in `%s': %s" % (filename, targets)) for target, depends in tdlist: self.Depends(target, depends) def Platform(self, platform): platform = self.subst(platform) return SCons.Platform.Platform(platform)(self) def Prepend(self, **kw): """Prepend values to existing construction variables in an Environment. """ kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): # It would be easier on the eyes to write this using # "continue" statements whenever we finish processing an item, # but Python 1.5.2 apparently doesn't let you use "continue" # within try:-except: blocks, so we have to nest our code. try: orig = self._dict[key] except KeyError: # No existing variable in the environment, so just set # it to the new value. self._dict[key] = val else: try: # Check if the original looks like a dictionary. # If it is, we can't just try adding the value because # dictionaries don't have __add__() methods, and # things like UserList will incorrectly coerce the # original dict to a list (which we don't want). update_dict = orig.update except AttributeError: try: # Most straightforward: just try to add them # together. This will work in most cases, when the # original and new values are of compatible types. self._dict[key] = val + orig except (KeyError, TypeError): try: # Check if the added value is a list. add_to_val = val.append except AttributeError: # The added value isn't a list, but the # original is (by process of elimination), # so insert the the new value in the original # (if there's one to insert). if val: orig.insert(0, val) else: # The added value is a list, so append # the original to it (if there's a value # to append). if orig: add_to_val(orig) self._dict[key] = val else: # The original looks like a dictionary, so update it # based on what we think the value looks like. if SCons.Util.is_List(val): for v in val: orig[v] = None else: try: update_dict(val) except (AttributeError, TypeError, ValueError): if SCons.Util.is_Dict(val): for k, v in val.items(): orig[k] = v else: orig[val] = None self.scanner_map_delete(kw) def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, delete_existing=1): """Prepend path elements to the path 'name' in the 'ENV' dictionary for this environment. Will only add any particular path once, and will normpath and normcase all paths to help assure this. This can also handle the case where the env variable is a list instead of a string. If delete_existing is 0, a newpath which is already in the path will not be moved to the front (it will be left where it is). """ orig = '' if envname in self._dict and name in self._dict[envname]: orig = self._dict[envname][name] nv = SCons.Util.PrependPath(orig, newpath, sep, delete_existing, canonicalize=self._canonicalize) if envname not in self._dict: self._dict[envname] = {} self._dict[envname][name] = nv def PrependUnique(self, delete_existing=0, **kw): """Prepend values to existing construction variables in an Environment, if they're not already there. If delete_existing is 1, removes existing values first, so values move to front. """ kw = copy_non_reserved_keywords(kw) for key, val in kw.items(): if SCons.Util.is_List(val): val = _delete_duplicates(val, not delete_existing) if key not in self._dict or self._dict[key] in ('', None): self._dict[key] = val elif SCons.Util.is_Dict(self._dict[key]) and \ SCons.Util.is_Dict(val): self._dict[key].update(val) elif SCons.Util.is_List(val): dk = self._dict[key] if not SCons.Util.is_List(dk): dk = [dk] if delete_existing: dk = filter(lambda x, val=val: x not in val, dk) else: val = filter(lambda x, dk=dk: x not in dk, val) self._dict[key] = val + dk else: dk = self._dict[key] if SCons.Util.is_List(dk): # By elimination, val is not a list. Since dk is a # list, wrap val in a list first. if delete_existing: dk = filter(lambda x, val=val: x not in val, dk) self._dict[key] = [val] + dk else: if not val in dk: self._dict[key] = [val] + dk else: if delete_existing: dk = filter(lambda x, val=val: x not in val, dk) self._dict[key] = val + dk self.scanner_map_delete(kw) def Replace(self, **kw): """Replace existing construction variables in an Environment with new construction variables and/or values. """ try: kwbd = kw['BUILDERS'] except KeyError: pass else: kwbd = semi_deepcopy(kwbd) del kw['BUILDERS'] self.__setitem__('BUILDERS', kwbd) kw = copy_non_reserved_keywords(kw) self._update(semi_deepcopy(kw)) self.scanner_map_delete(kw) def ReplaceIxes(self, path, old_prefix, old_suffix, new_prefix, new_suffix): """ Replace old_prefix with new_prefix and old_suffix with new_suffix. env - Environment used to interpolate variables. path - the path that will be modified. old_prefix - construction variable for the old prefix. old_suffix - construction variable for the old suffix. new_prefix - construction variable for the new prefix. new_suffix - construction variable for the new suffix. """ old_prefix = self.subst('$'+old_prefix) old_suffix = self.subst('$'+old_suffix) new_prefix = self.subst('$'+new_prefix) new_suffix = self.subst('$'+new_suffix) dir,name = os.path.split(str(path)) if name[:len(old_prefix)] == old_prefix: name = name[len(old_prefix):] if name[-len(old_suffix):] == old_suffix: name = name[:-len(old_suffix)] return os.path.join(dir, new_prefix+name+new_suffix) def SetDefault(self, **kw): for k in kw.keys(): if k in self._dict: del kw[k] self.Replace(*(), **kw) def _find_toolpath_dir(self, tp): return self.fs.Dir(self.subst(tp)).srcnode().abspath def Tool(self, tool, toolpath=None, **kw): if SCons.Util.is_String(tool): tool = self.subst(tool) if toolpath is None: toolpath = self.get('toolpath', []) toolpath = map(self._find_toolpath_dir, toolpath) tool = SCons.Tool.Tool(*(tool, toolpath), **kw) tool(self) def WhereIs(self, prog, path=None, pathext=None, reject=[]): """Find prog in the path. """ if path is None: try: path = self['ENV']['PATH'] except KeyError: pass elif SCons.Util.is_String(path): path = self.subst(path) if pathext is None: try: pathext = self['ENV']['PATHEXT'] except KeyError: pass elif SCons.Util.is_String(pathext): pathext = self.subst(pathext) prog = self.subst(prog) path = SCons.Util.WhereIs(prog, path, pathext, reject) if path: return path return None ####################################################################### # Public methods for doing real "SCons stuff" (manipulating # dependencies, setting attributes on targets, etc.). These begin # with upper-case letters. The essential characteristic of methods # in this section is that they all *should* have corresponding # same-named global functions. ####################################################################### def Action(self, *args, **kw): def subst_string(a, self=self): if SCons.Util.is_String(a): a = self.subst(a) return a nargs = map(subst_string, args) nkw = self.subst_kw(kw) return SCons.Action.Action(*nargs, **nkw) def AddPreAction(self, files, action): nodes = self.arg2nodes(files, self.fs.Entry) action = SCons.Action.Action(action) uniq = {} for executor in map(lambda n: n.get_executor(), nodes): uniq[executor] = 1 for executor in uniq.keys(): executor.add_pre_action(action) return nodes def AddPostAction(self, files, action): nodes = self.arg2nodes(files, self.fs.Entry) action = SCons.Action.Action(action) uniq = {} for executor in map(lambda n: n.get_executor(), nodes): uniq[executor] = 1 for executor in uniq.keys(): executor.add_post_action(action) return nodes def Alias(self, target, source=[], action=None, **kw): tlist = self.arg2nodes(target, self.ans.Alias) if not SCons.Util.is_List(source): source = [source] source = filter(None, source) if not action: if not source: # There are no source files and no action, so just # return a target list of classic Alias Nodes, without # any builder. The externally visible effect is that # this will make the wrapping Script.BuildTask class # say that there's "Nothing to be done" for this Alias, # instead of that it's "up to date." return tlist # No action, but there are sources. Re-call all the target # builders to add the sources to each target. result = [] for t in tlist: bld = t.get_builder(AliasBuilder) result.extend(bld(self, t, source)) return result nkw = self.subst_kw(kw) nkw.update({ 'action' : SCons.Action.Action(action), 'source_factory' : self.fs.Entry, 'multi' : 1, 'is_explicit' : None, }) bld = SCons.Builder.Builder(*(), **nkw) # Apply the Builder separately to each target so that the Aliases # stay separate. If we did one "normal" Builder call with the # whole target list, then all of the target Aliases would be # associated under a single Executor. result = [] for t in tlist: # Calling the convert() method will cause a new Executor to be # created from scratch, so we have to explicitly initialize # it with the target's existing sources, plus our new ones, # so nothing gets lost. b = t.get_builder() if b is None or b is AliasBuilder: b = bld else: nkw['action'] = b.action + action b = SCons.Builder.Builder(*(), **nkw) t.convert() result.extend(b(self, t, t.sources + source)) return result def AlwaysBuild(self, *targets): tlist = [] for t in targets: tlist.extend(self.arg2nodes(t, self.fs.Entry)) for t in tlist: t.set_always_build() return tlist def BuildDir(self, *args, **kw): if 'build_dir' in kw: kw['variant_dir'] = kw['build_dir'] del kw['build_dir'] return self.VariantDir(*args, **kw) def Builder(self, **kw): nkw = self.subst_kw(kw) return SCons.Builder.Builder(*[], **nkw) def CacheDir(self, path): import SCons.CacheDir if path is not None: path = self.subst(path) self._CacheDir_path = path def Clean(self, targets, files): global CleanTargets tlist = self.arg2nodes(targets, self.fs.Entry) flist = self.arg2nodes(files, self.fs.Entry) for t in tlist: try: CleanTargets[t].extend(flist) except KeyError: CleanTargets[t] = flist def Configure(self, *args, **kw): nargs = [self] if args: nargs = nargs + self.subst_list(args)[0] nkw = self.subst_kw(kw) nkw['_depth'] = kw.get('_depth', 0) + 1 try: nkw['custom_tests'] = self.subst_kw(nkw['custom_tests']) except KeyError: pass return SCons.SConf.SConf(*nargs, **nkw) def Command(self, target, source, action, **kw): """Builds the supplied target files from the supplied source files using the supplied action. Action may be any type that the Builder constructor will accept for an action.""" bkw = { 'action' : action, 'target_factory' : self.fs.Entry, 'source_factory' : self.fs.Entry, } try: bkw['source_scanner'] = kw['source_scanner'] except KeyError: pass else: del kw['source_scanner'] bld = SCons.Builder.Builder(*(), **bkw) return bld(*(self, target, source), **kw) def Depends(self, target, dependency): """Explicity specify that 'target's depend on 'dependency'.""" tlist = self.arg2nodes(target, self.fs.Entry) dlist = self.arg2nodes(dependency, self.fs.Entry) for t in tlist: t.add_dependency(dlist) return tlist def Dir(self, name, *args, **kw): """ """ s = self.subst(name) if SCons.Util.is_Sequence(s): result=[] for e in s: result.append(self.fs.Dir(*(e,) + args, **kw)) return result return self.fs.Dir(*(s,) + args, **kw) def NoClean(self, *targets): """Tags a target so that it will not be cleaned by -c""" tlist = [] for t in targets: tlist.extend(self.arg2nodes(t, self.fs.Entry)) for t in tlist: t.set_noclean() return tlist def NoCache(self, *targets): """Tags a target so that it will not be cached""" tlist = [] for t in targets: tlist.extend(self.arg2nodes(t, self.fs.Entry)) for t in tlist: t.set_nocache() return tlist def Entry(self, name, *args, **kw): """ """ s = self.subst(name) if SCons.Util.is_Sequence(s): result=[] for e in s: result.append(self.fs.Entry(*(e,) + args, **kw)) return result return self.fs.Entry(*(s,) + args, **kw) def Environment(self, **kw): return SCons.Environment.Environment(*[], **self.subst_kw(kw)) def Execute(self, action, *args, **kw): """Directly execute an action through an Environment """ action = self.Action(*(action,) + args, **kw) result = action([], [], self) if isinstance(result, SCons.Errors.BuildError): errstr = result.errstr if result.filename: errstr = result.filename + ': ' + errstr sys.stderr.write("scons: *** %s\n" % errstr) return result.status else: return result def File(self, name, *args, **kw): """ """ s = self.subst(name) if SCons.Util.is_Sequence(s): result=[] for e in s: result.append(self.fs.File(*(e,) + args, **kw)) return result return self.fs.File(*(s,) + args, **kw) def FindFile(self, file, dirs): file = self.subst(file) nodes = self.arg2nodes(dirs, self.fs.Dir) return SCons.Node.FS.find_file(file, tuple(nodes)) def Flatten(self, sequence): return SCons.Util.flatten(sequence) def GetBuildPath(self, files): result = map(str, self.arg2nodes(files, self.fs.Entry)) if SCons.Util.is_List(files): return result else: return result[0] def Glob(self, pattern, ondisk=True, source=False, strings=False): return self.fs.Glob(self.subst(pattern), ondisk, source, strings) def Ignore(self, target, dependency): """Ignore a dependency.""" tlist = self.arg2nodes(target, self.fs.Entry) dlist = self.arg2nodes(dependency, self.fs.Entry) for t in tlist: t.add_ignore(dlist) return tlist def Literal(self, string): return SCons.Subst.Literal(string) def Local(self, *targets): ret = [] for targ in targets: if isinstance(targ, SCons.Node.Node): targ.set_local() ret.append(targ) else: for t in self.arg2nodes(targ, self.fs.Entry): t.set_local() ret.append(t) return ret def Precious(self, *targets): tlist = [] for t in targets: tlist.extend(self.arg2nodes(t, self.fs.Entry)) for t in tlist: t.set_precious() return tlist def Repository(self, *dirs, **kw): dirs = self.arg2nodes(list(dirs), self.fs.Dir) self.fs.Repository(*dirs, **kw) def Requires(self, target, prerequisite): """Specify that 'prerequisite' must be built before 'target', (but 'target' does not actually depend on 'prerequisite' and need not be rebuilt if it changes).""" tlist = self.arg2nodes(target, self.fs.Entry) plist = self.arg2nodes(prerequisite, self.fs.Entry) for t in tlist: t.add_prerequisite(plist) return tlist def Scanner(self, *args, **kw): nargs = [] for arg in args: if SCons.Util.is_String(arg): arg = self.subst(arg) nargs.append(arg) nkw = self.subst_kw(kw) return SCons.Scanner.Base(*nargs, **nkw) def SConsignFile(self, name=".sconsign", dbm_module=None): if name is not None: name = self.subst(name) if not os.path.isabs(name): name = os.path.join(str(self.fs.SConstruct_dir), name) if name: name = os.path.normpath(name) sconsign_dir = os.path.dirname(name) if sconsign_dir and not os.path.exists(sconsign_dir): self.Execute(SCons.Defaults.Mkdir(sconsign_dir)) SCons.SConsign.File(name, dbm_module) def SideEffect(self, side_effect, target): """Tell scons that side_effects are built as side effects of building targets.""" side_effects = self.arg2nodes(side_effect, self.fs.Entry) targets = self.arg2nodes(target, self.fs.Entry) for side_effect in side_effects: if side_effect.multiple_side_effect_has_builder(): raise SCons.Errors.UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect)) side_effect.add_source(targets) side_effect.side_effect = 1 self.Precious(side_effect) for target in targets: target.side_effects.append(side_effect) return side_effects def SourceCode(self, entry, builder): """Arrange for a source code builder for (part of) a tree.""" entries = self.arg2nodes(entry, self.fs.Entry) for entry in entries: entry.set_src_builder(builder) return entries def SourceSignatures(self, type): global _warn_source_signatures_deprecated if _warn_source_signatures_deprecated: msg = "The env.SourceSignatures() method is deprecated;\n" + \ "\tconvert your build to use the env.Decider() method instead." SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceSignaturesWarning, msg) _warn_source_signatures_deprecated = False type = self.subst(type) self.src_sig_type = type if type == 'MD5': if not SCons.Util.md5: raise UserError("MD5 signatures are not available in this version of Python.") self.decide_source = self._changed_content elif type == 'timestamp': self.decide_source = self._changed_timestamp_match else: raise UserError("Unknown source signature type '%s'" % type) def Split(self, arg): """This function converts a string or list into a list of strings or Nodes. This makes things easier for users by allowing files to be specified as a white-space separated list to be split. The input rules are: - A single string containing names separated by spaces. These will be split apart at the spaces. - A single Node instance - A list containing either strings or Node instances. Any strings in the list are not split at spaces. In all cases, the function returns a list of Nodes and strings.""" if SCons.Util.is_List(arg): return map(self.subst, arg) elif SCons.Util.is_String(arg): return string.split(self.subst(arg)) else: return [self.subst(arg)] def TargetSignatures(self, type): global _warn_target_signatures_deprecated if _warn_target_signatures_deprecated: msg = "The env.TargetSignatures() method is deprecated;\n" + \ "\tconvert your build to use the env.Decider() method instead." SCons.Warnings.warn(SCons.Warnings.DeprecatedTargetSignaturesWarning, msg) _warn_target_signatures_deprecated = False type = self.subst(type) self.tgt_sig_type = type if type in ('MD5', 'content'): if not SCons.Util.md5: raise UserError("MD5 signatures are not available in this version of Python.") self.decide_target = self._changed_content elif type == 'timestamp': self.decide_target = self._changed_timestamp_match elif type == 'build': self.decide_target = self._changed_build elif type == 'source': self.decide_target = self._changed_source else: raise UserError("Unknown target signature type '%s'"%type) def Value(self, value, built_value=None): """ """ return SCons.Node.Python.Value(value, built_value) def VariantDir(self, variant_dir, src_dir, duplicate=1): variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0] src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0] self.fs.VariantDir(variant_dir, src_dir, duplicate) def FindSourceFiles(self, node='.'): """ returns a list of all source files. """ node = self.arg2nodes(node, self.fs.Entry)[0] sources = [] # Uncomment this and get rid of the global definition when we # drop support for pre-2.2 Python versions. #def build_source(ss, result): # for s in ss: # if isinstance(s, SCons.Node.FS.Dir): # build_source(s.all_children(), result) # elif s.has_builder(): # build_source(s.sources, result) # elif isinstance(s.disambiguate(), SCons.Node.FS.File): # result.append(s) build_source(node.all_children(), sources) # THIS CODE APPEARS TO HAVE NO EFFECT # # get the final srcnode for all nodes, this means stripping any # # attached build node by calling the srcnode function # for file in sources: # srcnode = file.srcnode() # while srcnode != file.srcnode(): # srcnode = file.srcnode() # remove duplicates return list(set(sources)) def FindInstalledFiles(self): """ returns the list of all targets of the Install and InstallAs Builder. """ from SCons.Tool import install if install._UNIQUE_INSTALLED_FILES is None: install._UNIQUE_INSTALLED_FILES = SCons.Util.uniquer_hashables(install._INSTALLED_FILES) return install._UNIQUE_INSTALLED_FILES class OverrideEnvironment(Base): """A proxy that overrides variables in a wrapped construction environment by returning values from an overrides dictionary in preference to values from the underlying subject environment. This is a lightweight (I hope) proxy that passes through most use of attributes to the underlying Environment.Base class, but has just enough additional methods defined to act like a real construction environment with overridden values. It can wrap either a Base construction environment, or another OverrideEnvironment, which can in turn nest arbitrary OverrideEnvironments... Note that we do *not* call the underlying base class (SubsitutionEnvironment) initialization, because we get most of those from proxying the attributes of the subject construction environment. But because we subclass SubstitutionEnvironment, this class also has inherited arg2nodes() and subst*() methods; those methods can't be proxied because they need *this* object's methods to fetch the values from the overrides dictionary. """ def __init__(self, subject, overrides={}): if __debug__: logInstanceCreation(self, 'Environment.OverrideEnvironment') self.__dict__['__subject'] = subject self.__dict__['overrides'] = overrides # Methods that make this class act like a proxy. def __getattr__(self, name): return getattr(self.__dict__['__subject'], name) def __setattr__(self, name, value): setattr(self.__dict__['__subject'], name, value) # Methods that make this class act like a dictionary. def __getitem__(self, key): try: return self.__dict__['overrides'][key] except KeyError: return self.__dict__['__subject'].__getitem__(key) def __setitem__(self, key, value): if not is_valid_construction_var(key): raise SCons.Errors.UserError("Illegal construction variable `%s'" % key) self.__dict__['overrides'][key] = value def __delitem__(self, key): try: del self.__dict__['overrides'][key] except KeyError: deleted = 0 else: deleted = 1 try: result = self.__dict__['__subject'].__delitem__(key) except KeyError: if not deleted: raise result = None return result def get(self, key, default=None): """Emulates the get() method of dictionaries.""" try: return self.__dict__['overrides'][key] except KeyError: return self.__dict__['__subject'].get(key, default) def has_key(self, key): try: self.__dict__['overrides'][key] return 1 except KeyError: return key in self.__dict__['__subject'] def __contains__(self, key): if self.__dict__['overrides'].__contains__(key): return 1 return self.__dict__['__subject'].__contains__(key) def Dictionary(self): """Emulates the items() method of dictionaries.""" d = self.__dict__['__subject'].Dictionary().copy() d.update(self.__dict__['overrides']) return d def items(self): """Emulates the items() method of dictionaries.""" return self.Dictionary().items() # Overridden private construction environment methods. def _update(self, dict): """Update an environment's values directly, bypassing the normal checks that occur when users try to set items. """ self.__dict__['overrides'].update(dict) def gvars(self): return self.__dict__['__subject'].gvars() def lvars(self): lvars = self.__dict__['__subject'].lvars() lvars.update(self.__dict__['overrides']) return lvars # Overridden public construction environment methods. def Replace(self, **kw): kw = copy_non_reserved_keywords(kw) self.__dict__['overrides'].update(semi_deepcopy(kw)) # The entry point that will be used by the external world # to refer to a construction environment. This allows the wrapper # interface to extend a construction environment for its own purposes # by subclassing SCons.Environment.Base and then assigning the # class to SCons.Environment.Environment. Environment = Base # An entry point for returning a proxy subclass instance that overrides # the subst*() methods so they don't actually perform construction # variable substitution. This is specifically intended to be the shim # layer in between global function calls (which don't want construction # variable substitution) and the DefaultEnvironment() (which would # substitute variables if left to its own devices).""" # # We have to wrap this in a function that allows us to delay definition of # the class until it's necessary, so that when it subclasses Environment # it will pick up whatever Environment subclass the wrapper interface # might have assigned to SCons.Environment.Environment. def NoSubstitutionProxy(subject): class _NoSubstitutionProxy(Environment): def __init__(self, subject): self.__dict__['__subject'] = subject def __getattr__(self, name): return getattr(self.__dict__['__subject'], name) def __setattr__(self, name, value): return setattr(self.__dict__['__subject'], name, value) def raw_to_mode(self, dict): try: raw = dict['raw'] except KeyError: pass else: del dict['raw'] dict['mode'] = raw def subst(self, string, *args, **kwargs): return string def subst_kw(self, kw, *args, **kwargs): return kw def subst_list(self, string, *args, **kwargs): nargs = (string, self,) + args nkw = kwargs.copy() nkw['gvars'] = {} self.raw_to_mode(nkw) return SCons.Subst.scons_subst_list(*nargs, **nkw) def subst_target_source(self, string, *args, **kwargs): nargs = (string, self,) + args nkw = kwargs.copy() nkw['gvars'] = {} self.raw_to_mode(nkw) return SCons.Subst.scons_subst(*nargs, **nkw) return _NoSubstitutionProxy(subject) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/0000755000175000017500000000000013606712377020755 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/__init__.py0000644000175000017500000003447413606712377023102 0ustar kurtkurt"""SCons.Scanner The Scanner package for the SCons software construction utility. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/__init__.py 4369 2009/09/19 15:58:29 scons" import re import string import SCons.Node.FS import SCons.Util class _Null: pass # This is used instead of None as a default argument value so None can be # used as an actual argument value. _null = _Null def Scanner(function, *args, **kw): """ Public interface factory function for creating different types of Scanners based on the different types of "functions" that may be supplied. TODO: Deprecate this some day. We've moved the functionality inside the Base class and really don't need this factory function any more. It was, however, used by some of our Tool modules, so the call probably ended up in various people's custom modules patterned on SCons code. """ if SCons.Util.is_Dict(function): return Selector(*(function,) + args, **kw) else: return Base(*(function,) + args, **kw) class FindPathDirs: """A class to bind a specific *PATH variable name to a function that will return all of the *path directories.""" def __init__(self, variable): self.variable = variable def __call__(self, env, dir=None, target=None, source=None, argument=None): import SCons.PathList try: path = env[self.variable] except KeyError: return () dir = dir or env.fs._cwd path = SCons.PathList.PathList(path).subst_path(env, target, source) return tuple(dir.Rfindalldirs(path)) class Base: """ The base class for dependency scanners. This implements straightforward, single-pass scanning of a single file. """ def __init__(self, function, name = "NONE", argument = _null, skeys = _null, path_function = None, node_class = SCons.Node.FS.Entry, node_factory = None, scan_check = None, recursive = None): """ Construct a new scanner object given a scanner function. 'function' - a scanner function taking two or three arguments and returning a list of strings. 'name' - a name for identifying this scanner object. 'argument' - an optional argument that, if specified, will be passed to both the scanner function and the path_function. 'skeys' - an optional list argument that can be used to determine which scanner should be used for a given Node. In the case of File nodes, for example, the 'skeys' would be file suffixes. 'path_function' - a function that takes four or five arguments (a construction environment, Node for the directory containing the SConscript file that defined the primary target, list of target nodes, list of source nodes, and optional argument for this instance) and returns a tuple of the directories that can be searched for implicit dependency files. May also return a callable() which is called with no args and returns the tuple (supporting Bindable class). 'node_class' - the class of Nodes which this scan will return. If node_class is None, then this scanner will not enforce any Node conversion and will return the raw results from the underlying scanner function. 'node_factory' - the factory function to be called to translate the raw results returned by the scanner function into the expected node_class objects. 'scan_check' - a function to be called to first check whether this node really needs to be scanned. 'recursive' - specifies that this scanner should be invoked recursively on all of the implicit dependencies it returns (the canonical example being #include lines in C source files). May be a callable, which will be called to filter the list of nodes found to select a subset for recursive scanning (the canonical example being only recursively scanning subdirectories within a directory). The scanner function's first argument will be a Node that should be scanned for dependencies, the second argument will be an Environment object, the third argument will be the tuple of paths returned by the path_function, and the fourth argument will be the value passed into 'argument', and the returned list should contain the Nodes for all the direct dependencies of the file. Examples: s = Scanner(my_scanner_function) s = Scanner(function = my_scanner_function) s = Scanner(function = my_scanner_function, argument = 'foo') """ # Note: this class could easily work with scanner functions that take # something other than a filename as an argument (e.g. a database # node) and a dependencies list that aren't file names. All that # would need to be changed is the documentation. self.function = function self.path_function = path_function self.name = name self.argument = argument if skeys is _null: if SCons.Util.is_Dict(function): skeys = function.keys() else: skeys = [] self.skeys = skeys self.node_class = node_class self.node_factory = node_factory self.scan_check = scan_check if callable(recursive): self.recurse_nodes = recursive elif recursive: self.recurse_nodes = self._recurse_all_nodes else: self.recurse_nodes = self._recurse_no_nodes def path(self, env, dir=None, target=None, source=None): if not self.path_function: return () if not self.argument is _null: return self.path_function(env, dir, target, source, self.argument) else: return self.path_function(env, dir, target, source) def __call__(self, node, env, path = ()): """ This method scans a single object. 'node' is the node that will be passed to the scanner function, and 'env' is the environment that will be passed to the scanner function. A list of direct dependency nodes for the specified node will be returned. """ if self.scan_check and not self.scan_check(node, env): return [] self = self.select(node) if not self.argument is _null: list = self.function(node, env, path, self.argument) else: list = self.function(node, env, path) kw = {} if hasattr(node, 'dir'): kw['directory'] = node.dir node_factory = env.get_factory(self.node_factory) nodes = [] for l in list: if self.node_class and not isinstance(l, self.node_class): l = node_factory(*(l,), **kw) nodes.append(l) return nodes def __cmp__(self, other): try: return cmp(self.__dict__, other.__dict__) except AttributeError: # other probably doesn't have a __dict__ return cmp(self.__dict__, other) def __hash__(self): return id(self) def __str__(self): return self.name def add_skey(self, skey): """Add a skey to the list of skeys""" self.skeys.append(skey) def get_skeys(self, env=None): if env and SCons.Util.is_String(self.skeys): return env.subst_list(self.skeys)[0] return self.skeys def select(self, node): if SCons.Util.is_Dict(self.function): key = node.scanner_key() try: return self.function[key] except KeyError: return None else: return self def _recurse_all_nodes(self, nodes): return nodes def _recurse_no_nodes(self, nodes): return [] recurse_nodes = _recurse_no_nodes def add_scanner(self, skey, scanner): self.function[skey] = scanner self.add_skey(skey) class Selector(Base): """ A class for selecting a more specific scanner based on the scanner_key() (suffix) for a specific Node. TODO: This functionality has been moved into the inner workings of the Base class, and this class will be deprecated at some point. (It was never exposed directly as part of the public interface, although it is used by the Scanner() factory function that was used by various Tool modules and therefore was likely a template for custom modules that may be out there.) """ def __init__(self, dict, *args, **kw): Base.__init__(*(self, None,)+args, **kw) self.dict = dict self.skeys = dict.keys() def __call__(self, node, env, path = ()): return self.select(node)(node, env, path) def select(self, node): try: return self.dict[node.scanner_key()] except KeyError: return None def add_scanner(self, skey, scanner): self.dict[skey] = scanner self.add_skey(skey) class Current(Base): """ A class for scanning files that are source files (have no builder) or are derived files and are current (which implies that they exist, either locally or in a repository). """ def __init__(self, *args, **kw): def current_check(node, env): return not node.has_builder() or node.is_up_to_date() kw['scan_check'] = current_check Base.__init__(*(self,) + args, **kw) class Classic(Current): """ A Scanner subclass to contain the common logic for classic CPP-style include scanning, but which can be customized to use different regular expressions to find the includes. Note that in order for this to work "out of the box" (without overriding the find_include() and sort_key() methods), the regular expression passed to the constructor must return the name of the include file in group 0. """ def __init__(self, name, suffixes, path_variable, regex, *args, **kw): self.cre = re.compile(regex, re.M) def _scan(node, env, path=(), self=self): node = node.rfile() if not node.exists(): return [] return self.scan(node, path) kw['function'] = _scan kw['path_function'] = FindPathDirs(path_variable) kw['recursive'] = 1 kw['skeys'] = suffixes kw['name'] = name Current.__init__(*(self,) + args, **kw) def find_include(self, include, source_dir, path): n = SCons.Node.FS.find_file(include, (source_dir,) + tuple(path)) return n, include def sort_key(self, include): return SCons.Node.FS._my_normcase(include) def find_include_names(self, node): return self.cre.findall(node.get_text_contents()) def scan(self, node, path=()): # cache the includes list in node so we only scan it once: if node.includes is not None: includes = node.includes else: includes = self.find_include_names (node) # Intern the names of the include files. Saves some memory # if the same header is included many times. node.includes = map(SCons.Util.silent_intern, includes) # This is a hand-coded DSU (decorate-sort-undecorate, or # Schwartzian transform) pattern. The sort key is the raw name # of the file as specifed on the #include line (including the # " or <, since that may affect what file is found), which lets # us keep the sort order constant regardless of whether the file # is actually found in a Repository or locally. nodes = [] source_dir = node.get_dir() if callable(path): path = path() for include in includes: n, i = self.find_include(include, source_dir, path) if n is None: SCons.Warnings.warn(SCons.Warnings.DependencyWarning, "No dependency generated for file: %s (included from: %s) -- file not found" % (i, node)) else: sortkey = self.sort_key(include) nodes.append((sortkey, n)) nodes.sort() nodes = map(lambda pair: pair[1], nodes) return nodes class ClassicCPP(Classic): """ A Classic Scanner subclass which takes into account the type of bracketing used to include the file, and uses classic CPP rules for searching for the files based on the bracketing. Note that in order for this to work, the regular expression passed to the constructor must return the leading bracket in group 0, and the contained filename in group 1. """ def find_include(self, include, source_dir, path): if include[0] == '"': paths = (source_dir,) + tuple(path) else: paths = tuple(path) + (source_dir,) n = SCons.Node.FS.find_file(include[1], paths) i = SCons.Util.silent_intern(include[1]) return n, i def sort_key(self, include): return SCons.Node.FS._my_normcase(string.join(include)) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/LaTeX.py0000644000175000017500000003443113606712377022311 0ustar kurtkurt"""SCons.Scanner.LaTeX This module implements the dependency scanner for LaTeX code. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/LaTeX.py 4369 2009/09/19 15:58:29 scons" import os.path import string import re import SCons.Scanner import SCons.Util # list of graphics file extensions for TeX and LaTeX TexGraphics = ['.eps', '.ps'] LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif'] # Used as a return value of modify_env_var if the variable is not set. class _Null: pass _null = _Null # The user specifies the paths in env[variable], similar to other builders. # They may be relative and must be converted to absolute, as expected # by LaTeX and Co. The environment may already have some paths in # env['ENV'][var]. These paths are honored, but the env[var] paths have # higher precedence. All changes are un-done on exit. def modify_env_var(env, var, abspath): try: save = env['ENV'][var] except KeyError: save = _null env.PrependENVPath(var, abspath) try: if SCons.Util.is_List(env[var]): #TODO(1.5) #env.PrependENVPath(var, [os.path.abspath(str(p)) for p in env[var]]) env.PrependENVPath(var, map(lambda p: os.path.abspath(str(p)), env[var])) else: # Split at os.pathsep to convert into absolute path #TODO(1.5) env.PrependENVPath(var, [os.path.abspath(p) for p in str(env[var]).split(os.pathsep)]) env.PrependENVPath(var, map(lambda p: os.path.abspath(p), string.split(str(env[var]), os.pathsep))) except KeyError: pass # Convert into a string explicitly to append ":" (without which it won't search system # paths as well). The problem is that env.AppendENVPath(var, ":") # does not work, refuses to append ":" (os.pathsep). if SCons.Util.is_List(env['ENV'][var]): # TODO(1.5) #env['ENV'][var] = os.pathsep.join(env['ENV'][var]) env['ENV'][var] = string.join(env['ENV'][var], os.pathsep) # Append the trailing os.pathsep character here to catch the case with no env[var] env['ENV'][var] = env['ENV'][var] + os.pathsep return save class FindENVPathDirs: """A class to bind a specific *PATH variable name to a function that will return all of the *path directories.""" def __init__(self, variable): self.variable = variable def __call__(self, env, dir=None, target=None, source=None, argument=None): import SCons.PathList try: path = env['ENV'][self.variable] except KeyError: return () dir = dir or env.fs._cwd path = SCons.PathList.PathList(path).subst_path(env, target, source) return tuple(dir.Rfindalldirs(path)) def LaTeXScanner(): """Return a prototype Scanner instance for scanning LaTeX source files when built with latex. """ ds = LaTeX(name = "LaTeXScanner", suffixes = '$LATEXSUFFIXES', # in the search order, see below in LaTeX class docstring graphics_extensions = TexGraphics, recursive = 0) return ds def PDFLaTeXScanner(): """Return a prototype Scanner instance for scanning LaTeX source files when built with pdflatex. """ ds = LaTeX(name = "PDFLaTeXScanner", suffixes = '$LATEXSUFFIXES', # in the search order, see below in LaTeX class docstring graphics_extensions = LatexGraphics, recursive = 0) return ds class LaTeX(SCons.Scanner.Base): """Class for scanning LaTeX files for included files. Unlike most scanners, which use regular expressions that just return the included file name, this returns a tuple consisting of the keyword for the inclusion ("include", "includegraphics", "input", or "bibliography"), and then the file name itself. Based on a quick look at LaTeX documentation, it seems that we should append .tex suffix for the "include" keywords, append .tex if there is no extension for the "input" keyword, and need to add .bib for the "bibliography" keyword that does not accept extensions by itself. Finally, if there is no extension for an "includegraphics" keyword latex will append .ps or .eps to find the file, while pdftex may use .pdf, .jpg, .tif, .mps, or .png. The actual subset and search order may be altered by DeclareGraphicsExtensions command. This complication is ignored. The default order corresponds to experimentation with teTeX $ latex --version pdfeTeX 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.4 The order is: ['.eps', '.ps'] for latex ['.png', '.pdf', '.jpg', '.tif']. Another difference is that the search path is determined by the type of the file being searched: env['TEXINPUTS'] for "input" and "include" keywords env['TEXINPUTS'] for "includegraphics" keyword env['BIBINPUTS'] for "bibliography" keyword env['BSTINPUTS'] for "bibliographystyle" keyword FIXME: also look for the class or style in document[class|style]{} FIXME: also look for the argument of bibliographystyle{} """ keyword_paths = {'include': 'TEXINPUTS', 'input': 'TEXINPUTS', 'includegraphics': 'TEXINPUTS', 'bibliography': 'BIBINPUTS', 'bibliographystyle': 'BSTINPUTS', 'usepackage': 'TEXINPUTS'} env_variables = SCons.Util.unique(keyword_paths.values()) def __init__(self, name, suffixes, graphics_extensions, *args, **kw): # We have to include \n with the % we exclude from the first part # part of the regex because the expression is compiled with re.M. # Without the \n, the ^ could match the beginning of a *previous* # line followed by one or more newline characters (i.e. blank # lines), interfering with a match on the next line. regex = r'^[^%\n]*\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography|usepackage){([^}]*)}' self.cre = re.compile(regex, re.M) self.graphics_extensions = graphics_extensions def _scan(node, env, path=(), self=self): node = node.rfile() if not node.exists(): return [] return self.scan(node, path) class FindMultiPathDirs: """The stock FindPathDirs function has the wrong granularity: it is called once per target, while we need the path that depends on what kind of included files is being searched. This wrapper hides multiple instances of FindPathDirs, one per the LaTeX path variable in the environment. When invoked, the function calculates and returns all the required paths as a dictionary (converted into a tuple to become hashable). Then the scan function converts it back and uses a dictionary of tuples rather than a single tuple of paths. """ def __init__(self, dictionary): self.dictionary = {} for k,n in dictionary.items(): self.dictionary[k] = ( SCons.Scanner.FindPathDirs(n), FindENVPathDirs(n) ) def __call__(self, env, dir=None, target=None, source=None, argument=None): di = {} for k,(c,cENV) in self.dictionary.items(): di[k] = ( c(env, dir=None, target=None, source=None, argument=None) , cENV(env, dir=None, target=None, source=None, argument=None) ) # To prevent "dict is not hashable error" return tuple(di.items()) class LaTeXScanCheck: """Skip all but LaTeX source files, i.e., do not scan *.eps, *.pdf, *.jpg, etc. """ def __init__(self, suffixes): self.suffixes = suffixes def __call__(self, node, env): current = not node.has_builder() or node.is_up_to_date() scannable = node.get_suffix() in env.subst_list(self.suffixes)[0] # Returning false means that the file is not scanned. return scannable and current kw['function'] = _scan kw['path_function'] = FindMultiPathDirs(LaTeX.keyword_paths) kw['recursive'] = 1 kw['skeys'] = suffixes kw['scan_check'] = LaTeXScanCheck(suffixes) kw['name'] = name SCons.Scanner.Base.__init__(*(self,) + args, **kw) def _latex_names(self, include): filename = include[1] if include[0] == 'input': base, ext = os.path.splitext( filename ) if ext == "": return [filename + '.tex'] if (include[0] == 'include'): return [filename + '.tex'] if include[0] == 'bibliography': base, ext = os.path.splitext( filename ) if ext == "": return [filename + '.bib'] if include[0] == 'usepackage': base, ext = os.path.splitext( filename ) if ext == "": return [filename + '.sty'] if include[0] == 'includegraphics': base, ext = os.path.splitext( filename ) if ext == "": #TODO(1.5) return [filename + e for e in self.graphics_extensions] #return map(lambda e, f=filename: f+e, self.graphics_extensions + TexGraphics) # use the line above to find dependency for PDF builder when only .eps figure is present # Since it will be found if the user tell scons how to make the pdf figure leave it out for now. return map(lambda e, f=filename: f+e, self.graphics_extensions) return [filename] def sort_key(self, include): return SCons.Node.FS._my_normcase(str(include)) def find_include(self, include, source_dir, path): try: sub_path = path[include[0]] except (IndexError, KeyError): sub_path = () try_names = self._latex_names(include) for n in try_names: # see if we find it using the path in env[var] i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[0]) if i: return i, include # see if we find it using the path in env['ENV'][var] i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[1]) if i: return i, include return i, include def scan(self, node, path=()): # Modify the default scan function to allow for the regular # expression to return a comma separated list of file names # as can be the case with the bibliography keyword. # Cache the includes list in node so we only scan it once: path_dict = dict(list(path)) noopt_cre = re.compile('\[.*$') if node.includes != None: includes = node.includes else: includes = self.cre.findall(node.get_text_contents()) # 1. Split comma-separated lines, e.g. # ('bibliography', 'phys,comp') # should become two entries # ('bibliography', 'phys') # ('bibliography', 'comp') # 2. Remove the options, e.g., such as # ('includegraphics[clip,width=0.7\\linewidth]', 'picture.eps') # should become # ('includegraphics', 'picture.eps') split_includes = [] for include in includes: inc_type = noopt_cre.sub('', include[0]) inc_list = string.split(include[1],',') for j in range(len(inc_list)): split_includes.append( (inc_type, inc_list[j]) ) # includes = split_includes node.includes = includes # This is a hand-coded DSU (decorate-sort-undecorate, or # Schwartzian transform) pattern. The sort key is the raw name # of the file as specifed on the \include, \input, etc. line. # TODO: what about the comment in the original Classic scanner: # """which lets # us keep the sort order constant regardless of whether the file # is actually found in a Repository or locally.""" nodes = [] source_dir = node.get_dir() for include in includes: # # Handle multiple filenames in include[1] # n, i = self.find_include(include, source_dir, path_dict) if n is None: # Do not bother with 'usepackage' warnings, as they most # likely refer to system-level files if include[0] != 'usepackage': SCons.Warnings.warn(SCons.Warnings.DependencyWarning, "No dependency generated for file: %s (included from: %s) -- file not found" % (i, node)) else: sortkey = self.sort_key(n) nodes.append((sortkey, n)) # nodes.sort() nodes = map(lambda pair: pair[1], nodes) return nodes # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/Prog.py0000644000175000017500000000634613606712377022247 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/Prog.py 4369 2009/09/19 15:58:29 scons" import string import SCons.Node import SCons.Node.FS import SCons.Scanner import SCons.Util # global, set by --debug=findlibs print_find_libs = None def ProgramScanner(**kw): """Return a prototype Scanner instance for scanning executable files for static-lib dependencies""" kw['path_function'] = SCons.Scanner.FindPathDirs('LIBPATH') ps = SCons.Scanner.Base(*[scan, "ProgramScanner"], **kw) return ps def scan(node, env, libpath = ()): """ This scanner scans program files for static-library dependencies. It will search the LIBPATH environment variable for libraries specified in the LIBS variable, returning any files it finds as dependencies. """ try: libs = env['LIBS'] except KeyError: # There are no LIBS in this environment, so just return a null list: return [] if SCons.Util.is_String(libs): libs = string.split(libs) else: libs = SCons.Util.flatten(libs) try: prefix = env['LIBPREFIXES'] if not SCons.Util.is_List(prefix): prefix = [ prefix ] except KeyError: prefix = [ '' ] try: suffix = env['LIBSUFFIXES'] if not SCons.Util.is_List(suffix): suffix = [ suffix ] except KeyError: suffix = [ '' ] pairs = [] for suf in map(env.subst, suffix): for pref in map(env.subst, prefix): pairs.append((pref, suf)) result = [] if callable(libpath): libpath = libpath() find_file = SCons.Node.FS.find_file adjustixes = SCons.Util.adjustixes for lib in libs: if SCons.Util.is_String(lib): lib = env.subst(lib) for pref, suf in pairs: l = adjustixes(lib, pref, suf) l = find_file(l, libpath, verbose=print_find_libs) if l: result.append(l) else: result.append(lib) return result # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/D.py0000644000175000017500000000500013606712377021505 0ustar kurtkurt"""SCons.Scanner.D Scanner for the Digital Mars "D" programming language. Coded by Andy Friesen 17 Nov 2003 """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/D.py 4369 2009/09/19 15:58:29 scons" import re import string import SCons.Scanner def DScanner(): """Return a prototype Scanner instance for scanning D source files""" ds = D() return ds class D(SCons.Scanner.Classic): def __init__ (self): SCons.Scanner.Classic.__init__ (self, name = "DScanner", suffixes = '$DSUFFIXES', path_variable = 'DPATH', regex = 'import\s+(?:[a-zA-Z0-9_.]+)\s*(?:,\s*(?:[a-zA-Z0-9_.]+)\s*)*;') self.cre2 = re.compile ('(?:import\s)?\s*([a-zA-Z0-9_.]+)\s*(?:,|;)', re.M) def find_include(self, include, source_dir, path): # translate dots (package separators) to slashes inc = string.replace(include, '.', '/') i = SCons.Node.FS.find_file(inc + '.d', (source_dir,) + path) if i is None: i = SCons.Node.FS.find_file (inc + '.di', (source_dir,) + path) return i, include def find_include_names(self, node): includes = [] for i in self.cre.findall(node.get_text_contents()): includes = includes + self.cre2.findall(i) return includes # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/C.py0000644000175000017500000001136413606712377021516 0ustar kurtkurt"""SCons.Scanner.C This module implements the depenency scanner for C/C++ code. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/C.py 4369 2009/09/19 15:58:29 scons" import SCons.Node.FS import SCons.Scanner import SCons.Util import SCons.cpp class SConsCPPScanner(SCons.cpp.PreProcessor): """ SCons-specific subclass of the cpp.py module's processing. We subclass this so that: 1) we can deal with files represented by Nodes, not strings; 2) we can keep track of the files that are missing. """ def __init__(self, *args, **kw): SCons.cpp.PreProcessor.__init__(*(self,)+args, **kw) self.missing = [] def initialize_result(self, fname): self.result = SCons.Util.UniqueList([fname]) def finalize_result(self, fname): return self.result[1:] def find_include_file(self, t): keyword, quote, fname = t result = SCons.Node.FS.find_file(fname, self.searchpath[quote]) if not result: self.missing.append((fname, self.current_file)) return result def read_file(self, file): try: fp = open(str(file.rfile())) except EnvironmentError as e: self.missing.append((file, self.current_file)) return '' else: return fp.read() def dictify_CPPDEFINES(env): cppdefines = env.get('CPPDEFINES', {}) if cppdefines is None: return {} if SCons.Util.is_Sequence(cppdefines): result = {} for c in cppdefines: if SCons.Util.is_Sequence(c): result[c[0]] = c[1] else: result[c] = None return result if not SCons.Util.is_Dict(cppdefines): return {cppdefines : None} return cppdefines class SConsCPPScannerWrapper: """ The SCons wrapper around a cpp.py scanner. This is the actual glue between the calling conventions of generic SCons scanners, and the (subclass of) cpp.py class that knows how to look for #include lines with reasonably real C-preprocessor-like evaluation of #if/#ifdef/#else/#elif lines. """ def __init__(self, name, variable): self.name = name self.path = SCons.Scanner.FindPathDirs(variable) def __call__(self, node, env, path = ()): cpp = SConsCPPScanner(current = node.get_dir(), cpppath = path, dict = dictify_CPPDEFINES(env)) result = cpp(node) for included, includer in cpp.missing: fmt = "No dependency generated for file: %s (included from: %s) -- file not found" SCons.Warnings.warn(SCons.Warnings.DependencyWarning, fmt % (included, includer)) return result def recurse_nodes(self, nodes): return nodes def select(self, node): return self def CScanner(): """Return a prototype Scanner instance for scanning source files that use the C pre-processor""" # Here's how we would (or might) use the CPP scanner code above that # knows how to evaluate #if/#ifdef/#else/#elif lines when searching # for #includes. This is commented out for now until we add the # right configurability to let users pick between the scanners. #return SConsCPPScannerWrapper("CScanner", "CPPPATH") cs = SCons.Scanner.ClassicCPP("CScanner", "$CPPSUFFIXES", "CPPPATH", '^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")') return cs # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/Fortran.py0000644000175000017500000003414613606712377022752 0ustar kurtkurt"""SCons.Scanner.Fortran This module implements the dependency scanner for Fortran code. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/Fortran.py 4369 2009/09/19 15:58:29 scons" import re import string import SCons.Node import SCons.Node.FS import SCons.Scanner import SCons.Util import SCons.Warnings class F90Scanner(SCons.Scanner.Classic): """ A Classic Scanner subclass for Fortran source files which takes into account both USE and INCLUDE statements. This scanner will work for both F77 and F90 (and beyond) compilers. Currently, this scanner assumes that the include files do not contain USE statements. To enable the ability to deal with USE statements in include files, add logic right after the module names are found to loop over each include file, search for and locate each USE statement, and append each module name to the list of dependencies. Caching the search results in a common dictionary somewhere so that the same include file is not searched multiple times would be a smart thing to do. """ def __init__(self, name, suffixes, path_variable, use_regex, incl_regex, def_regex, *args, **kw): self.cre_use = re.compile(use_regex, re.M) self.cre_incl = re.compile(incl_regex, re.M) self.cre_def = re.compile(def_regex, re.M) def _scan(node, env, path, self=self): node = node.rfile() if not node.exists(): return [] return self.scan(node, env, path) kw['function'] = _scan kw['path_function'] = SCons.Scanner.FindPathDirs(path_variable) kw['recursive'] = 1 kw['skeys'] = suffixes kw['name'] = name SCons.Scanner.Current.__init__(*(self,) + args, **kw) def scan(self, node, env, path=()): # cache the includes list in node so we only scan it once: if node.includes != None: mods_and_includes = node.includes else: # retrieve all included filenames includes = self.cre_incl.findall(node.get_text_contents()) # retrieve all USE'd module names modules = self.cre_use.findall(node.get_text_contents()) # retrieve all defined module names defmodules = self.cre_def.findall(node.get_text_contents()) # Remove all USE'd module names that are defined in the same file d = {} for m in defmodules: d[m] = 1 modules = filter(lambda m, d=d: m not in d, modules) #modules = self.undefinedModules(modules, defmodules) # Convert module name to a .mod filename suffix = env.subst('$FORTRANMODSUFFIX') modules = map(lambda x, s=suffix: string.lower(x) + s, modules) # Remove unique items from the list mods_and_includes = SCons.Util.unique(includes+modules) node.includes = mods_and_includes # This is a hand-coded DSU (decorate-sort-undecorate, or # Schwartzian transform) pattern. The sort key is the raw name # of the file as specifed on the USE or INCLUDE line, which lets # us keep the sort order constant regardless of whether the file # is actually found in a Repository or locally. nodes = [] source_dir = node.get_dir() if callable(path): path = path() for dep in mods_and_includes: n, i = self.find_include(dep, source_dir, path) if n is None: SCons.Warnings.warn(SCons.Warnings.DependencyWarning, "No dependency generated for file: %s (referenced by: %s) -- file not found" % (i, node)) else: sortkey = self.sort_key(dep) nodes.append((sortkey, n)) nodes.sort() nodes = map(lambda pair: pair[1], nodes) return nodes def FortranScan(path_variable="FORTRANPATH"): """Return a prototype Scanner instance for scanning source files for Fortran USE & INCLUDE statements""" # The USE statement regex matches the following: # # USE module_name # USE :: module_name # USE, INTRINSIC :: module_name # USE, NON_INTRINSIC :: module_name # # Limitations # # -- While the regex can handle multiple USE statements on one line, # it cannot properly handle them if they are commented out. # In either of the following cases: # # ! USE mod_a ; USE mod_b [entire line is commented out] # USE mod_a ! ; USE mod_b [in-line comment of second USE statement] # # the second module name (mod_b) will be picked up as a dependency # even though it should be ignored. The only way I can see # to rectify this would be to modify the scanner to eliminate # the call to re.findall, read in the contents of the file, # treating the comment character as an end-of-line character # in addition to the normal linefeed, loop over each line, # weeding out the comments, and looking for the USE statements. # One advantage to this is that the regex passed to the scanner # would no longer need to match a semicolon. # # -- I question whether or not we need to detect dependencies to # INTRINSIC modules because these are built-in to the compiler. # If we consider them a dependency, will SCons look for them, not # find them, and kill the build? Or will we there be standard # compiler-specific directories we will need to point to so the # compiler and SCons can locate the proper object and mod files? # Here is a breakdown of the regex: # # (?i) : regex is case insensitive # ^ : start of line # (?: : group a collection of regex symbols without saving the match as a "group" # ^|; : matches either the start of the line or a semicolon - semicolon # ) : end the unsaved grouping # \s* : any amount of white space # USE : match the string USE, case insensitive # (?: : group a collection of regex symbols without saving the match as a "group" # \s+| : match one or more whitespace OR .... (the next entire grouped set of regex symbols) # (?: : group a collection of regex symbols without saving the match as a "group" # (?: : establish another unsaved grouping of regex symbols # \s* : any amount of white space # , : match a comma # \s* : any amount of white space # (?:NON_)? : optionally match the prefix NON_, case insensitive # INTRINSIC : match the string INTRINSIC, case insensitive # )? : optionally match the ", INTRINSIC/NON_INTRINSIC" grouped expression # \s* : any amount of white space # :: : match a double colon that must appear after the INTRINSIC/NON_INTRINSIC attribute # ) : end the unsaved grouping # ) : end the unsaved grouping # \s* : match any amount of white space # (\w+) : match the module name that is being USE'd # # use_regex = "(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)" # The INCLUDE statement regex matches the following: # # INCLUDE 'some_Text' # INCLUDE "some_Text" # INCLUDE "some_Text" ; INCLUDE "some_Text" # INCLUDE kind_"some_Text" # INCLUDE kind_'some_Text" # # where some_Text can include any alphanumeric and/or special character # as defined by the Fortran 2003 standard. # # Limitations: # # -- The Fortran standard dictates that a " or ' in the INCLUDE'd # string must be represented as a "" or '', if the quotes that wrap # the entire string are either a ' or ", respectively. While the # regular expression below can detect the ' or " characters just fine, # the scanning logic, presently is unable to detect them and reduce # them to a single instance. This probably isn't an issue since, # in practice, ' or " are not generally used in filenames. # # -- This regex will not properly deal with multiple INCLUDE statements # when the entire line has been commented out, ala # # ! INCLUDE 'some_file' ; INCLUDE 'some_file' # # In such cases, it will properly ignore the first INCLUDE file, # but will actually still pick up the second. Interestingly enough, # the regex will properly deal with these cases: # # INCLUDE 'some_file' # INCLUDE 'some_file' !; INCLUDE 'some_file' # # To get around the above limitation, the FORTRAN programmer could # simply comment each INCLUDE statement separately, like this # # ! INCLUDE 'some_file' !; INCLUDE 'some_file' # # The way I see it, the only way to get around this limitation would # be to modify the scanning logic to replace the calls to re.findall # with a custom loop that processes each line separately, throwing # away fully commented out lines before attempting to match against # the INCLUDE syntax. # # Here is a breakdown of the regex: # # (?i) : regex is case insensitive # (?: : begin a non-saving group that matches the following: # ^ : either the start of the line # | : or # ['">]\s*; : a semicolon that follows a single quote, # double quote or greater than symbol (with any # amount of whitespace in between). This will # allow the regex to match multiple INCLUDE # statements per line (although it also requires # the positive lookahead assertion that is # used below). It will even properly deal with # (i.e. ignore) cases in which the additional # INCLUDES are part of an in-line comment, ala # " INCLUDE 'someFile' ! ; INCLUDE 'someFile2' " # ) : end of non-saving group # \s* : any amount of white space # INCLUDE : match the string INCLUDE, case insensitive # \s+ : match one or more white space characters # (?\w+_)? : match the optional "kind-param _" prefix allowed by the standard # [<"'] : match the include delimiter - an apostrophe, double quote, or less than symbol # (.+?) : match one or more characters that make up # the included path and file name and save it # in a group. The Fortran standard allows for # any non-control character to be used. The dot # operator will pick up any character, including # control codes, but I can't conceive of anyone # putting control codes in their file names. # The question mark indicates it is non-greedy so # that regex will match only up to the next quote, # double quote, or greater than symbol # (?=["'>]) : positive lookahead assertion to match the include # delimiter - an apostrophe, double quote, or # greater than symbol. This level of complexity # is required so that the include delimiter is # not consumed by the match, thus allowing the # sub-regex discussed above to uniquely match a # set of semicolon-separated INCLUDE statements # (as allowed by the F2003 standard) include_regex = """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])""" # The MODULE statement regex finds module definitions by matching # the following: # # MODULE module_name # # but *not* the following: # # MODULE PROCEDURE procedure_name # # Here is a breakdown of the regex: # # (?i) : regex is case insensitive # ^\s* : any amount of white space # MODULE : match the string MODULE, case insensitive # \s+ : match one or more white space characters # (?!PROCEDURE) : but *don't* match if the next word matches # PROCEDURE (negative lookahead assertion), # case insensitive # (\w+) : match one or more alphanumeric characters # that make up the defined module name and # save it in a group def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" scanner = F90Scanner("FortranScan", "$FORTRANSUFFIXES", path_variable, use_regex, include_regex, def_regex) return scanner # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/Dir.py0000644000175000017500000000733213606712377022052 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/Dir.py 4369 2009/09/19 15:58:29 scons" import SCons.Node.FS import SCons.Scanner def only_dirs(nodes): is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir) return filter(is_Dir, nodes) def DirScanner(**kw): """Return a prototype Scanner instance for scanning directories for on-disk files""" kw['node_factory'] = SCons.Node.FS.Entry kw['recursive'] = only_dirs return SCons.Scanner.Base(*(scan_on_disk, "DirScanner"), **kw) def DirEntryScanner(**kw): """Return a prototype Scanner instance for "scanning" directory Nodes for their in-memory entries""" kw['node_factory'] = SCons.Node.FS.Entry kw['recursive'] = None return SCons.Scanner.Base(*(scan_in_memory, "DirEntryScanner"), **kw) skip_entry = {} skip_entry_list = [ '.', '..', '.sconsign', # Used by the native dblite.py module. '.sconsign.dblite', # Used by dbm and dumbdbm. '.sconsign.dir', # Used by dbm. '.sconsign.pag', # Used by dumbdbm. '.sconsign.dat', '.sconsign.bak', # Used by some dbm emulations using Berkeley DB. '.sconsign.db', ] for skip in skip_entry_list: skip_entry[skip] = 1 skip_entry[SCons.Node.FS._my_normcase(skip)] = 1 do_not_scan = lambda k: k not in skip_entry def scan_on_disk(node, env, path=()): """ Scans a directory for on-disk files and directories therein. Looking up the entries will add these to the in-memory Node tree representation of the file system, so all we have to do is just that and then call the in-memory scanning function. """ try: flist = node.fs.listdir(node.abspath) except (IOError, OSError): return [] e = node.Entry for f in filter(do_not_scan, flist): # Add ./ to the beginning of the file name so if it begins with a # '#' we don't look it up relative to the top-level directory. e('./' + f) return scan_in_memory(node, env, path) def scan_in_memory(node, env, path=()): """ "Scans" a Node.FS.Dir for its in-memory entries. """ try: entries = node.entries except AttributeError: # It's not a Node.FS.Dir (or doesn't look enough like one for # our purposes), which can happen if a target list containing # mixed Node types (Dirs and Files, for example) has a Dir as # the first entry. return [] entry_list = sorted(filter(do_not_scan, entries.keys())) return map(lambda n, e=entries: e[n], entry_list) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/IDL.py0000644000175000017500000000347413606712377021747 0ustar kurtkurt"""SCons.Scanner.IDL This module implements the depenency scanner for IDL (Interface Definition Language) files. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/IDL.py 4369 2009/09/19 15:58:29 scons" import SCons.Node.FS import SCons.Scanner def IDLScan(): """Return a prototype Scanner instance for scanning IDL source files""" cs = SCons.Scanner.ClassicCPP("IDLScan", "$IDLSUFFIXES", "CPPPATH", '^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")') return cs # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Scanner/RC.py0000644000175000017500000000401413606712377021632 0ustar kurtkurt"""SCons.Scanner.RC This module implements the depenency scanner for RC (Interface Definition Language) files. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Scanner/RC.py 4369 2009/09/19 15:58:29 scons" import SCons.Node.FS import SCons.Scanner import re def RCScan(): """Return a prototype Scanner instance for scanning RC source files""" res_re= r'^(?:\s*#\s*(?:include)|' \ '.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \ '\s*.*?)' \ '\s*(<|"| )([^>"\s]+)(?:[>" ])*$' resScanner = SCons.Scanner.ClassicCPP( "ResourceScanner", "$RCSUFFIXES", "CPPPATH", res_re ) return resScanner # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/cpp.py0000644000175000017500000004715313606712377020532 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/cpp.py 4369 2009/09/19 15:58:29 scons" __doc__ = """ SCons C Pre-Processor module """ # TODO(1.5): remove this import # This module doesn't use anything from SCons by name, but we import SCons # here to pull in zip() from the SCons.compat layer for early Pythons. import SCons import os import re import string # # First "subsystem" of regular expressions that we set up: # # Stuff to turn the C preprocessor directives in a file's contents into # a list of tuples that we can process easily. # # A table of regular expressions that fetch the arguments from the rest of # a C preprocessor line. Different directives have different arguments # that we want to fetch, using the regular expressions to which the lists # of preprocessor directives map. cpp_lines_dict = { # Fetch the rest of a #if/#elif/#ifdef/#ifndef as one argument, # separated from the keyword by white space. ('if', 'elif', 'ifdef', 'ifndef',) : '\s+(.+)', # Fetch the rest of a #import/#include/#include_next line as one # argument, with white space optional. ('import', 'include', 'include_next',) : '\s*(.+)', # We don't care what comes after a #else or #endif line. ('else', 'endif',) : '', # Fetch three arguments from a #define line: # 1) The #defined keyword. # 2) The optional parentheses and arguments (if it's a function-like # macro, '' if it's not). # 3) The expansion value. ('define',) : '\s+([_A-Za-z][_A-Za-z0-9_]*)(\([^)]*\))?\s*(.*)', # Fetch the #undefed keyword from a #undef line. ('undef',) : '\s+([_A-Za-z][A-Za-z0-9_]*)', } # Create a table that maps each individual C preprocessor directive to # the corresponding compiled regular expression that fetches the arguments # we care about. Table = {} for op_list, expr in cpp_lines_dict.items(): e = re.compile(expr) for op in op_list: Table[op] = e del e del op del op_list # Create a list of the expressions we'll use to match all of the # preprocessor directives. These are the same as the directives # themselves *except* that we must use a negative lookahead assertion # when matching "if" so it doesn't match the "if" in "ifdef." override = { 'if' : 'if(?!def)', } l = map(lambda x, o=override: o.get(x, x), Table.keys()) # Turn the list of expressions into one big honkin' regular expression # that will match all the preprocessor lines at once. This will return # a list of tuples, one for each preprocessor line. The preprocessor # directive will be the first element in each tuple, and the rest of # the line will be the second element. e = '^\s*#\s*(' + string.join(l, '|') + ')(.*)$' # And last but not least, compile the expression. CPP_Expression = re.compile(e, re.M) # # Second "subsystem" of regular expressions that we set up: # # Stuff to translate a C preprocessor expression (as found on a #if or # #elif line) into an equivalent Python expression that we can eval(). # # A dictionary that maps the C representation of Boolean operators # to their Python equivalents. CPP_to_Python_Ops_Dict = { '!' : ' not ', '!=' : ' != ', '&&' : ' and ', '||' : ' or ', '?' : ' and ', ':' : ' or ', '\r' : '', } CPP_to_Python_Ops_Sub = lambda m, d=CPP_to_Python_Ops_Dict: d[m.group(0)] # We have to sort the keys by length so that longer expressions # come *before* shorter expressions--in particular, "!=" must # come before "!" in the alternation. Without this, the Python # re module, as late as version 2.2.2, empirically matches the # "!" in "!=" first, instead of finding the longest match. # What's up with that? l = CPP_to_Python_Ops_Dict.keys() l.sort(lambda a, b: cmp(len(b), len(a))) # Turn the list of keys into one regular expression that will allow us # to substitute all of the operators at once. expr = string.join(map(re.escape, l), '|') # ...and compile the expression. CPP_to_Python_Ops_Expression = re.compile(expr) # A separate list of expressions to be evaluated and substituted # sequentially, not all at once. CPP_to_Python_Eval_List = [ ['defined\s+(\w+)', '__dict__.has_key("\\1")'], ['defined\s*\((\w+)\)', '__dict__.has_key("\\1")'], ['/\*.*\*/', ''], ['/\*.*', ''], ['//.*', ''], ['(0x[0-9A-Fa-f]*)[UL]+', '\\1L'], ] # Replace the string representations of the regular expressions in the # list with compiled versions. for l in CPP_to_Python_Eval_List: l[0] = re.compile(l[0]) # Wrap up all of the above into a handy function. def CPP_to_Python(s): """ Converts a C pre-processor expression into an equivalent Python expression that can be evaluated. """ s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s) for expr, repl in CPP_to_Python_Eval_List: s = expr.sub(repl, s) return s del expr del l del override class FunctionEvaluator: """ Handles delayed evaluation of a #define function call. """ def __init__(self, name, args, expansion): """ Squirrels away the arguments and expansion value of a #define macro function for later evaluation when we must actually expand a value that uses it. """ self.name = name self.args = function_arg_separator.split(args) try: expansion = string.split(expansion, '##') except (AttributeError, TypeError): # Python 1.5 throws TypeError if "expansion" isn't a string, # later versions throw AttributeError. pass self.expansion = expansion def __call__(self, *values): """ Evaluates the expansion of a #define macro function called with the specified values. """ if len(self.args) != len(values): raise ValueError("Incorrect number of arguments to `%s'" % self.name) # Create a dictionary that maps the macro arguments to the # corresponding values in this "call." We'll use this when we # eval() the expansion so that arguments will get expanded to # the right values. locals = {} for k, v in zip(self.args, values): locals[k] = v parts = [] for s in self.expansion: if not s in self.args: s = repr(s) parts.append(s) statement = string.join(parts, ' + ') return eval(statement, globals(), locals) # Find line continuations. line_continuations = re.compile('\\\\\r?\n') # Search for a "function call" macro on an expansion. Returns the # two-tuple of the "function" name itself, and a string containing the # arguments within the call parentheses. function_name = re.compile('(\S+)\(([^)]*)\)') # Split a string containing comma-separated function call arguments into # the separate arguments. function_arg_separator = re.compile(',\s*') class PreProcessor: """ The main workhorse class for handling C pre-processing. """ def __init__(self, current=os.curdir, cpppath=(), dict={}, all=0): global Table cpppath = tuple(cpppath) self.searchpath = { '"' : (current,) + cpppath, '<' : cpppath + (current,), } # Initialize our C preprocessor namespace for tracking the # values of #defined keywords. We use this namespace to look # for keywords on #ifdef/#ifndef lines, and to eval() the # expressions on #if/#elif lines (after massaging them from C to # Python). self.cpp_namespace = dict.copy() self.cpp_namespace['__dict__'] = self.cpp_namespace if all: self.do_include = self.all_include # For efficiency, a dispatch table maps each C preprocessor # directive (#if, #define, etc.) to the method that should be # called when we see it. We accomodate state changes (#if, # #ifdef, #ifndef) by pushing the current dispatch table on a # stack and changing what method gets called for each relevant # directive we might see next at this level (#else, #elif). # #endif will simply pop the stack. d = { 'scons_current_file' : self.scons_current_file } for op in Table.keys(): d[op] = getattr(self, 'do_' + op) self.default_table = d # Controlling methods. def tupleize(self, contents): """ Turns the contents of a file into a list of easily-processed tuples describing the CPP lines in the file. The first element of each tuple is the line's preprocessor directive (#if, #include, #define, etc., minus the initial '#'). The remaining elements are specific to the type of directive, as pulled apart by the regular expression. """ global CPP_Expression, Table contents = line_continuations.sub('', contents) cpp_tuples = CPP_Expression.findall(contents) return map(lambda m, t=Table: (m[0],) + t[m[0]].match(m[1]).groups(), cpp_tuples) def __call__(self, file): """ Pre-processes a file. This is the main public entry point. """ self.current_file = file return self.process_contents(self.read_file(file), file) def process_contents(self, contents, fname=None): """ Pre-processes a file contents. This is the main internal entry point. """ self.stack = [] self.dispatch_table = self.default_table.copy() self.current_file = fname self.tuples = self.tupleize(contents) self.initialize_result(fname) while self.tuples: t = self.tuples.pop(0) # Uncomment to see the list of tuples being processed (e.g., # to validate the CPP lines are being translated correctly). #print t self.dispatch_table[t[0]](t) return self.finalize_result(fname) # Dispatch table stack manipulation methods. def save(self): """ Pushes the current dispatch table on the stack and re-initializes the current dispatch table to the default. """ self.stack.append(self.dispatch_table) self.dispatch_table = self.default_table.copy() def restore(self): """ Pops the previous dispatch table off the stack and makes it the current one. """ try: self.dispatch_table = self.stack.pop() except IndexError: pass # Utility methods. def do_nothing(self, t): """ Null method for when we explicitly want the action for a specific preprocessor directive to do nothing. """ pass def scons_current_file(self, t): self.current_file = t[1] def eval_expression(self, t): """ Evaluates a C preprocessor expression. This is done by converting it to a Python equivalent and eval()ing it in the C preprocessor namespace we use to track #define values. """ t = CPP_to_Python(string.join(t[1:])) try: return eval(t, self.cpp_namespace) except (NameError, TypeError): return 0 def initialize_result(self, fname): self.result = [fname] def finalize_result(self, fname): return self.result[1:] def find_include_file(self, t): """ Finds the #include file for a given preprocessor tuple. """ fname = t[2] for d in self.searchpath[t[1]]: if d == os.curdir: f = fname else: f = os.path.join(d, fname) if os.path.isfile(f): return f return None def read_file(self, file): return open(file).read() # Start and stop processing include lines. def start_handling_includes(self, t=None): """ Causes the PreProcessor object to start processing #import, #include and #include_next lines. This method will be called when a #if, #ifdef, #ifndef or #elif evaluates True, or when we reach the #else in a #if, #ifdef, #ifndef or #elif block where a condition already evaluated False. """ d = self.dispatch_table d['import'] = self.do_import d['include'] = self.do_include d['include_next'] = self.do_include def stop_handling_includes(self, t=None): """ Causes the PreProcessor object to stop processing #import, #include and #include_next lines. This method will be called when a #if, #ifdef, #ifndef or #elif evaluates False, or when we reach the #else in a #if, #ifdef, #ifndef or #elif block where a condition already evaluated True. """ d = self.dispatch_table d['import'] = self.do_nothing d['include'] = self.do_nothing d['include_next'] = self.do_nothing # Default methods for handling all of the preprocessor directives. # (Note that what actually gets called for a given directive at any # point in time is really controlled by the dispatch_table.) def _do_if_else_condition(self, condition): """ Common logic for evaluating the conditions on #if, #ifdef and #ifndef lines. """ self.save() d = self.dispatch_table if condition: self.start_handling_includes() d['elif'] = self.stop_handling_includes d['else'] = self.stop_handling_includes else: self.stop_handling_includes() d['elif'] = self.do_elif d['else'] = self.start_handling_includes def do_ifdef(self, t): """ Default handling of a #ifdef line. """ self._do_if_else_condition(t[1] in self.cpp_namespace) def do_ifndef(self, t): """ Default handling of a #ifndef line. """ self._do_if_else_condition(t[1] not in self.cpp_namespace) def do_if(self, t): """ Default handling of a #if line. """ self._do_if_else_condition(self.eval_expression(t)) def do_elif(self, t): """ Default handling of a #elif line. """ d = self.dispatch_table if self.eval_expression(t): self.start_handling_includes() d['elif'] = self.stop_handling_includes d['else'] = self.stop_handling_includes def do_else(self, t): """ Default handling of a #else line. """ pass def do_endif(self, t): """ Default handling of a #endif line. """ self.restore() def do_define(self, t): """ Default handling of a #define line. """ _, name, args, expansion = t try: expansion = int(expansion) except (TypeError, ValueError): pass if args: evaluator = FunctionEvaluator(name, args[1:-1], expansion) self.cpp_namespace[name] = evaluator else: self.cpp_namespace[name] = expansion def do_undef(self, t): """ Default handling of a #undef line. """ try: del self.cpp_namespace[t[1]] except KeyError: pass def do_import(self, t): """ Default handling of a #import line. """ # XXX finish this -- maybe borrow/share logic from do_include()...? pass def do_include(self, t): """ Default handling of a #include line. """ t = self.resolve_include(t) include_file = self.find_include_file(t) if include_file: #print "include_file =", include_file self.result.append(include_file) contents = self.read_file(include_file) new_tuples = [('scons_current_file', include_file)] + \ self.tupleize(contents) + \ [('scons_current_file', self.current_file)] self.tuples[:] = new_tuples + self.tuples # Date: Tue, 22 Nov 2005 20:26:09 -0500 # From: Stefan Seefeld # # By the way, #include_next is not the same as #include. The difference # being that #include_next starts its search in the path following the # path that let to the including file. In other words, if your system # include paths are ['/foo', '/bar'], and you are looking at a header # '/foo/baz.h', it might issue an '#include_next ' which would # correctly resolve to '/bar/baz.h' (if that exists), but *not* see # '/foo/baz.h' again. See http://www.delorie.com/gnu/docs/gcc/cpp_11.html # for more reasoning. # # I have no idea in what context 'import' might be used. # XXX is #include_next really the same as #include ? do_include_next = do_include # Utility methods for handling resolution of include files. def resolve_include(self, t): """Resolve a tuple-ized #include line. This handles recursive expansion of values without "" or <> surrounding the name until an initial " or < is found, to handle #include FILE where FILE is a #define somewhere else. """ s = t[1] while not s[0] in '<"': #print "s =", s try: s = self.cpp_namespace[s] except KeyError: m = function_name.search(s) s = self.cpp_namespace[m.group(1)] if callable(s): args = function_arg_separator.split(m.group(2)) s = s(*args) if not s: return None return (t[0], s[0], s[1:-1]) def all_include(self, t): """ """ self.result.append(self.resolve_include(t)) class DumbPreProcessor(PreProcessor): """A preprocessor that ignores all #if/#elif/#else/#endif directives and just reports back *all* of the #include files (like the classic SCons scanner did). This is functionally equivalent to using a regular expression to find all of the #include lines, only slower. It exists mainly as an example of how the main PreProcessor class can be sub-classed to tailor its behavior. """ def __init__(self, *args, **kw): PreProcessor.__init__(*(self,)+args, **kw) d = self.default_table for func in ['if', 'elif', 'else', 'endif', 'ifdef', 'ifndef']: d[func] = d[func] = self.do_nothing del __revision__ # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Warnings.py0000644000175000017500000001353313606712377021533 0ustar kurtkurt# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # """SCons.Warnings This file implements the warnings framework for SCons. """ __revision__ = "src/engine/SCons/Warnings.py 4369 2009/09/19 15:58:29 scons" import string import sys import SCons.Errors class Warning(SCons.Errors.UserError): pass class MandatoryWarning(Warning): pass class FutureDeprecatedWarning(Warning): pass class DeprecatedWarning(Warning): pass class MandatoryDeprecatedWarning(MandatoryWarning): pass # NOTE: If you add a new warning class, add it to the man page, too! class CacheWriteErrorWarning(Warning): pass class CorruptSConsignWarning(Warning): pass class DependencyWarning(Warning): pass class DeprecatedCopyWarning(DeprecatedWarning): pass class DeprecatedOptionsWarning(DeprecatedWarning): pass class DeprecatedSourceSignaturesWarning(DeprecatedWarning): pass class DeprecatedTargetSignaturesWarning(DeprecatedWarning): pass class DuplicateEnvironmentWarning(Warning): pass class FutureReservedVariableWarning(Warning): pass class LinkWarning(Warning): pass class MisleadingKeywordsWarning(Warning): pass class MissingSConscriptWarning(Warning): pass class NoMD5ModuleWarning(Warning): pass class NoMetaclassSupportWarning(Warning): pass class NoObjectCountWarning(Warning): pass class NoParallelSupportWarning(Warning): pass class PythonVersionWarning(DeprecatedWarning): pass class ReservedVariableWarning(Warning): pass class StackSizeWarning(Warning): pass class TaskmasterNeedsExecuteWarning(FutureDeprecatedWarning): pass class VisualCMissingWarning(Warning): pass class VisualStudioMissingWarning(Warning): pass class FortranCxxMixWarning(LinkWarning): pass _warningAsException = 0 # The below is a list of 2-tuples. The first element is a class object. # The second element is true if that class is enabled, false if it is disabled. _enabled = [] _warningOut = None def suppressWarningClass(clazz): """Suppresses all warnings that are of type clazz or derived from clazz.""" _enabled.insert(0, (clazz, 0)) def enableWarningClass(clazz): """Suppresses all warnings that are of type clazz or derived from clazz.""" _enabled.insert(0, (clazz, 1)) def warningAsException(flag=1): """Turn warnings into exceptions. Returns the old value of the flag.""" global _warningAsException old = _warningAsException _warningAsException = flag return old def warn(clazz, *args): global _enabled, _warningAsException, _warningOut warning = clazz(args) for clazz, flag in _enabled: if isinstance(warning, clazz): if flag: if _warningAsException: raise warning if _warningOut: _warningOut(warning) break def process_warn_strings(arguments): """Process string specifications of enabling/disabling warnings, as passed to the --warn option or the SetOption('warn') function. An argument to this option should be of the form or no-. The warning class is munged in order to get an actual class name from the classes above, which we need to pass to the {enable,disable}WarningClass() functions. The supplied is split on hyphens, each element is capitalized, then smushed back together. Then the string "Warning" is appended to get the class name. For example, 'deprecated' will enable the DeprecatedWarning class. 'no-dependency' will disable the .DependencyWarning class. As a special case, --warn=all and --warn=no-all will enable or disable (respectively) the base Warning class of all warnings. """ def _capitalize(s): if s[:5] == "scons": return "SCons" + s[5:] else: return string.capitalize(s) for arg in arguments: elems = string.split(string.lower(arg), '-') enable = 1 if elems[0] == 'no': enable = 0 del elems[0] if len(elems) == 1 and elems[0] == 'all': class_name = "Warning" else: class_name = string.join(map(_capitalize, elems), '') + "Warning" try: clazz = globals()[class_name] except KeyError: sys.stderr.write("No warning type: '%s'\n" % arg) else: if enable: enableWarningClass(clazz) elif issubclass(clazz, MandatoryDeprecatedWarning): fmt = "Can not disable mandataory warning: '%s'\n" sys.stderr.write(fmt % arg) else: suppressWarningClass(clazz) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Node/0000755000175000017500000000000013606712377020251 5ustar kurtkurtpivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Node/Alias.py0000644000175000017500000001025313606712377021655 0ustar kurtkurt """scons.Node.Alias Alias nodes. This creates a hash of global Aliases (dummy targets). """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Node/Alias.py 4369 2009/09/19 15:58:29 scons" import string import UserDict import SCons.Errors import SCons.Node import SCons.Util class AliasNameSpace(UserDict.UserDict): def Alias(self, name, **kw): if isinstance(name, SCons.Node.Alias.Alias): return name try: a = self[name] except KeyError: a = SCons.Node.Alias.Alias(*(name,), **kw) self[name] = a return a def lookup(self, name, **kw): try: return self[name] except KeyError: return None class AliasNodeInfo(SCons.Node.NodeInfoBase): current_version_id = 1 field_list = ['csig'] def str_to_node(self, s): return default_ans.Alias(s) class AliasBuildInfo(SCons.Node.BuildInfoBase): current_version_id = 1 class Alias(SCons.Node.Node): NodeInfo = AliasNodeInfo BuildInfo = AliasBuildInfo def __init__(self, name): SCons.Node.Node.__init__(self) self.name = name def str_for_display(self): return '"' + self.__str__() + '"' def __str__(self): return self.name def make_ready(self): self.get_csig() really_build = SCons.Node.Node.build is_up_to_date = SCons.Node.Node.children_are_up_to_date def is_under(self, dir): # Make Alias nodes get built regardless of # what directory scons was run from. Alias nodes # are outside the filesystem: return 1 def get_contents(self): """The contents of an alias is the concatenation of the content signatures of all its sources.""" childsigs = map(lambda n: n.get_csig(), self.children()) return string.join(childsigs, '') def sconsign(self): """An Alias is not recorded in .sconsign files""" pass # # # def changed_since_last_build(self, target, prev_ni): cur_csig = self.get_csig() try: return cur_csig != prev_ni.csig except AttributeError: return 1 def build(self): """A "builder" for aliases.""" pass def convert(self): try: del self.builder except AttributeError: pass self.reset_executor() self.build = self.really_build def get_csig(self): """ Generate a node's content signature, the digested signature of its content. node - the node cache - alternate node to use for the signature cache returns - the content signature """ try: return self.ninfo.csig except AttributeError: pass contents = self.get_contents() csig = SCons.Util.MD5signature(contents) self.get_ninfo().csig = csig return csig default_ans = AliasNameSpace() SCons.Node.arg2nodes_lookups.append(default_ans.lookup) # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Node/__init__.py0000644000175000017500000013530113606712377022365 0ustar kurtkurt"""SCons.Node The Node package for the SCons software construction utility. This is, in many ways, the heart of SCons. A Node is where we encapsulate all of the dependency information about any thing that SCons can build, or about any thing which SCons can use to build some other thing. The canonical "thing," of course, is a file, but a Node can also represent something remote (like a web page) or something completely abstract (like an Alias). Each specific type of "thing" is specifically represented by a subclass of the Node base class: Node.FS.File for files, Node.Alias for aliases, etc. Dependency information is kept here in the base class, and information specific to files/aliases/etc. is in the subclass. The goal, if we've done this correctly, is that any type of "thing" should be able to depend on any other type of "thing." """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Node/__init__.py 4369 2009/09/19 15:58:29 scons" import copy from itertools import chain, izip import string import UserList from SCons.Debug import logInstanceCreation import SCons.Executor import SCons.Memoize import SCons.Util from SCons.Debug import Trace def classname(obj): return string.split(str(obj.__class__), '.')[-1] # Node states # # These are in "priority" order, so that the maximum value for any # child/dependency of a node represents the state of that node if # it has no builder of its own. The canonical example is a file # system directory, which is only up to date if all of its children # were up to date. no_state = 0 pending = 1 executing = 2 up_to_date = 3 executed = 4 failed = 5 StateString = { 0 : "no_state", 1 : "pending", 2 : "executing", 3 : "up_to_date", 4 : "executed", 5 : "failed", } # controls whether implicit dependencies are cached: implicit_cache = 0 # controls whether implicit dep changes are ignored: implicit_deps_unchanged = 0 # controls whether the cached implicit deps are ignored: implicit_deps_changed = 0 # A variable that can be set to an interface-specific function be called # to annotate a Node with information about its creation. def do_nothing(node): pass Annotate = do_nothing # Classes for signature info for Nodes. class NodeInfoBase: """ The generic base class for signature information for a Node. Node subclasses should subclass NodeInfoBase to provide their own logic for dealing with their own Node-specific signature information. """ current_version_id = 1 def __init__(self, node): # Create an object attribute from the class attribute so it ends up # in the pickled data in the .sconsign file. self._version_id = self.current_version_id def update(self, node): try: field_list = self.field_list except AttributeError: return for f in field_list: try: delattr(self, f) except AttributeError: pass try: func = getattr(node, 'get_' + f) except AttributeError: pass else: setattr(self, f, func()) def convert(self, node, val): pass def merge(self, other): self.__dict__.update(other.__dict__) def format(self, field_list=None, names=0): if field_list is None: try: field_list = self.field_list except AttributeError: field_list = sorted(self.__dict__.keys()) fields = [] for field in field_list: try: f = getattr(self, field) except AttributeError: f = None f = str(f) if names: f = field + ': ' + f fields.append(f) return fields class BuildInfoBase: """ The generic base class for build information for a Node. This is what gets stored in a .sconsign file for each target file. It contains a NodeInfo instance for this node (signature information that's specific to the type of Node) and direct attributes for the generic build stuff we have to track: sources, explicit dependencies, implicit dependencies, and action information. """ current_version_id = 1 def __init__(self, node): # Create an object attribute from the class attribute so it ends up # in the pickled data in the .sconsign file. self._version_id = self.current_version_id self.bsourcesigs = [] self.bdependsigs = [] self.bimplicitsigs = [] self.bactsig = None def merge(self, other): self.__dict__.update(other.__dict__) class Node: """The base Node class, for entities that we know how to build, or use to build other Nodes. """ if SCons.Memoize.use_memoizer: __metaclass__ = SCons.Memoize.Memoized_Metaclass memoizer_counters = [] class Attrs: pass def __init__(self): if __debug__: logInstanceCreation(self, 'Node.Node') # Note that we no longer explicitly initialize a self.builder # attribute to None here. That's because the self.builder # attribute may be created on-the-fly later by a subclass (the # canonical example being a builder to fetch a file from a # source code system like CVS or Subversion). # Each list of children that we maintain is accompanied by a # dictionary used to look up quickly whether a node is already # present in the list. Empirical tests showed that it was # fastest to maintain them as side-by-side Node attributes in # this way, instead of wrapping up each list+dictionary pair in # a class. (Of course, we could always still do that in the # future if we had a good reason to...). self.sources = [] # source files used to build node self.sources_set = set() self._specific_sources = False self.depends = [] # explicit dependencies (from Depends) self.depends_set = set() self.ignore = [] # dependencies to ignore self.ignore_set = set() self.prerequisites = SCons.Util.UniqueList() self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) self.waiting_parents = set() self.waiting_s_e = set() self.ref_count = 0 self.wkids = None # Kids yet to walk, when it's an array self.env = None self.state = no_state self.precious = None self.noclean = 0 self.nocache = 0 self.always_build = None self.includes = None self.attributes = self.Attrs() # Generic place to stick information about the Node. self.side_effect = 0 # true iff this node is a side effect self.side_effects = [] # the side effects of building this target self.linked = 0 # is this node linked to the variant directory? self.clear_memoized_values() # Let the interface in which the build engine is embedded # annotate this Node with its own info (like a description of # what line in what file created the node, for example). Annotate(self) def disambiguate(self, must_exist=None): return self def get_suffix(self): return '' memoizer_counters.append(SCons.Memoize.CountValue('get_build_env')) def get_build_env(self): """Fetch the appropriate Environment to build this node. """ try: return self._memo['get_build_env'] except KeyError: pass result = self.get_executor().get_build_env() self._memo['get_build_env'] = result return result def get_build_scanner_path(self, scanner): """Fetch the appropriate scanner path for this node.""" return self.get_executor().get_build_scanner_path(scanner) def set_executor(self, executor): """Set the action executor for this node.""" self.executor = executor def get_executor(self, create=1): """Fetch the action executor for this node. Create one if there isn't already one, and requested to do so.""" try: executor = self.executor except AttributeError: if not create: raise try: act = self.builder.action except AttributeError: executor = SCons.Executor.Null(targets=[self]) else: executor = SCons.Executor.Executor(act, self.env or self.builder.env, [self.builder.overrides], [self], self.sources) self.executor = executor return executor def executor_cleanup(self): """Let the executor clean up any cached information.""" try: executor = self.get_executor(create=None) except AttributeError: pass else: executor.cleanup() def reset_executor(self): "Remove cached executor; forces recompute when needed." try: delattr(self, 'executor') except AttributeError: pass def push_to_cache(self): """Try to push a node into a cache """ pass def retrieve_from_cache(self): """Try to retrieve the node's content from a cache This method is called from multiple threads in a parallel build, so only do thread safe stuff here. Do thread unsafe stuff in built(). Returns true iff the node was successfully retrieved. """ return 0 # # Taskmaster interface subsystem # def make_ready(self): """Get a Node ready for evaluation. This is called before the Taskmaster decides if the Node is up-to-date or not. Overriding this method allows for a Node subclass to be disambiguated if necessary, or for an implicit source builder to be attached. """ pass def prepare(self): """Prepare for this Node to be built. This is called after the Taskmaster has decided that the Node is out-of-date and must be rebuilt, but before actually calling the method to build the Node. This default implementation checks that explicit or implicit dependencies either exist or are derived, and initializes the BuildInfo structure that will hold the information about how this node is, uh, built. (The existence of source files is checked separately by the Executor, which aggregates checks for all of the targets built by a specific action.) Overriding this method allows for for a Node subclass to remove the underlying file from the file system. Note that subclass methods should call this base class method to get the child check and the BuildInfo structure. """ for d in self.depends: if d.missing(): msg = "Explicit dependency `%s' not found, needed by target `%s'." raise SCons.Errors.StopError(msg % (d, self)) if self.implicit is not None: for i in self.implicit: if i.missing(): msg = "Implicit dependency `%s' not found, needed by target `%s'." raise SCons.Errors.StopError(msg % (i, self)) self.binfo = self.get_binfo() def build(self, **kw): """Actually build the node. This is called by the Taskmaster after it's decided that the Node is out-of-date and must be rebuilt, and after the prepare() method has gotten everything, uh, prepared. This method is called from multiple threads in a parallel build, so only do thread safe stuff here. Do thread unsafe stuff in built(). """ try: self.get_executor()(*(self,), **kw) except SCons.Errors.BuildError as e: e.node = self raise def built(self): """Called just after this node is successfully built.""" # Clear the implicit dependency caches of any Nodes # waiting for this Node to be built. for parent in self.waiting_parents: parent.implicit = None self.clear() self.ninfo.update(self) def visited(self): """Called just after this node has been visited (with or without a build).""" try: binfo = self.binfo except AttributeError: # Apparently this node doesn't need build info, so # don't bother calculating or storing it. pass else: self.ninfo.update(self) self.store_info() # # # def add_to_waiting_s_e(self, node): self.waiting_s_e.add(node) def add_to_waiting_parents(self, node): """ Returns the number of nodes added to our waiting parents list: 1 if we add a unique waiting parent, 0 if not. (Note that the returned values are intended to be used to increment a reference count, so don't think you can "clean up" this function by using True and False instead...) """ wp = self.waiting_parents if node in wp: return 0 wp.add(node) return 1 def postprocess(self): """Clean up anything we don't need to hang onto after we've been built.""" self.executor_cleanup() self.waiting_parents = set() def clear(self): """Completely clear a Node of all its cached state (so that it can be re-evaluated by interfaces that do continuous integration builds). """ # The del_binfo() call here isn't necessary for normal execution, # but is for interactive mode, where we might rebuild the same # target and need to start from scratch. self.del_binfo() self.clear_memoized_values() self.ninfo = self.new_ninfo() self.executor_cleanup() try: delattr(self, '_calculated_sig') except AttributeError: pass self.includes = None def clear_memoized_values(self): self._memo = {} def builder_set(self, builder): self.builder = builder try: del self.executor except AttributeError: pass def has_builder(self): """Return whether this Node has a builder or not. In Boolean tests, this turns out to be a *lot* more efficient than simply examining the builder attribute directly ("if node.builder: ..."). When the builder attribute is examined directly, it ends up calling __getattr__ for both the __len__ and __nonzero__ attributes on instances of our Builder Proxy class(es), generating a bazillion extra calls and slowing things down immensely. """ try: b = self.builder except AttributeError: # There was no explicit builder for this Node, so initialize # the self.builder attribute to None now. b = self.builder = None return b is not None def set_explicit(self, is_explicit): self.is_explicit = is_explicit def has_explicit_builder(self): """Return whether this Node has an explicit builder This allows an internal Builder created by SCons to be marked non-explicit, so that it can be overridden by an explicit builder that the user supplies (the canonical example being directories).""" try: return self.is_explicit except AttributeError: self.is_explicit = None return self.is_explicit def get_builder(self, default_builder=None): """Return the set builder, or a specified default value""" try: return self.builder except AttributeError: return default_builder multiple_side_effect_has_builder = has_builder def is_derived(self): """ Returns true iff this node is derived (i.e. built). This should return true only for nodes whose path should be in the variant directory when duplicate=0 and should contribute their build signatures when they are used as source files to other derived files. For example: source with source builders are not derived in this sense, and hence should not return true. """ return self.has_builder() or self.side_effect def alter_targets(self): """Return a list of alternate targets for this Node. """ return [], None def get_found_includes(self, env, scanner, path): """Return the scanned include lines (implicit dependencies) found in this node. The default is no implicit dependencies. We expect this method to be overridden by any subclass that can be scanned for implicit dependencies. """ return [] def get_implicit_deps(self, env, scanner, path): """Return a list of implicit dependencies for this node. This method exists to handle recursive invocation of the scanner on the implicit dependencies returned by the scanner, if the scanner's recursive flag says that we should. """ if not scanner: return [] # Give the scanner a chance to select a more specific scanner # for this Node. #scanner = scanner.select(self) nodes = [self] seen = {} seen[self] = 1 deps = [] while nodes: n = nodes.pop(0) d = filter(lambda x, seen=seen: x not in seen, n.get_found_includes(env, scanner, path)) if d: deps.extend(d) for n in d: seen[n] = 1 nodes.extend(scanner.recurse_nodes(d)) return deps def get_env_scanner(self, env, kw={}): return env.get_scanner(self.scanner_key()) def get_target_scanner(self): return self.builder.target_scanner def get_source_scanner(self, node): """Fetch the source scanner for the specified node NOTE: "self" is the target being built, "node" is the source file for which we want to fetch the scanner. Implies self.has_builder() is true; again, expect to only be called from locations where this is already verified. This function may be called very often; it attempts to cache the scanner found to improve performance. """ scanner = None try: scanner = self.builder.source_scanner except AttributeError: pass if not scanner: # The builder didn't have an explicit scanner, so go look up # a scanner from env['SCANNERS'] based on the node's scanner # key (usually the file extension). scanner = self.get_env_scanner(self.get_build_env()) if scanner: scanner = scanner.select(node) return scanner def add_to_implicit(self, deps): if not hasattr(self, 'implicit') or self.implicit is None: self.implicit = [] self.implicit_set = set() self._children_reset() self._add_child(self.implicit, self.implicit_set, deps) def scan(self): """Scan this node's dependents for implicit dependencies.""" # Don't bother scanning non-derived files, because we don't # care what their dependencies are. # Don't scan again, if we already have scanned. if self.implicit is not None: return self.implicit = [] self.implicit_set = set() self._children_reset() if not self.has_builder(): return build_env = self.get_build_env() executor = self.get_executor() # Here's where we implement --implicit-cache. if implicit_cache and not implicit_deps_changed: implicit = self.get_stored_implicit() if implicit is not None: # We now add the implicit dependencies returned from the # stored .sconsign entry to have already been converted # to Nodes for us. (We used to run them through a # source_factory function here.) # Update all of the targets with them. This # essentially short-circuits an N*M scan of the # sources for each individual target, which is a hell # of a lot more efficient. for tgt in executor.get_all_targets(): tgt.add_to_implicit(implicit) if implicit_deps_unchanged or self.is_up_to_date(): return # one of this node's sources has changed, # so we must recalculate the implicit deps: self.implicit = [] self.implicit_set = set() # Have the executor scan the sources. executor.scan_sources(self.builder.source_scanner) # If there's a target scanner, have the executor scan the target # node itself and associated targets that might be built. scanner = self.get_target_scanner() if scanner: executor.scan_targets(scanner) def scanner_key(self): return None def select_scanner(self, scanner): """Selects a scanner for this Node. This is a separate method so it can be overridden by Node subclasses (specifically, Node.FS.Dir) that *must* use their own Scanner and don't select one the Scanner.Selector that's configured for the target. """ return scanner.select(self) def env_set(self, env, safe=0): if safe and self.env: return self.env = env # # SIGNATURE SUBSYSTEM # NodeInfo = NodeInfoBase BuildInfo = BuildInfoBase def new_ninfo(self): ninfo = self.NodeInfo(self) return ninfo def get_ninfo(self): try: return self.ninfo except AttributeError: self.ninfo = self.new_ninfo() return self.ninfo def new_binfo(self): binfo = self.BuildInfo(self) return binfo def get_binfo(self): """ Fetch a node's build information. node - the node whose sources will be collected cache - alternate node to use for the signature cache returns - the build signature This no longer handles the recursive descent of the node's children's signatures. We expect that they're already built and updated by someone else, if that's what's wanted. """ try: return self.binfo except AttributeError: pass binfo = self.new_binfo() self.binfo = binfo executor = self.get_executor() ignore_set = self.ignore_set if self.has_builder(): binfo.bact = str(executor) binfo.bactsig = SCons.Util.MD5signature(executor.get_contents()) if self._specific_sources: sources = [] for s in self.sources: if s not in ignore_set: sources.append(s) else: sources = executor.get_unignored_sources(self, self.ignore) seen = set() bsources = [] bsourcesigs = [] for s in sources: if not s in seen: seen.add(s) bsources.append(s) bsourcesigs.append(s.get_ninfo()) binfo.bsources = bsources binfo.bsourcesigs = bsourcesigs depends = self.depends dependsigs = [] for d in depends: if d not in ignore_set: dependsigs.append(d.get_ninfo()) binfo.bdepends = depends binfo.bdependsigs = dependsigs implicit = self.implicit or [] implicitsigs = [] for i in implicit: if i not in ignore_set: implicitsigs.append(i.get_ninfo()) binfo.bimplicit = implicit binfo.bimplicitsigs = implicitsigs return binfo def del_binfo(self): """Delete the build info from this node.""" try: delattr(self, 'binfo') except AttributeError: pass def get_csig(self): try: return self.ninfo.csig except AttributeError: ninfo = self.get_ninfo() ninfo.csig = SCons.Util.MD5signature(self.get_contents()) return self.ninfo.csig def get_cachedir_csig(self): return self.get_csig() def store_info(self): """Make the build signature permanent (that is, store it in the .sconsign file or equivalent).""" pass def do_not_store_info(self): pass def get_stored_info(self): return None def get_stored_implicit(self): """Fetch the stored implicit dependencies""" return None # # # def set_precious(self, precious = 1): """Set the Node's precious value.""" self.precious = precious def set_noclean(self, noclean = 1): """Set the Node's noclean value.""" # Make sure noclean is an integer so the --debug=stree # output in Util.py can use it as an index. self.noclean = noclean and 1 or 0 def set_nocache(self, nocache = 1): """Set the Node's nocache value.""" # Make sure nocache is an integer so the --debug=stree # output in Util.py can use it as an index. self.nocache = nocache and 1 or 0 def set_always_build(self, always_build = 1): """Set the Node's always_build value.""" self.always_build = always_build def exists(self): """Does this node exists?""" # All node exist by default: return 1 def rexists(self): """Does this node exist locally or in a repositiory?""" # There are no repositories by default: return self.exists() def missing(self): return not self.is_derived() and \ not self.linked and \ not self.rexists() def remove(self): """Remove this Node: no-op by default.""" return None def add_dependency(self, depend): """Adds dependencies.""" try: self._add_child(self.depends, self.depends_set, depend) except TypeError as e: e = e.args[0] if SCons.Util.is_List(e): s = map(str, e) else: s = str(e) raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) def add_prerequisite(self, prerequisite): """Adds prerequisites""" self.prerequisites.extend(prerequisite) self._children_reset() def add_ignore(self, depend): """Adds dependencies to ignore.""" try: self._add_child(self.ignore, self.ignore_set, depend) except TypeError as e: e = e.args[0] if SCons.Util.is_List(e): s = map(str, e) else: s = str(e) raise SCons.Errors.UserError("attempted to ignore a non-Node dependency of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) def add_source(self, source): """Adds sources.""" if self._specific_sources: return try: self._add_child(self.sources, self.sources_set, source) except TypeError as e: e = e.args[0] if SCons.Util.is_List(e): s = map(str, e) else: s = str(e) raise SCons.Errors.UserError("attempted to add a non-Node as source of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e))) def _add_child(self, collection, set, child): """Adds 'child' to 'collection', first checking 'set' to see if it's already present.""" #if type(child) is not type([]): # child = [child] #for c in child: # if not isinstance(c, Node): # raise TypeError, c added = None for c in child: if c not in set: set.add(c) collection.append(c) added = 1 if added: self._children_reset() def set_specific_source(self, source): self.add_source(source) self._specific_sources = True def add_wkid(self, wkid): """Add a node to the list of kids waiting to be evaluated""" if self.wkids is not None: self.wkids.append(wkid) def _children_reset(self): self.clear_memoized_values() # We need to let the Executor clear out any calculated # build info that it's cached so we can re-calculate it. self.executor_cleanup() memoizer_counters.append(SCons.Memoize.CountValue('_children_get')) def _children_get(self): try: return self._memo['children_get'] except KeyError: pass # The return list may contain duplicate Nodes, especially in # source trees where there are a lot of repeated #includes # of a tangle of .h files. Profiling shows, however, that # eliminating the duplicates with a brute-force approach that # preserves the order (that is, something like: # # u = [] # for n in list: # if n not in u: # u.append(n)" # # takes more cycles than just letting the underlying methods # hand back cached values if a Node's information is requested # multiple times. (Other methods of removing duplicates, like # using dictionary keys, lose the order, and the only ordered # dictionary patterns I found all ended up using "not in" # internally anyway...) if self.ignore_set: if self.implicit is None: iter = chain(self.sources,self.depends) else: iter = chain(self.sources, self.depends, self.implicit) children = [] for i in iter: if i not in self.ignore_set: children.append(i) else: if self.implicit is None: children = self.sources + self.depends else: children = self.sources + self.depends + self.implicit self._memo['children_get'] = children return children def all_children(self, scan=1): """Return a list of all the node's direct children.""" if scan: self.scan() # The return list may contain duplicate Nodes, especially in # source trees where there are a lot of repeated #includes # of a tangle of .h files. Profiling shows, however, that # eliminating the duplicates with a brute-force approach that # preserves the order (that is, something like: # # u = [] # for n in list: # if n not in u: # u.append(n)" # # takes more cycles than just letting the underlying methods # hand back cached values if a Node's information is requested # multiple times. (Other methods of removing duplicates, like # using dictionary keys, lose the order, and the only ordered # dictionary patterns I found all ended up using "not in" # internally anyway...) if self.implicit is None: return self.sources + self.depends else: return self.sources + self.depends + self.implicit def children(self, scan=1): """Return a list of the node's direct children, minus those that are ignored by this node.""" if scan: self.scan() return self._children_get() def set_state(self, state): self.state = state def get_state(self): return self.state def state_has_changed(self, target, prev_ni): return (self.state != SCons.Node.up_to_date) def get_env(self): env = self.env if not env: import SCons.Defaults env = SCons.Defaults.DefaultEnvironment() return env def changed_since_last_build(self, target, prev_ni): """ Must be overridden in a specific subclass to return True if this Node (a dependency) has changed since the last time it was used to build the specified target. prev_ni is this Node's state (for example, its file timestamp, length, maybe content signature) as of the last time the target was built. Note that this method is called through the dependency, not the target, because a dependency Node must be able to use its own logic to decide if it changed. For example, File Nodes need to obey if we're configured to use timestamps, but Python Value Nodes never use timestamps and always use the content. If this method were called through the target, then each Node's implementation of this method would have to have more complicated logic to handle all the different Node types on which it might depend. """ raise NotImplementedError def Decider(self, function): SCons.Util.AddMethod(self, function, 'changed_since_last_build') def changed(self, node=None): """ Returns if the node is up-to-date with respect to the BuildInfo stored last time it was built. The default behavior is to compare it against our own previously stored BuildInfo, but the stored BuildInfo from another Node (typically one in a Repository) can be used instead. Note that we now *always* check every dependency. We used to short-circuit the check by returning as soon as we detected any difference, but we now rely on checking every dependency to make sure that any necessary Node information (for example, the content signature of an #included .h file) is updated. """ t = 0 if t: Trace('changed(%s [%s], %s)' % (self, classname(self), node)) if node is None: node = self result = False bi = node.get_stored_info().binfo then = bi.bsourcesigs + bi.bdependsigs + bi.bimplicitsigs children = self.children() diff = len(children) - len(then) if diff: # The old and new dependency lists are different lengths. # This always indicates that the Node must be rebuilt. # We also extend the old dependency list with enough None # entries to equal the new dependency list, for the benefit # of the loop below that updates node information. then.extend([None] * diff) if t: Trace(': old %s new %s' % (len(then), len(children))) result = True for child, prev_ni in izip(children, then): if child.changed_since_last_build(self, prev_ni): if t: Trace(': %s changed' % child) result = True contents = self.get_executor().get_contents() if self.has_builder(): import SCons.Util newsig = SCons.Util.MD5signature(contents) if bi.bactsig != newsig: if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig)) result = True if not result: if t: Trace(': up to date') if t: Trace('\n') return result def is_up_to_date(self): """Default check for whether the Node is current: unknown Node subtypes are always out of date, so they will always get built.""" return None def children_are_up_to_date(self): """Alternate check for whether the Node is current: If all of our children were up-to-date, then this Node was up-to-date, too. The SCons.Node.Alias and SCons.Node.Python.Value subclasses rebind their current() method to this method.""" # Allow the children to calculate their signatures. self.binfo = self.get_binfo() if self.always_build: return None state = 0 for kid in self.children(None): s = kid.get_state() if s and (not state or s > state): state = s return (state == 0 or state == SCons.Node.up_to_date) def is_literal(self): """Always pass the string representation of a Node to the command interpreter literally.""" return 1 def render_include_tree(self): """ Return a text representation, suitable for displaying to the user, of the include tree for the sources of this node. """ if self.is_derived() and self.env: env = self.get_build_env() for s in self.sources: scanner = self.get_source_scanner(s) if scanner: path = self.get_build_scanner_path(scanner) else: path = None def f(node, env=env, scanner=scanner, path=path): return node.get_found_includes(env, scanner, path) return SCons.Util.render_tree(s, f, 1) else: return None def get_abspath(self): """ Return an absolute path to the Node. This will return simply str(Node) by default, but for Node types that have a concept of relative path, this might return something different. """ return str(self) def for_signature(self): """ Return a string representation of the Node that will always be the same for this particular Node, no matter what. This is by contrast to the __str__() method, which might, for instance, return a relative path for a file Node. The purpose of this method is to generate a value to be used in signature calculation for the command line used to build a target, and we use this method instead of str() to avoid unnecessary rebuilds. This method does not need to return something that would actually work in a command line; it can return any kind of nonsense, so long as it does not change. """ return str(self) def get_string(self, for_signature): """This is a convenience function designed primarily to be used in command generators (i.e., CommandGeneratorActions or Environment variables that are callable), which are called with a for_signature argument that is nonzero if the command generator is being called to generate a signature for the command line, which determines if we should rebuild or not. Such command generators should use this method in preference to str(Node) when converting a Node to a string, passing in the for_signature parameter, such that we will call Node.for_signature() or str(Node) properly, depending on whether we are calculating a signature or actually constructing a command line.""" if for_signature: return self.for_signature() return str(self) def get_subst_proxy(self): """ This method is expected to return an object that will function exactly like this Node, except that it implements any additional special features that we would like to be in effect for Environment variable substitution. The principle use is that some Nodes would like to implement a __getattr__() method, but putting that in the Node type itself has a tendency to kill performance. We instead put it in a proxy and return it from this method. It is legal for this method to return self if no new functionality is needed for Environment substitution. """ return self def explain(self): if not self.exists(): return "building `%s' because it doesn't exist\n" % self if self.always_build: return "rebuilding `%s' because AlwaysBuild() is specified\n" % self old = self.get_stored_info() if old is None: return None old = old.binfo old.prepare_dependencies() try: old_bkids = old.bsources + old.bdepends + old.bimplicit old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs except AttributeError: return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self new = self.get_binfo() new_bkids = new.bsources + new.bdepends + new.bimplicit new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs osig = dict(izip(old_bkids, old_bkidsigs)) nsig = dict(izip(new_bkids, new_bkidsigs)) # The sources and dependencies we'll want to report are all stored # as relative paths to this target's directory, but we want to # report them relative to the top-level SConstruct directory, # so we only print them after running them through this lambda # to turn them into the right relative Node and then return # its string. def stringify( s, E=self.dir.Entry ) : if hasattr( s, 'dir' ) : return str(E(s)) return str(s) lines = [] removed = filter(lambda x, nk=new_bkids: not x in nk, old_bkids) if removed: removed = map(stringify, removed) fmt = "`%s' is no longer a dependency\n" lines.extend(map(lambda s, fmt=fmt: fmt % s, removed)) for k in new_bkids: if not k in old_bkids: lines.append("`%s' is a new dependency\n" % stringify(k)) elif k.changed_since_last_build(self, osig[k]): lines.append("`%s' changed\n" % stringify(k)) if len(lines) == 0 and old_bkids != new_bkids: lines.append("the dependency order changed:\n" + "%sold: %s\n" % (' '*15, map(stringify, old_bkids)) + "%snew: %s\n" % (' '*15, map(stringify, new_bkids))) if len(lines) == 0: def fmt_with_title(title, strlines): lines = string.split(strlines, '\n') sep = '\n' + ' '*(15 + len(title)) return ' '*15 + title + string.join(lines, sep) + '\n' if old.bactsig != new.bactsig: if old.bact == new.bact: lines.append("the contents of the build action changed\n" + fmt_with_title('action: ', new.bact)) else: lines.append("the build action changed:\n" + fmt_with_title('old: ', old.bact) + fmt_with_title('new: ', new.bact)) if len(lines) == 0: return "rebuilding `%s' for unknown reasons\n" % self preamble = "rebuilding `%s' because" % self if len(lines) == 1: return "%s %s" % (preamble, lines[0]) else: lines = ["%s:\n" % preamble] + lines return string.join(lines, ' '*11) try: [].extend(UserList.UserList([])) except TypeError: # Python 1.5.2 doesn't allow a list to be extended by list-like # objects (such as UserList instances), so just punt and use # real lists. def NodeList(l): return l else: class NodeList(UserList.UserList): def __str__(self): return str(map(str, self.data)) def get_children(node, parent): return node.children() def ignore_cycle(node, stack): pass def do_nothing(node, parent): pass class Walker: """An iterator for walking a Node tree. This is depth-first, children are visited before the parent. The Walker object can be initialized with any node, and returns the next node on the descent with each next() call. 'kids_func' is an optional function that will be called to get the children of a node instead of calling 'children'. 'cycle_func' is an optional function that will be called when a cycle is detected. This class does not get caught in node cycles caused, for example, by C header file include loops. """ def __init__(self, node, kids_func=get_children, cycle_func=ignore_cycle, eval_func=do_nothing): self.kids_func = kids_func self.cycle_func = cycle_func self.eval_func = eval_func node.wkids = copy.copy(kids_func(node, None)) self.stack = [node] self.history = {} # used to efficiently detect and avoid cycles self.history[node] = None def next(self): """Return the next node for this walk of the tree. This function is intentionally iterative, not recursive, to sidestep any issues of stack size limitations. """ while self.stack: if self.stack[-1].wkids: node = self.stack[-1].wkids.pop(0) if not self.stack[-1].wkids: self.stack[-1].wkids = None if node in self.history: self.cycle_func(node, self.stack) else: node.wkids = copy.copy(self.kids_func(node, self.stack[-1])) self.stack.append(node) self.history[node] = None else: node = self.stack.pop() del self.history[node] if node: if self.stack: parent = self.stack[-1] else: parent = None self.eval_func(node, parent) return node return None def is_done(self): return not self.stack arg2nodes_lookups = [] # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Node/Python.py0000644000175000017500000001016713606712377022111 0ustar kurtkurt"""scons.Node.Python Python nodes. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Node/Python.py 4369 2009/09/19 15:58:29 scons" import SCons.Node class ValueNodeInfo(SCons.Node.NodeInfoBase): current_version_id = 1 field_list = ['csig'] def str_to_node(self, s): return Value(s) class ValueBuildInfo(SCons.Node.BuildInfoBase): current_version_id = 1 class Value(SCons.Node.Node): """A class for Python variables, typically passed on the command line or generated by a script, but not from a file or some other source. """ NodeInfo = ValueNodeInfo BuildInfo = ValueBuildInfo def __init__(self, value, built_value=None): SCons.Node.Node.__init__(self) self.value = value if built_value is not None: self.built_value = built_value def str_for_display(self): return repr(self.value) def __str__(self): return str(self.value) def make_ready(self): self.get_csig() def build(self, **kw): if not hasattr(self, 'built_value'): SCons.Node.Node.build(*(self,), **kw) is_up_to_date = SCons.Node.Node.children_are_up_to_date def is_under(self, dir): # Make Value nodes get built regardless of # what directory scons was run from. Value nodes # are outside the filesystem: return 1 def write(self, built_value): """Set the value of the node.""" self.built_value = built_value def read(self): """Return the value. If necessary, the value is built.""" self.build() if not hasattr(self, 'built_value'): self.built_value = self.value return self.built_value def get_text_contents(self): """By the assumption that the node.built_value is a deterministic product of the sources, the contents of a Value are the concatenation of all the contents of its sources. As the value need not be built when get_contents() is called, we cannot use the actual node.built_value.""" ###TODO: something reasonable about universal newlines contents = str(self.value) for kid in self.children(None): contents = contents + kid.get_contents() return contents get_contents = get_text_contents ###TODO should return 'bytes' value def changed_since_last_build(self, target, prev_ni): cur_csig = self.get_csig() try: return cur_csig != prev_ni.csig except AttributeError: return 1 def get_csig(self, calc=None): """Because we're a Python value node and don't have a real timestamp, we get to ignore the calculator and just use the value contents.""" try: return self.ninfo.csig except AttributeError: pass contents = self.get_contents() self.get_ninfo().csig = contents return contents # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons-local-1.2.0.d20090919/SCons/Node/FS.py0000644000175000017500000033673513606712377021154 0ustar kurtkurt"""scons.Node.FS File system nodes. These Nodes represent the canonical external objects that people think of when they think of building software: files and directories. This holds a "default_fs" variable that should be initialized with an FS that can be used by scripts or modules looking for the canonical default. """ # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/engine/SCons/Node/FS.py 4369 2009/09/19 15:58:29 scons" from itertools import izip import cStringIO import fnmatch import os import os.path import re import shutil import stat import string import sys import time try: import codecs except ImportError: pass else: # TODO(2.2): Remove when 2.3 becomes the minimal supported version. try: codecs.BOM_UTF8 except AttributeError: codecs.BOM_UTF8 = '\xef\xbb\xbf' try: codecs.BOM_UTF16_LE codecs.BOM_UTF16_BE except AttributeError: codecs.BOM_UTF16_LE = '\xff\xfe' codecs.BOM_UTF16_BE = '\xfe\xff' # Provide a wrapper function to handle decoding differences in # different versions of Python. Normally, we'd try to do this in the # compat layer (and maybe it still makes sense to move there?) but # that doesn't provide a way to supply the string class used in # pre-2.3 Python versions with a .decode() method that all strings # naturally have. Plus, the 2.[01] encodings behave differently # enough that we have to settle for a lowest-common-denominator # wrapper approach. # # Note that the 2.[012] implementations below may be inefficient # because they perform an explicit look up of the encoding for every # decode, but they're old enough (and we want to stop supporting # them soon enough) that it's not worth complicating the interface. # Think of it as additional incentive for people to upgrade... try: ''.decode except AttributeError: # 2.0 through 2.2: strings have no .decode() method try: codecs.lookup('ascii').decode except AttributeError: # 2.0 and 2.1: encodings are a tuple of functions, and the # decode() function returns a (result, length) tuple. def my_decode(contents, encoding): return codecs.lookup(encoding)[1](contents)[0] else: # 2.2: encodings are an object with methods, and the # .decode() method returns just the decoded bytes. def my_decode(contents, encoding): return codecs.lookup(encoding).decode(contents) else: # 2.3 or later: use the .decode() string method def my_decode(contents, encoding): return contents.decode(encoding) import SCons.Action from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Memoize import SCons.Node import SCons.Node.Alias import SCons.Subst import SCons.Util import SCons.Warnings from SCons.Debug import Trace do_store_info = True class EntryProxyAttributeError(AttributeError): """ An AttributeError subclass for recording and displaying the name of the underlying Entry involved in an AttributeError exception. """ def __init__(self, entry_proxy, attribute): AttributeError.__init__(self) self.entry_proxy = entry_proxy self.attribute = attribute def __str__(self): entry = self.entry_proxy.get() fmt = "%s instance %s has no attribute %s" return fmt % (entry.__class__.__name__, repr(entry.name), repr(self.attribute)) # The max_drift value: by default, use a cached signature value for # any file that's been untouched for more than two days. default_max_drift = 2*24*60*60 # # We stringify these file system Nodes a lot. Turning a file system Node # into a string is non-trivial, because the final string representation # can depend on a lot of factors: whether it's a derived target or not, # whether it's linked to a repository or source directory, and whether # there's duplication going on. The normal technique for optimizing # calculations like this is to memoize (cache) the string value, so you # only have to do the calculation once. # # A number of the above factors, however, can be set after we've already # been asked to return a string for a Node, because a Repository() or # VariantDir() call or the like may not occur until later in SConscript # files. So this variable controls whether we bother trying to save # string values for Nodes. The wrapper interface can set this whenever # they're done mucking with Repository and VariantDir and the other stuff, # to let this module know it can start returning saved string values # for Nodes. # Save_Strings = None def save_strings(val): global Save_Strings Save_Strings = val # # Avoid unnecessary function calls by recording a Boolean value that # tells us whether or not os.path.splitdrive() actually does anything # on this system, and therefore whether we need to bother calling it # when looking up path names in various methods below. # do_splitdrive = None def initialize_do_splitdrive(): global do_splitdrive drive, path = os.path.splitdrive('X:/foo') do_splitdrive = not not drive initialize_do_splitdrive() # needs_normpath_check = None def initialize_normpath_check(): """ Initialize the normpath_check regular expression. This function is used by the unit tests to re-initialize the pattern when testing for behavior with different values of os.sep. """ global needs_normpath_check if os.sep == '/': pattern = r'.*/|\.$|\.\.$' else: pattern = r'.*[/%s]|\.$|\.\.$' % re.escape(os.sep) needs_normpath_check = re.compile(pattern) initialize_normpath_check() # # SCons.Action objects for interacting with the outside world. # # The Node.FS methods in this module should use these actions to # create and/or remove files and directories; they should *not* use # os.{link,symlink,unlink,mkdir}(), etc., directly. # # Using these SCons.Action objects ensures that descriptions of these # external activities are properly displayed, that the displays are # suppressed when the -s (silent) option is used, and (most importantly) # the actions are disabled when the the -n option is used, in which case # there should be *no* changes to the external file system(s)... # if hasattr(os, 'link'): def _hardlink_func(fs, src, dst): # If the source is a symlink, we can't just hard-link to it # because a relative symlink may point somewhere completely # different. We must disambiguate the symlink and then # hard-link the final destination file. while fs.islink(src): link = fs.readlink(src) if not os.path.isabs(link): src = link else: src = os.path.join(os.path.dirname(src), link) fs.link(src, dst) else: _hardlink_func = None if hasattr(os, 'symlink'): def _softlink_func(fs, src, dst): fs.symlink(src, dst) else: _softlink_func = None def _copy_func(fs, src, dest): shutil.copy2(src, dest) st = fs.stat(src) fs.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) Valid_Duplicates = ['hard-soft-copy', 'soft-hard-copy', 'hard-copy', 'soft-copy', 'copy'] Link_Funcs = [] # contains the callables of the specified duplication style def set_duplicate(duplicate): # Fill in the Link_Funcs list according to the argument # (discarding those not available on the platform). # Set up the dictionary that maps the argument names to the # underlying implementations. We do this inside this function, # not in the top-level module code, so that we can remap os.link # and os.symlink for testing purposes. link_dict = { 'hard' : _hardlink_func, 'soft' : _softlink_func, 'copy' : _copy_func } if not duplicate in Valid_Duplicates: raise SCons.Errors.InternalError("The argument of set_duplicate " "should be in Valid_Duplicates") global Link_Funcs Link_Funcs = [] for func in string.split(duplicate,'-'): if link_dict[func]: Link_Funcs.append(link_dict[func]) def LinkFunc(target, source, env): # Relative paths cause problems with symbolic links, so # we use absolute paths, which may be a problem for people # who want to move their soft-linked src-trees around. Those # people should use the 'hard-copy' mode, softlinks cannot be # used for that; at least I have no idea how ... src = source[0].abspath dest = target[0].abspath dir, file = os.path.split(dest) if dir and not target[0].fs.isdir(dir): os.makedirs(dir) if not Link_Funcs: # Set a default order of link functions. set_duplicate('hard-soft-copy') fs = source[0].fs # Now link the files with the previously specified order. for func in Link_Funcs: try: func(fs, src, dest) break except (IOError, OSError): # An OSError indicates something happened like a permissions # problem or an attempt to symlink across file-system # boundaries. An IOError indicates something like the file # not existing. In either case, keeping trying additional # functions in the list and only raise an error if the last # one failed. if func == Link_Funcs[-1]: # exception of the last link method (copy) are fatal raise return 0 Link = SCons.Action.Action(LinkFunc, None) def LocalString(target, source, env): return 'Local copy of %s from %s' % (target[0], source[0]) LocalCopy = SCons.Action.Action(LinkFunc, LocalString) def UnlinkFunc(target, source, env): t = target[0] t.fs.unlink(t.abspath) return 0 Unlink = SCons.Action.Action(UnlinkFunc, None) def MkdirFunc(target, source, env): t = target[0] if not t.exists(): t.fs.mkdir(t.abspath) return 0 Mkdir = SCons.Action.Action(MkdirFunc, None, presub=None) MkdirBuilder = None def get_MkdirBuilder(): global MkdirBuilder if MkdirBuilder is None: import SCons.Builder import SCons.Defaults # "env" will get filled in by Executor.get_build_env() # calling SCons.Defaults.DefaultEnvironment() when necessary. MkdirBuilder = SCons.Builder.Builder(action = Mkdir, env = None, explain = None, is_explicit = None, target_scanner = SCons.Defaults.DirEntryScanner, name = "MkdirBuilder") return MkdirBuilder class _Null: pass _null = _Null() DefaultSCCSBuilder = None DefaultRCSBuilder = None def get_DefaultSCCSBuilder(): global DefaultSCCSBuilder if DefaultSCCSBuilder is None: import SCons.Builder # "env" will get filled in by Executor.get_build_env() # calling SCons.Defaults.DefaultEnvironment() when necessary. act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR') DefaultSCCSBuilder = SCons.Builder.Builder(action = act, env = None, name = "DefaultSCCSBuilder") return DefaultSCCSBuilder def get_DefaultRCSBuilder(): global DefaultRCSBuilder if DefaultRCSBuilder is None: import SCons.Builder # "env" will get filled in by Executor.get_build_env() # calling SCons.Defaults.DefaultEnvironment() when necessary. act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR') DefaultRCSBuilder = SCons.Builder.Builder(action = act, env = None, name = "DefaultRCSBuilder") return DefaultRCSBuilder # Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem. _is_cygwin = sys.platform == "cygwin" if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin: def _my_normcase(x): return x else: def _my_normcase(x): return string.upper(x) class DiskChecker: def __init__(self, type, do, ignore): self.type = type self.do = do self.ignore = ignore self.set_do() def set_do(self): self.__call__ = self.do def set_ignore(self): self.__call__ = self.ignore def set(self, list): if self.type in list: self.set_do() else: self.set_ignore() def do_diskcheck_match(node, predicate, errorfmt): result = predicate() try: # If calling the predicate() cached a None value from stat(), # remove it so it doesn't interfere with later attempts to # build this Node as we walk the DAG. (This isn't a great way # to do this, we're reaching into an interface that doesn't # really belong to us, but it's all about performance, so # for now we'll just document the dependency...) if node._memo['stat'] is None: del node._memo['stat'] except (AttributeError, KeyError): pass if result: raise TypeError(errorfmt % node.abspath) def ignore_diskcheck_match(node, predicate, errorfmt): pass def do_diskcheck_rcs(node, name): try: rcs_dir = node.rcs_dir except AttributeError: if node.entry_exists_on_disk('RCS'): rcs_dir = node.Dir('RCS') else: rcs_dir = None node.rcs_dir = rcs_dir if rcs_dir: return rcs_dir.entry_exists_on_disk(name+',v') return None def ignore_diskcheck_rcs(node, name): return None def do_diskcheck_sccs(node, name): try: sccs_dir = node.sccs_dir except AttributeError: if node.entry_exists_on_disk('SCCS'): sccs_dir = node.Dir('SCCS') else: sccs_dir = None node.sccs_dir = sccs_dir if sccs_dir: return sccs_dir.entry_exists_on_disk('s.'+name) return None def ignore_diskcheck_sccs(node, name): return None diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match) diskcheck_rcs = DiskChecker('rcs', do_diskcheck_rcs, ignore_diskcheck_rcs) diskcheck_sccs = DiskChecker('sccs', do_diskcheck_sccs, ignore_diskcheck_sccs) diskcheckers = [ diskcheck_match, diskcheck_rcs, diskcheck_sccs, ] def set_diskcheck(list): for dc in diskcheckers: dc.set(list) def diskcheck_types(): return map(lambda dc: dc.type, diskcheckers) class EntryProxy(SCons.Util.Proxy): def __get_abspath(self): entry = self.get() return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(), entry.name + "_abspath") def __get_filebase(self): name = self.get().name return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[0], name + "_filebase") def __get_suffix(self): name = self.get().name return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[1], name + "_suffix") def __get_file(self): name = self.get().name return SCons.Subst.SpecialAttrWrapper(name, name + "_file") def __get_base_path(self): """Return the file's directory and file name, with the suffix stripped.""" entry = self.get() return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(entry.get_path())[0], entry.name + "_base") def __get_posix_path(self): """Return the path with / as the path separator, regardless of platform.""" if os.sep == '/': return self else: entry = self.get() r = string.replace(entry.get_path(), os.sep, '/') return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix") def __get_windows_path(self): """Return the path with \ as the path separator, regardless of platform.""" if os.sep == '\\': return self else: entry = self.get() r = string.replace(entry.get_path(), os.sep, '\\') return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_windows") def __get_srcnode(self): return EntryProxy(self.get().srcnode()) def __get_srcdir(self): """Returns the directory containing the source node linked to this node via VariantDir(), or the directory of this node if not linked.""" return EntryProxy(self.get().srcnode().dir) def __get_rsrcnode(self): return EntryProxy(self.get().srcnode().rfile()) def __get_rsrcdir(self): """Returns the directory containing the source node linked to this node via VariantDir(), or the directory of this node if not linked.""" return EntryProxy(self.get().srcnode().rfile().dir) def __get_dir(self): return EntryProxy(self.get().dir) dictSpecialAttrs = { "base" : __get_base_path, "posix" : __get_posix_path, "windows" : __get_windows_path, "win32" : __get_windows_path, "srcpath" : __get_srcnode, "srcdir" : __get_srcdir, "dir" : __get_dir, "abspath" : __get_abspath, "filebase" : __get_filebase, "suffix" : __get_suffix, "file" : __get_file, "rsrcpath" : __get_rsrcnode, "rsrcdir" : __get_rsrcdir, } def __getattr__(self, name): # This is how we implement the "special" attributes # such as base, posix, srcdir, etc. try: attr_function = self.dictSpecialAttrs[name] except KeyError: try: attr = SCons.Util.Proxy.__getattr__(self, name) except AttributeError as e: # Raise our own AttributeError subclass with an # overridden __str__() method that identifies the # name of the entry that caused the exception. raise EntryProxyAttributeError(self, name) return attr else: return attr_function(self) class Base(SCons.Node.Node): """A generic class for file system entries. This class is for when we don't know yet whether the entry being looked up is a file or a directory. Instances of this class can morph into either Dir or File objects by a later, more precise lookup. Note: this class does not define __cmp__ and __hash__ for efficiency reasons. SCons does a lot of comparing of Node.FS.{Base,Entry,File,Dir} objects, so those operations must be as fast as possible, which means we want to use Python's built-in object identity comparisons. """ memoizer_counters = [] def __init__(self, name, directory, fs): """Initialize a generic Node.FS.Base object. Call the superclass initialization, take care of setting up our relative and absolute paths, identify our parent directory, and indicate that this node should use signatures.""" if __debug__: logInstanceCreation(self, 'Node.FS.Base') SCons.Node.Node.__init__(self) # Filenames and paths are probably reused and are intern'ed to # save some memory. self.name = SCons.Util.silent_intern(name) self.suffix = SCons.Util.silent_intern(SCons.Util.splitext(name)[1]) self.fs = fs assert directory, "A directory must be provided" self.abspath = SCons.Util.silent_intern(directory.entry_abspath(name)) self.labspath = SCons.Util.silent_intern(directory.entry_labspath(name)) if directory.path == '.': self.path = SCons.Util.silent_intern(name) else: self.path = SCons.Util.silent_intern(directory.entry_path(name)) if directory.tpath == '.': self.tpath = SCons.Util.silent_intern(name) else: self.tpath = SCons.Util.silent_intern(directory.entry_tpath(name)) self.path_elements = directory.path_elements + [self] self.dir = directory self.cwd = None # will hold the SConscript directory for target nodes self.duplicate = directory.duplicate def str_for_display(self): return '"' + self.__str__() + '"' def must_be_same(self, klass): """ This node, which already existed, is being looked up as the specified klass. Raise an exception if it isn't. """ if isinstance(self, klass) or klass is Entry: return raise TypeError("Tried to lookup %s '%s' as a %s." %\ (self.__class__.__name__, self.path, klass.__name__)) def get_dir(self): return self.dir def get_suffix(self): return self.suffix def rfile(self): return self def __str__(self): """A Node.FS.Base object's string representation is its path name.""" global Save_Strings if Save_Strings: return self._save_str() return self._get_str() memoizer_counters.append(SCons.Memoize.CountValue('_save_str')) def _save_str(self): try: return self._memo['_save_str'] except KeyError: pass result = sys.intern(self._get_str()) self._memo['_save_str'] = result return result def _get_str(self): global Save_Strings if self.duplicate or self.is_derived(): return self.get_path() srcnode = self.srcnode() if srcnode.stat() is None and self.stat() is not None: result = self.get_path() else: result = srcnode.get_path() if not Save_Strings: # We're not at the point where we're saving the string string # representations of FS Nodes (because we haven't finished # reading the SConscript files and need to have str() return # things relative to them). That also means we can't yet # cache values returned (or not returned) by stat(), since # Python code in the SConscript files might still create # or otherwise affect the on-disk file. So get rid of the # values that the underlying stat() method saved. try: del self._memo['stat'] except KeyError: pass if self is not srcnode: try: del srcnode._memo['stat'] except KeyError: pass return result rstr = __str__ memoizer_counters.append(SCons.Memoize.CountValue('stat')) def stat(self): try: return self._memo['stat'] except KeyError: pass try: result = self.fs.stat(self.abspath) except os.error: result = None self._memo['stat'] = result return result def exists(self): return self.stat() is not None def rexists(self): return self.rfile().exists() def getmtime(self): st = self.stat() if st: return st[stat.ST_MTIME] else: return None def getsize(self): st = self.stat() if st: return st[stat.ST_SIZE] else: return None def isdir(self): st = self.stat() return st is not None and stat.S_ISDIR(st[stat.ST_MODE]) def isfile(self): st = self.stat() return st is not None and stat.S_ISREG(st[stat.ST_MODE]) if hasattr(os, 'symlink'): def islink(self): try: st = self.fs.lstat(self.abspath) except os.error: return 0 return stat.S_ISLNK(st[stat.ST_MODE]) else: def islink(self): return 0 # no symlinks def is_under(self, dir): if self is dir: return 1 else: return self.dir.is_under(dir) def set_local(self): self._local = 1 def srcnode(self): """If this node is in a build path, return the node corresponding to its source file. Otherwise, return ourself. """ srcdir_list = self.dir.srcdir_list() if srcdir_list: srcnode = srcdir_list[0].Entry(self.name) srcnode.must_be_same(self.__class__) return srcnode return self def get_path(self, dir=None): """Return path relative to the current working directory of the Node.FS.Base object that owns us.""" if not dir: dir = self.fs.getcwd() if self == dir: return '.' path_elems = self.path_elements try: i = path_elems.index(dir) except ValueError: pass else: path_elems = path_elems[i+1:] path_elems = map(lambda n: n.name, path_elems) return string.join(path_elems, os.sep) def set_src_builder(self, builder): """Set the source code builder for this node.""" self.sbuilder = builder if not self.has_builder(): self.builder_set(builder) def src_builder(self): """Fetch the source code builder for this node. If there isn't one, we cache the source code builder specified for the directory (which in turn will cache the value from its parent directory, and so on up to the file system root). """ try: scb = self.sbuilder except AttributeError: scb = self.dir.src_builder() self.sbuilder = scb return scb def get_abspath(self): """Get the absolute path of the file.""" return self.abspath def for_signature(self): # Return just our name. Even an absolute path would not work, # because that can change thanks to symlinks or remapped network # paths. return self.name def get_subst_proxy(self): try: return self._proxy except AttributeError: ret = EntryProxy(self) self._proxy = ret return ret def target_from_source(self, prefix, suffix, splitext=SCons.Util.splitext): """ Generates a target entry that corresponds to this entry (usually a source file) with the specified prefix and suffix. Note that this method can be overridden dynamically for generated files that need different behavior. See Tool/swig.py for an example. """ return self.dir.Entry(prefix + splitext(self.name)[0] + suffix) def _Rfindalldirs_key(self, pathlist): return pathlist memoizer_counters.append(SCons.Memoize.CountDict('Rfindalldirs', _Rfindalldirs_key)) def Rfindalldirs(self, pathlist): """ Return all of the directories for a given path list, including corresponding "backing" directories in any repositories. The Node lookups are relative to this Node (typically a directory), so memoizing result saves cycles from looking up the same path for each target in a given directory. """ try: memo_dict = self._memo['Rfindalldirs'] except KeyError: memo_dict = {} self._memo['Rfindalldirs'] = memo_dict else: try: return memo_dict[pathlist] except KeyError: pass create_dir_relative_to_self = self.Dir result = [] for path in pathlist: if isinstance(path, SCons.Node.Node): result.append(path) else: dir = create_dir_relative_to_self(path) result.extend(dir.get_all_rdirs()) memo_dict[pathlist] = result return result def RDirs(self, pathlist): """Search for a list of directories in the Repository list.""" cwd = self.cwd or self.fs._cwd return cwd.Rfindalldirs(pathlist) memoizer_counters.append(SCons.Memoize.CountValue('rentry')) def rentry(self): try: return self._memo['rentry'] except KeyError: pass result = self if not self.exists(): norm_name = _my_normcase(self.name) for dir in self.dir.get_all_rdirs(): try: node = dir.entries[norm_name] except KeyError: if dir.entry_exists_on_disk(self.name): result = dir.Entry(self.name) break self._memo['rentry'] = result return result def _glob1(self, pattern, ondisk=True, source=False, strings=False): return [] class Entry(Base): """This is the class for generic Node.FS entries--that is, things that could be a File or a Dir, but we're just not sure yet. Consequently, the methods in this class really exist just to transform their associated object into the right class when the time comes, and then call the same-named method in the transformed class.""" def diskcheck_match(self): pass def disambiguate(self, must_exist=None): """ """ if self.isdir(): self.__class__ = Dir self._morph() elif self.isfile(): self.__class__ = File self._morph() self.clear() else: # There was nothing on-disk at this location, so look in # the src directory. # # We can't just use self.srcnode() straight away because # that would create an actual Node for this file in the src # directory, and there might not be one. Instead, use the # dir_on_disk() method to see if there's something on-disk # with that name, in which case we can go ahead and call # self.srcnode() to create the right type of entry. srcdir = self.dir.srcnode() if srcdir != self.dir and \ srcdir.entry_exists_on_disk(self.name) and \ self.srcnode().isdir(): self.__class__ = Dir self._morph() elif must_exist: msg = "No such file or directory: '%s'" % self.abspath raise SCons.Errors.UserError(msg) else: self.__class__ = File self._morph() self.clear() return self def rfile(self): """We're a generic Entry, but the caller is actually looking for a File at this point, so morph into one.""" self.__class__ = File self._morph() self.clear() return File.rfile(self) def scanner_key(self): return self.get_suffix() def get_contents(self): """Fetch the contents of the entry. Returns the exact binary contents of the file.""" try: self = self.disambiguate(must_exist=1) except SCons.Errors.UserError: # There was nothing on disk with which to disambiguate # this entry. Leave it as an Entry, but return a null # string so calls to get_contents() in emitters and the # like (e.g. in qt.py) don't have to disambiguate by hand # or catch the exception. return '' else: return self.get_contents() def get_text_contents(self): """Fetch the decoded text contents of a Unicode encoded Entry. Since this should return the text contents from the file system, we check to see into what sort of subclass we should morph this Entry.""" try: self = self.disambiguate(must_exist=1) except SCons.Errors.UserError: # There was nothing on disk with which to disambiguate # this entry. Leave it as an Entry, but return a null # string so calls to get_text_contents() in emitters and # the like (e.g. in qt.py) don't have to disambiguate by # hand or catch the exception. return '' else: return self.get_text_contents() def must_be_same(self, klass): """Called to make sure a Node is a Dir. Since we're an Entry, we can morph into one.""" if self.__class__ is not klass: self.__class__ = klass self._morph() self.clear() # The following methods can get called before the Taskmaster has # had a chance to call disambiguate() directly to see if this Entry # should really be a Dir or a File. We therefore use these to call # disambiguate() transparently (from our caller's point of view). # # Right now, this minimal set of methods has been derived by just # looking at some of the methods that will obviously be called early # in any of the various Taskmasters' calling sequences, and then # empirically figuring out which additional methods are necessary # to make various tests pass. def exists(self): """Return if the Entry exists. Check the file system to see what we should turn into first. Assume a file if there's no directory.""" return self.disambiguate().exists() def rel_path(self, other): d = self.disambiguate() if d.__class__ is Entry: raise Exception("rel_path() could not disambiguate File/Dir") return d.rel_path(other) def new_ninfo(self): return self.disambiguate().new_ninfo() def changed_since_last_build(self, target, prev_ni): return self.disambiguate().changed_since_last_build(target, prev_ni) def _glob1(self, pattern, ondisk=True, source=False, strings=False): return self.disambiguate()._glob1(pattern, ondisk, source, strings) def get_subst_proxy(self): return self.disambiguate().get_subst_proxy() # This is for later so we can differentiate between Entry the class and Entry # the method of the FS class. _classEntry = Entry class LocalFS: if SCons.Memoize.use_memoizer: __metaclass__ = SCons.Memoize.Memoized_Metaclass # This class implements an abstraction layer for operations involving # a local file system. Essentially, this wraps any function in # the os, os.path or shutil modules that we use to actually go do # anything with or to the local file system. # # Note that there's a very good chance we'll refactor this part of # the architecture in some way as we really implement the interface(s) # for remote file system Nodes. For example, the right architecture # might be to have this be a subclass instead of a base class. # Nevertheless, we're using this as a first step in that direction. # # We're not using chdir() yet because the calling subclass method # needs to use os.chdir() directly to avoid recursion. Will we # really need this one? #def chdir(self, path): # return os.chdir(path) def chmod(self, path, mode): return os.chmod(path, mode) def copy(self, src, dst): return shutil.copy(src, dst) def copy2(self, src, dst): return shutil.copy2(src, dst) def exists(self, path): return os.path.exists(path) def getmtime(self, path): return os.path.getmtime(path) def getsize(self, path): return os.path.getsize(path) def isdir(self, path): return os.path.isdir(path) def isfile(self, path): return os.path.isfile(path) def link(self, src, dst): return os.link(src, dst) def lstat(self, path): return os.lstat(path) def listdir(self, path): return os.listdir(path) def makedirs(self, path): return os.makedirs(path) def mkdir(self, path): return os.mkdir(path) def rename(self, old, new): return os.rename(old, new) def stat(self, path): return os.stat(path) def symlink(self, src, dst): return os.symlink(src, dst) def open(self, path): return open(path) def unlink(self, path): return os.unlink(path) if hasattr(os, 'symlink'): def islink(self, path): return os.path.islink(path) else: def islink(self, path): return 0 # no symlinks if hasattr(os, 'readlink'): def readlink(self, file): return os.readlink(file) else: def readlink(self, file): return '' #class RemoteFS: # # Skeleton for the obvious methods we might need from the # # abstraction layer for a remote filesystem. # def upload(self, local_src, remote_dst): # pass # def download(self, remote_src, local_dst): # pass class FS(LocalFS): memoizer_counters = [] def __init__(self, path = None): """Initialize the Node.FS subsystem. The supplied path is the top of the source tree, where we expect to find the top-level build file. If no path is supplied, the current directory is the default. The path argument must be a valid absolute path. """ if __debug__: logInstanceCreation(self, 'Node.FS') self._memo = {} self.Root = {} self.SConstruct_dir = None self.max_drift = default_max_drift self.Top = None if path is None: self.pathTop = os.getcwd() else: self.pathTop = path self.defaultDrive = _my_normcase(os.path.splitdrive(self.pathTop)[0]) self.Top = self.Dir(self.pathTop) self.Top.path = '.' self.Top.tpath = '.' self._cwd = self.Top DirNodeInfo.fs = self FileNodeInfo.fs = self def set_SConstruct_dir(self, dir): self.SConstruct_dir = dir def get_max_drift(self): return self.max_drift def set_max_drift(self, max_drift): self.max_drift = max_drift def getcwd(self): return self._cwd def chdir(self, dir, change_os_dir=0): """Change the current working directory for lookups. If change_os_dir is true, we will also change the "real" cwd to match. """ curr=self._cwd try: if dir is not None: self._cwd = dir if change_os_dir: os.chdir(dir.abspath) except OSError: self._cwd = curr raise def get_root(self, drive): """ Returns the root directory for the specified drive, creating it if necessary. """ drive = _my_normcase(drive) try: return self.Root[drive] except KeyError: root = RootDir(drive, self) self.Root[drive] = root if not drive: self.Root[self.defaultDrive] = root elif drive == self.defaultDrive: self.Root[''] = root return root def _lookup(self, p, directory, fsclass, create=1): """ The generic entry point for Node lookup with user-supplied data. This translates arbitrary input into a canonical Node.FS object of the specified fsclass. The general approach for strings is to turn it into a fully normalized absolute path and then call the root directory's lookup_abs() method for the heavy lifting. If the path name begins with '#', it is unconditionally interpreted relative to the top-level directory of this FS. '#' is treated as a synonym for the top-level SConstruct directory, much like '~' is treated as a synonym for the user's home directory in a UNIX shell. So both '#foo' and '#/foo' refer to the 'foo' subdirectory underneath the top-level SConstruct directory. If the path name is relative, then the path is looked up relative to the specified directory, or the current directory (self._cwd, typically the SConscript directory) if the specified directory is None. """ if isinstance(p, Base): # It's already a Node.FS object. Make sure it's the right # class and return. p.must_be_same(fsclass) return p # str(p) in case it's something like a proxy object p = str(p) initial_hash = (p[0:1] == '#') if initial_hash: # There was an initial '#', so we strip it and override # whatever directory they may have specified with the # top-level SConstruct directory. p = p[1:] directory = self.Top if directory and not isinstance(directory, Dir): directory = self.Dir(directory) if do_splitdrive: drive, p = os.path.splitdrive(p) else: drive = '' if drive and not p: # This causes a naked drive letter to be treated as a synonym # for the root directory on that drive. p = os.sep absolute = os.path.isabs(p) needs_normpath = needs_normpath_check.match(p) if initial_hash or not absolute: # This is a relative lookup, either to the top-level # SConstruct directory (because of the initial '#') or to # the current directory (the path name is not absolute). # Add the string to the appropriate directory lookup path, # after which the whole thing gets normalized. if not directory: directory = self._cwd if p: p = directory.labspath + '/' + p else: p = directory.labspath if needs_normpath: p = os.path.normpath(p) if drive or absolute: root = self.get_root(drive) else: if not directory: directory = self._cwd root = directory.root if os.sep != '/': p = string.replace(p, os.sep, '/') return root._lookup_abs(p, fsclass, create) def Entry(self, name, directory = None, create = 1): """Look up or create a generic Entry node with the specified name. If the name is a relative path (begins with ./, ../, or a file name), then it is looked up relative to the supplied directory node, or to the top level directory of the FS (supplied at construction time) if no directory is supplied. """ return self._lookup(name, directory, Entry, create) def File(self, name, directory = None, create = 1): """Look up or create a File node with the specified name. If the name is a relative path (begins with ./, ../, or a file name), then it is looked up relative to the supplied directory node, or to the top level directory of the FS (supplied at construction time) if no directory is supplied. This method will raise TypeError if a directory is found at the specified path. """ return self._lookup(name, directory, File, create) def Dir(self, name, directory = None, create = True): """Look up or create a Dir node with the specified name. If the name is a relative path (begins with ./, ../, or a file name), then it is looked up relative to the supplied directory node, or to the top level directory of the FS (supplied at construction time) if no directory is supplied. This method will raise TypeError if a normal file is found at the specified path. """ return self._lookup(name, directory, Dir, create) def VariantDir(self, variant_dir, src_dir, duplicate=1): """Link the supplied variant directory to the source directory for purposes of building files.""" if not isinstance(src_dir, SCons.Node.Node): src_dir = self.Dir(src_dir) if not isinstance(variant_dir, SCons.Node.Node): variant_dir = self.Dir(variant_dir) if src_dir.is_under(variant_dir): raise SCons.Errors.UserError("Source directory cannot be under variant directory.") if variant_dir.srcdir: if variant_dir.srcdir == src_dir: return # We already did this. raise SCons.Errors.UserError("'%s' already has a source directory: '%s'."%(variant_dir, variant_dir.srcdir)) variant_dir.link(src_dir, duplicate) def Repository(self, *dirs): """Specify Repository directories to search.""" for d in dirs: if not isinstance(d, SCons.Node.Node): d = self.Dir(d) self.Top.addRepository(d) def variant_dir_target_climb(self, orig, dir, tail): """Create targets in corresponding variant directories Climb the directory tree, and look up path names relative to any linked variant directories we find. Even though this loops and walks up the tree, we don't memoize the return value because this is really only used to process the command-line targets. """ targets = [] message = None fmt = "building associated VariantDir targets: %s" start_dir = dir while dir: for bd in dir.variant_dirs: if start_dir.is_under(bd): # If already in the build-dir location, don't reflect return [orig], fmt % str(orig) p = os.path.join(*[bd.path] + tail) targets.append(self.Entry(p)) tail = [dir.name] + tail dir = dir.up() if targets: message = fmt % string.join(map(str, targets)) return targets, message def Glob(self, pathname, ondisk=True, source=True, strings=False, cwd=None): """ Globs This is mainly a shim layer """ if cwd is None: cwd = self.getcwd() return cwd.glob(pathname, ondisk, source, strings) class DirNodeInfo(SCons.Node.NodeInfoBase): # This should get reset by the FS initialization. current_version_id = 1 fs = None def str_to_node(self, s): top = self.fs.Top root = top.root if do_splitdrive: drive, s = os.path.splitdrive(s) if drive: root = self.fs.get_root(drive) if not os.path.isabs(s): s = top.labspath + '/' + s return root._lookup_abs(s, Entry) class DirBuildInfo(SCons.Node.BuildInfoBase): current_version_id = 1 glob_magic_check = re.compile('[*?[]') def has_glob_magic(s): return glob_magic_check.search(s) is not None class Dir(Base): """A class for directories in a file system. """ memoizer_counters = [] NodeInfo = DirNodeInfo BuildInfo = DirBuildInfo def __init__(self, name, directory, fs): if __debug__: logInstanceCreation(self, 'Node.FS.Dir') Base.__init__(self, name, directory, fs) self._morph() def _morph(self): """Turn a file system Node (either a freshly initialized directory object or a separate Entry object) into a proper directory object. Set up this directory's entries and hook it into the file system tree. Specify that directories (this Node) don't use signatures for calculating whether they're current. """ self.repositories = [] self.srcdir = None self.entries = {} self.entries['.'] = self self.entries['..'] = self.dir self.cwd = self self.searched = 0 self._sconsign = None self.variant_dirs = [] self.root = self.dir.root # Don't just reset the executor, replace its action list, # because it might have some pre-or post-actions that need to # be preserved. self.builder = get_MkdirBuilder() self.get_executor().set_action_list(self.builder.action) def diskcheck_match(self): diskcheck_match(self, self.isfile, "File %s found where directory expected.") def __clearRepositoryCache(self, duplicate=None): """Called when we change the repository(ies) for a directory. This clears any cached information that is invalidated by changing the repository.""" for node in self.entries.values(): if node != self.dir: if node != self and isinstance(node, Dir): node.__clearRepositoryCache(duplicate) else: node.clear() try: del node._srcreps except AttributeError: pass if duplicate is not None: node.duplicate=duplicate def __resetDuplicate(self, node): if node != self: node.duplicate = node.get_dir().duplicate def Entry(self, name): """ Looks up or creates an entry node named 'name' relative to this directory. """ return self.fs.Entry(name, self) def Dir(self, name, create=True): """ Looks up or creates a directory node named 'name' relative to this directory. """ return self.fs.Dir(name, self, create) def File(self, name): """ Looks up or creates a file node named 'name' relative to this directory. """ return self.fs.File(name, self) def _lookup_rel(self, name, klass, create=1): """ Looks up a *normalized* relative path name, relative to this directory. This method is intended for use by internal lookups with already-normalized path data. For general-purpose lookups, use the Entry(), Dir() and File() methods above. This method does *no* input checking and will die or give incorrect results if it's passed a non-normalized path name (e.g., a path containing '..'), an absolute path name, a top-relative ('#foo') path name, or any kind of object. """ name = self.entry_labspath(name) return self.root._lookup_abs(name, klass, create) def link(self, srcdir, duplicate): """Set this directory as the variant directory for the supplied source directory.""" self.srcdir = srcdir self.duplicate = duplicate self.__clearRepositoryCache(duplicate) srcdir.variant_dirs.append(self) def getRepositories(self): """Returns a list of repositories for this directory. """ if self.srcdir and not self.duplicate: return self.srcdir.get_all_rdirs() + self.repositories return self.repositories memoizer_counters.append(SCons.Memoize.CountValue('get_all_rdirs')) def get_all_rdirs(self): try: return list(self._memo['get_all_rdirs']) except KeyError: pass result = [self] fname = '.' dir = self while dir: for rep in dir.getRepositories(): result.append(rep.Dir(fname)) if fname == '.': fname = dir.name else: fname = dir.name + os.sep + fname dir = dir.up() self._memo['get_all_rdirs'] = list(result) return result def addRepository(self, dir): if dir != self and not dir in self.repositories: self.repositories.append(dir) dir.tpath = '.' self.__clearRepositoryCache() def up(self): return self.entries['..'] def _rel_path_key(self, other): return str(other) memoizer_counters.append(SCons.Memoize.CountDict('rel_path', _rel_path_key)) def rel_path(self, other): """Return a path to "other" relative to this directory. """ # This complicated and expensive method, which constructs relative # paths between arbitrary Node.FS objects, is no longer used # by SCons itself. It was introduced to store dependency paths # in .sconsign files relative to the target, but that ended up # being significantly inefficient. # # We're continuing to support the method because some SConstruct # files out there started using it when it was available, and # we're all about backwards compatibility.. try: memo_dict = self._memo['rel_path'] except KeyError: memo_dict = {} self._memo['rel_path'] = memo_dict else: try: return memo_dict[other] except KeyError: pass if self is other: result = '.' elif not other in self.path_elements: try: other_dir = other.get_dir() except AttributeError: result = str(other) else: if other_dir is None: result = other.name else: dir_rel_path = self.rel_path(other_dir) if dir_rel_path == '.': result = other.name else: result = dir_rel_path + os.sep + other.name else: i = self.path_elements.index(other) + 1 path_elems = ['..'] * (len(self.path_elements) - i) \ + map(lambda n: n.name, other.path_elements[i:]) result = string.join(path_elems, os.sep) memo_dict[other] = result return result def get_env_scanner(self, env, kw={}): import SCons.Defaults return SCons.Defaults.DirEntryScanner def get_target_scanner(self): import SCons.Defaults return SCons.Defaults.DirEntryScanner def get_found_includes(self, env, scanner, path): """Return this directory's implicit dependencies. We don't bother caching the results because the scan typically shouldn't be requested more than once (as opposed to scanning .h file contents, which can be requested as many times as the files is #included by other files). """ if not scanner: return [] # Clear cached info for this Dir. If we already visited this # directory on our walk down the tree (because we didn't know at # that point it was being used as the source for another Node) # then we may have calculated build signature before realizing # we had to scan the disk. Now that we have to, though, we need # to invalidate the old calculated signature so that any node # dependent on our directory structure gets one that includes # info about everything on disk. self.clear() return scanner(self, env, path) # # Taskmaster interface subsystem # def prepare(self): pass def build(self, **kw): """A null "builder" for directories.""" global MkdirBuilder if self.builder is not MkdirBuilder: SCons.Node.Node.build(*[self,], **kw) # # # def _create(self): """Create this directory, silently and without worrying about whether the builder is the default or not.""" listDirs = [] parent = self while parent: if parent.exists(): break listDirs.append(parent) p = parent.up() if p is None: # Don't use while: - else: for this condition because # if so, then parent is None and has no .path attribute. raise SCons.Errors.StopError(parent.path) parent = p listDirs.reverse() for dirnode in listDirs: try: # Don't call dirnode.build(), call the base Node method # directly because we definitely *must* create this # directory. The dirnode.build() method will suppress # the build if it's the default builder. SCons.Node.Node.build(dirnode) dirnode.get_executor().nullify() # The build() action may or may not have actually # created the directory, depending on whether the -n # option was used or not. Delete the _exists and # _rexists attributes so they can be reevaluated. dirnode.clear() except OSError: pass def multiple_side_effect_has_builder(self): global MkdirBuilder return self.builder is not MkdirBuilder and self.has_builder() def alter_targets(self): """Return any corresponding targets in a variant directory. """ return self.fs.variant_dir_target_climb(self, self, []) def scanner_key(self): """A directory does not get scanned.""" return None def get_text_contents(self): """We already emit things in text, so just return the binary version.""" return self.get_contents() def get_contents(self): """Return content signatures and names of all our children separated by new-lines. Ensure that the nodes are sorted.""" contents = [] name_cmp = lambda a, b: cmp(a.name, b.name) sorted_children = self.children()[:] sorted_children.sort(name_cmp) for node in sorted_children: contents.append('%s %s\n' % (node.get_csig(), node.name)) return string.join(contents, '') def get_csig(self): """Compute the content signature for Directory nodes. In general, this is not needed and the content signature is not stored in the DirNodeInfo. However, if get_contents on a Dir node is called which has a child directory, the child directory should return the hash of its contents.""" contents = self.get_contents() return SCons.Util.MD5signature(contents) def do_duplicate(self, src): pass changed_since_last_build = SCons.Node.Node.state_has_changed def is_up_to_date(self): """If any child is not up-to-date, then this directory isn't, either.""" if self.builder is not MkdirBuilder and not self.exists(): return 0 up_to_date = SCons.Node.up_to_date for kid in self.children(): if kid.get_state() > up_to_date: return 0 return 1 def rdir(self): if not self.exists(): norm_name = _my_normcase(self.name) for dir in self.dir.get_all_rdirs(): try: node = dir.entries[norm_name] except KeyError: node = dir.dir_on_disk(self.name) if node and node.exists() and \ (isinstance(dir, Dir) or isinstance(dir, Entry)): return node return self def sconsign(self): """Return the .sconsign file info for this directory, creating it first if necessary.""" if not self._sconsign: import SCons.SConsign self._sconsign = SCons.SConsign.ForDirectory(self) return self._sconsign def srcnode(self): """Dir has a special need for srcnode()...if we have a srcdir attribute set, then that *is* our srcnode.""" if self.srcdir: return self.srcdir return Base.srcnode(self) def get_timestamp(self): """Return the latest timestamp from among our children""" stamp = 0 for kid in self.children(): if kid.get_timestamp() > stamp: stamp = kid.get_timestamp() return stamp def entry_abspath(self, name): return self.abspath + os.sep + name def entry_labspath(self, name): return self.labspath + '/' + name def entry_path(self, name): return self.path + os.sep + name def entry_tpath(self, name): return self.tpath + os.sep + name def entry_exists_on_disk(self, name): try: d = self.on_disk_entries except AttributeError: d = {} try: entries = os.listdir(self.abspath) except OSError: pass else: for entry in map(_my_normcase, entries): d[entry] = True self.on_disk_entries = d if sys.platform == 'win32': name = _my_normcase(name) result = d.get(name) if result is None: # Belt-and-suspenders for Windows: check directly for # 8.3 file names that don't show up in os.listdir(). result = os.path.exists(self.abspath + os.sep + name) d[name] = result return result else: return name in d memoizer_counters.append(SCons.Memoize.CountValue('srcdir_list')) def srcdir_list(self): try: return self._memo['srcdir_list'] except KeyError: pass result = [] dirname = '.' dir = self while dir: if dir.srcdir: result.append(dir.srcdir.Dir(dirname)) dirname = dir.name + os.sep + dirname dir = dir.up() self._memo['srcdir_list'] = result return result def srcdir_duplicate(self, name): for dir in self.srcdir_list(): if self.is_under(dir): # We shouldn't source from something in the build path; # variant_dir is probably under src_dir, in which case # we are reflecting. break if dir.entry_exists_on_disk(name): srcnode = dir.Entry(name).disambiguate() if self.duplicate: node = self.Entry(name).disambiguate() node.do_duplicate(srcnode) return node else: return srcnode return None def _srcdir_find_file_key(self, filename): return filename memoizer_counters.append(SCons.Memoize.CountDict('srcdir_find_file', _srcdir_find_file_key)) def srcdir_find_file(self, filename): try: memo_dict = self._memo['srcdir_find_file'] except KeyError: memo_dict = {} self._memo['srcdir_find_file'] = memo_dict else: try: return memo_dict[filename] except KeyError: pass def func(node): if (isinstance(node, File) or isinstance(node, Entry)) and \ (node.is_derived() or node.exists()): return node return None norm_name = _my_normcase(filename) for rdir in self.get_all_rdirs(): try: node = rdir.entries[norm_name] except KeyError: node = rdir.file_on_disk(filename) else: node = func(node) if node: result = (node, self) memo_dict[filename] = result return result for srcdir in self.srcdir_list(): for rdir in srcdir.get_all_rdirs(): try: node = rdir.entries[norm_name] except KeyError: node = rdir.file_on_disk(filename) else: node = func(node) if node: result = (File(filename, self, self.fs), srcdir) memo_dict[filename] = result return result result = (None, None) memo_dict[filename] = result return result def dir_on_disk(self, name): if self.entry_exists_on_disk(name): try: return self.Dir(name) except TypeError: pass node = self.srcdir_duplicate(name) if isinstance(node, File): return None return node def file_on_disk(self, name): if self.entry_exists_on_disk(name) or \ diskcheck_rcs(self, name) or \ diskcheck_sccs(self, name): try: return self.File(name) except TypeError: pass node = self.srcdir_duplicate(name) if isinstance(node, Dir): return None return node def walk(self, func, arg): """ Walk this directory tree by calling the specified function for each directory in the tree. This behaves like the os.path.walk() function, but for in-memory Node.FS.Dir objects. The function takes the same arguments as the functions passed to os.path.walk(): func(arg, dirname, fnames) Except that "dirname" will actually be the directory *Node*, not the string. The '.' and '..' entries are excluded from fnames. The fnames list may be modified in-place to filter the subdirectories visited or otherwise impose a specific order. The "arg" argument is always passed to func() and may be used in any way (or ignored, passing None is common). """ entries = self.entries names = entries.keys() names.remove('.') names.remove('..') func(arg, self, names) select_dirs = lambda n, e=entries: isinstance(e[n], Dir) for dirname in filter(select_dirs, names): entries[dirname].walk(func, arg) def glob(self, pathname, ondisk=True, source=False, strings=False): """ Returns a list of Nodes (or strings) matching a specified pathname pattern. Pathname patterns follow UNIX shell semantics: * matches any-length strings of any characters, ? matches any character, and [] can enclose lists or ranges of characters. Matches do not span directory separators. The matches take into account Repositories, returning local Nodes if a corresponding entry exists in a Repository (either an in-memory Node or something on disk). By defafult, the glob() function matches entries that exist on-disk, in addition to in-memory Nodes. Setting the "ondisk" argument to False (or some other non-true value) causes the glob() function to only match in-memory Nodes. The default behavior is to return both the on-disk and in-memory Nodes. The "source" argument, when true, specifies that corresponding source Nodes must be returned if you're globbing in a build directory (initialized with VariantDir()). The default behavior is to return Nodes local to the VariantDir(). The "strings" argument, when true, returns the matches as strings, not Nodes. The strings are path names relative to this directory. The underlying algorithm is adapted from the glob.glob() function in the Python library (but heavily modified), and uses fnmatch() under the covers. """ dirname, basename = os.path.split(pathname) if not dirname: result = self._glob1(basename, ondisk, source, strings) result.sort(lambda a, b: cmp(str(a), str(b))) return result if has_glob_magic(dirname): list = self.glob(dirname, ondisk, source, strings=False) else: list = [self.Dir(dirname, create=True)] result = [] for dir in list: r = dir._glob1(basename, ondisk, source, strings) if strings: r = map(lambda x, d=str(dir): os.path.join(d, x), r) result.extend(r) result.sort(lambda a, b: cmp(str(a), str(b))) return result def _glob1(self, pattern, ondisk=True, source=False, strings=False): """ Globs for and returns a list of entry names matching a single pattern in this directory. This searches any repositories and source directories for corresponding entries and returns a Node (or string) relative to the current directory if an entry is found anywhere. TODO: handle pattern with no wildcard """ search_dir_list = self.get_all_rdirs() for srcdir in self.srcdir_list(): search_dir_list.extend(srcdir.get_all_rdirs()) selfEntry = self.Entry names = [] for dir in search_dir_list: # We use the .name attribute from the Node because the keys of # the dir.entries dictionary are normalized (that is, all upper # case) on case-insensitive systems like Windows. #node_names = [ v.name for k, v in dir.entries.items() if k not in ('.', '..') ] entry_names = filter(lambda n: n not in ('.', '..'), dir.entries.keys()) node_names = map(lambda n, e=dir.entries: e[n].name, entry_names) names.extend(node_names) if not strings: # Make sure the working directory (self) actually has # entries for all Nodes in repositories or variant dirs. for name in node_names: selfEntry(name) if ondisk: try: disk_names = os.listdir(dir.abspath) except os.error: continue names.extend(disk_names) if not strings: # We're going to return corresponding Nodes in # the local directory, so we need to make sure # those Nodes exist. We only want to create # Nodes for the entries that will match the # specified pattern, though, which means we # need to filter the list here, even though # the overall list will also be filtered later, # after we exit this loop. if pattern[0] != '.': #disk_names = [ d for d in disk_names if d[0] != '.' ] disk_names = filter(lambda x: x[0] != '.', disk_names) disk_names = fnmatch.filter(disk_names, pattern) dirEntry = dir.Entry for name in disk_names: # Add './' before disk filename so that '#' at # beginning of filename isn't interpreted. name = './' + name node = dirEntry(name).disambiguate() n = selfEntry(name) if n.__class__ != node.__class__: n.__class__ = node.__class__ n._morph() names = set(names) if pattern[0] != '.': #names = [ n for n in names if n[0] != '.' ] names = filter(lambda x: x[0] != '.', names) names = fnmatch.filter(names, pattern) if strings: return names #return [ self.entries[_my_normcase(n)] for n in names ] return map(lambda n, e=self.entries: e[_my_normcase(n)], names) class RootDir(Dir): """A class for the root directory of a file system. This is the same as a Dir class, except that the path separator ('/' or '\\') is actually part of the name, so we don't need to add a separator when creating the path names of entries within this directory. """ def __init__(self, name, fs): if __debug__: logInstanceCreation(self, 'Node.FS.RootDir') # We're going to be our own parent directory (".." entry and .dir # attribute) so we have to set up some values so Base.__init__() # won't gag won't it calls some of our methods. self.abspath = '' self.labspath = '' self.path = '' self.tpath = '' self.path_elements = [] self.duplicate = 0 self.root = self Base.__init__(self, name, self, fs) # Now set our paths to what we really want them to be: the # initial drive letter (the name) plus the directory separator, # except for the "lookup abspath," which does not have the # drive letter. self.abspath = name + os.sep self.labspath = '' self.path = name + os.sep self.tpath = name + os.sep self._morph() self._lookupDict = {} # The // and os.sep + os.sep entries are necessary because # os.path.normpath() seems to preserve double slashes at the # beginning of a path (presumably for UNC path names), but # collapses triple slashes to a single slash. self._lookupDict[''] = self self._lookupDict['/'] = self self._lookupDict['//'] = self self._lookupDict[os.sep] = self self._lookupDict[os.sep + os.sep] = self def must_be_same(self, klass): if klass is Dir: return Base.must_be_same(self, klass) def _lookup_abs(self, p, klass, create=1): """ Fast (?) lookup of a *normalized* absolute path. This method is intended for use by internal lookups with already-normalized path data. For general-purpose lookups, use the FS.Entry(), FS.Dir() or FS.File() methods. The caller is responsible for making sure we're passed a normalized absolute path; we merely let Python's dictionary look up and return the One True Node.FS object for the path. If no Node for the specified "p" doesn't already exist, and "create" is specified, the Node may be created after recursive invocation to find or create the parent directory or directories. """ k = _my_normcase(p) try: result = self._lookupDict[k] except KeyError: if not create: raise SCons.Errors.UserError # There is no Node for this path name, and we're allowed # to create it. dir_name, file_name = os.path.split(p) dir_node = self._lookup_abs(dir_name, Dir) result = klass(file_name, dir_node, self.fs) # Double-check on disk (as configured) that the Node we # created matches whatever is out there in the real world. result.diskcheck_match() self._lookupDict[k] = result dir_node.entries[_my_normcase(file_name)] = result dir_node.implicit = None else: # There is already a Node for this path name. Allow it to # complain if we were looking for an inappropriate type. result.must_be_same(klass) return result def __str__(self): return self.abspath def entry_abspath(self, name): return self.abspath + name def entry_labspath(self, name): return '/' + name def entry_path(self, name): return self.path + name def entry_tpath(self, name): return self.tpath + name def is_under(self, dir): if self is dir: return 1 else: return 0 def up(self): return None def get_dir(self): return None def src_builder(self): return _null class FileNodeInfo(SCons.Node.NodeInfoBase): current_version_id = 1 field_list = ['csig', 'timestamp', 'size'] # This should get reset by the FS initialization. fs = None def str_to_node(self, s): top = self.fs.Top root = top.root if do_splitdrive: drive, s = os.path.splitdrive(s) if drive: root = self.fs.get_root(drive) if not os.path.isabs(s): s = top.labspath + '/' + s return root._lookup_abs(s, Entry) class FileBuildInfo(SCons.Node.BuildInfoBase): current_version_id = 1 def convert_to_sconsign(self): """ Converts this FileBuildInfo object for writing to a .sconsign file This replaces each Node in our various dependency lists with its usual string representation: relative to the top-level SConstruct directory, or an absolute path if it's outside. """ if os.sep == '/': node_to_str = str else: def node_to_str(n): try: s = n.path except AttributeError: s = str(n) else: s = string.replace(s, os.sep, '/') return s for attr in ['bsources', 'bdepends', 'bimplicit']: try: val = getattr(self, attr) except AttributeError: pass else: setattr(self, attr, map(node_to_str, val)) def convert_from_sconsign(self, dir, name): """ Converts a newly-read FileBuildInfo object for in-SCons use For normal up-to-date checking, we don't have any conversion to perform--but we're leaving this method here to make that clear. """ pass def prepare_dependencies(self): """ Prepares a FileBuildInfo object for explaining what changed The bsources, bdepends and bimplicit lists have all been stored on disk as paths relative to the top-level SConstruct directory. Convert the strings to actual Nodes (for use by the --debug=explain code and --implicit-cache). """ attrs = [ ('bsources', 'bsourcesigs'), ('bdepends', 'bdependsigs'), ('bimplicit', 'bimplicitsigs'), ] for (nattr, sattr) in attrs: try: strings = getattr(self, nattr) nodeinfos = getattr(self, sattr) except AttributeError: continue nodes = [] for s, ni in izip(strings, nodeinfos): if not isinstance(s, SCons.Node.Node): s = ni.str_to_node(s) nodes.append(s) setattr(self, nattr, nodes) def format(self, names=0): result = [] bkids = self.bsources + self.bdepends + self.bimplicit bkidsigs = self.bsourcesigs + self.bdependsigs + self.bimplicitsigs for bkid, bkidsig in izip(bkids, bkidsigs): result.append(str(bkid) + ': ' + string.join(bkidsig.format(names=names), ' ')) result.append('%s [%s]' % (self.bactsig, self.bact)) return string.join(result, '\n') class File(Base): """A class for files in a file system. """ memoizer_counters = [] NodeInfo = FileNodeInfo BuildInfo = FileBuildInfo md5_chunksize = 64 def diskcheck_match(self): diskcheck_match(self, self.isdir, "Directory %s found where file expected.") def __init__(self, name, directory, fs): if __debug__: logInstanceCreation(self, 'Node.FS.File') Base.__init__(self, name, directory, fs) self._morph() def Entry(self, name): """Create an entry node named 'name' relative to the directory of this file.""" return self.dir.Entry(name) def Dir(self, name, create=True): """Create a directory node named 'name' relative to the directory of this file.""" return self.dir.Dir(name, create=create) def Dirs(self, pathlist): """Create a list of directories relative to the SConscript directory of this file.""" # TODO(1.5) # return [self.Dir(p) for p in pathlist] return map(lambda p, s=self: s.Dir(p), pathlist) def File(self, name): """Create a file node named 'name' relative to the directory of this file.""" return self.dir.File(name) #def generate_build_dict(self): # """Return an appropriate dictionary of values for building # this File.""" # return {'Dir' : self.Dir, # 'File' : self.File, # 'RDirs' : self.RDirs} def _morph(self): """Turn a file system node into a File object.""" self.scanner_paths = {} if not hasattr(self, '_local'): self._local = 0 # If there was already a Builder set on this entry, then # we need to make sure we call the target-decider function, # not the source-decider. Reaching in and doing this by hand # is a little bogus. We'd prefer to handle this by adding # an Entry.builder_set() method that disambiguates like the # other methods, but that starts running into problems with the # fragile way we initialize Dir Nodes with their Mkdir builders, # yet still allow them to be overridden by the user. Since it's # not clear right now how to fix that, stick with what works # until it becomes clear... if self.has_builder(): self.changed_since_last_build = self.decide_target def scanner_key(self): return self.get_suffix() def get_contents(self): if not self.rexists(): return '' fname = self.rfile().abspath try: contents = open(fname, "rb").read() except EnvironmentError as e: if not e.filename: e.filename = fname raise return contents try: import codecs except ImportError: get_text_contents = get_contents else: # This attempts to figure out what the encoding of the text is # based upon the BOM bytes, and then decodes the contents so that # it's a valid python string. def get_text_contents(self): contents = self.get_contents() # The behavior of various decode() methods and functions # w.r.t. the initial BOM bytes is different for different # encodings and/or Python versions. ('utf-8' does not strip # them, but has a 'utf-8-sig' which does; 'utf-16' seems to # strip them; etc.) Just side step all the complication by # explicitly stripping the BOM before we decode(). if contents.startswith(codecs.BOM_UTF8): contents = contents[len(codecs.BOM_UTF8):] # TODO(2.2): Remove when 2.3 becomes floor. #contents = contents.decode('utf-8') contents = my_decode(contents, 'utf-8') elif contents.startswith(codecs.BOM_UTF16_LE): contents = contents[len(codecs.BOM_UTF16_LE):] # TODO(2.2): Remove when 2.3 becomes floor. #contents = contents.decode('utf-16-le') contents = my_decode(contents, 'utf-16-le') elif contents.startswith(codecs.BOM_UTF16_BE): contents = contents[len(codecs.BOM_UTF16_BE):] # TODO(2.2): Remove when 2.3 becomes floor. #contents = contents.decode('utf-16-be') contents = my_decode(contents, 'utf-16-be') return contents def get_content_hash(self): """ Compute and return the MD5 hash for this file. """ if not self.rexists(): return SCons.Util.MD5signature('') fname = self.rfile().abspath try: cs = SCons.Util.MD5filesignature(fname, chunksize=SCons.Node.FS.File.md5_chunksize*1024) except EnvironmentError as e: if not e.filename: e.filename = fname raise return cs memoizer_counters.append(SCons.Memoize.CountValue('get_size')) def get_size(self): try: return self._memo['get_size'] except KeyError: pass if self.rexists(): size = self.rfile().getsize() else: size = 0 self._memo['get_size'] = size return size memoizer_counters.append(SCons.Memoize.CountValue('get_timestamp')) def get_timestamp(self): try: return self._memo['get_timestamp'] except KeyError: pass if self.rexists(): timestamp = self.rfile().getmtime() else: timestamp = 0 self._memo['get_timestamp'] = timestamp return timestamp def store_info(self): # Merge our build information into the already-stored entry. # This accomodates "chained builds" where a file that's a target # in one build (SConstruct file) is a source in a different build. # See test/chained-build.py for the use case. if do_store_info: self.dir.sconsign().store_info(self.name, self) convert_copy_attrs = [ 'bsources', 'bimplicit', 'bdepends', 'bact', 'bactsig', 'ninfo', ] convert_sig_attrs = [ 'bsourcesigs', 'bimplicitsigs', 'bdependsigs', ] def convert_old_entry(self, old_entry): # Convert a .sconsign entry from before the Big Signature # Refactoring, doing what we can to convert its information # to the new .sconsign entry format. # # The old format looked essentially like this: # # BuildInfo # .ninfo (NodeInfo) # .bsig # .csig # .timestamp # .size # .bsources # .bsourcesigs ("signature" list) # .bdepends # .bdependsigs ("signature" list) # .bimplicit # .bimplicitsigs ("signature" list) # .bact # .bactsig # # The new format looks like this: # # .ninfo (NodeInfo) # .bsig # .csig # .timestamp # .size # .binfo (BuildInfo) # .bsources # .bsourcesigs (NodeInfo list) # .bsig # .csig # .timestamp # .size # .bdepends # .bdependsigs (NodeInfo list) # .bsig # .csig # .timestamp # .size # .bimplicit # .bimplicitsigs (NodeInfo list) # .bsig # .csig # .timestamp # .size # .bact # .bactsig # # The basic idea of the new structure is that a NodeInfo always # holds all available information about the state of a given Node # at a certain point in time. The various .b*sigs lists can just # be a list of pointers to the .ninfo attributes of the different # dependent nodes, without any copying of information until it's # time to pickle it for writing out to a .sconsign file. # # The complicating issue is that the *old* format only stored one # "signature" per dependency, based on however the *last* build # was configured. We don't know from just looking at it whether # it was a build signature, a content signature, or a timestamp # "signature". Since we no longer use build signatures, the # best we can do is look at the length and if it's thirty two, # assume that it was (or might have been) a content signature. # If it was actually a build signature, then it will cause a # rebuild anyway when it doesn't match the new content signature, # but that's probably the best we can do. import SCons.SConsign new_entry = SCons.SConsign.SConsignEntry() new_entry.binfo = self.new_binfo() binfo = new_entry.binfo for attr in self.convert_copy_attrs: try: value = getattr(old_entry, attr) except AttributeError: continue setattr(binfo, attr, value) delattr(old_entry, attr) for attr in self.convert_sig_attrs: try: sig_list = getattr(old_entry, attr) except AttributeError: continue value = [] for sig in sig_list: ninfo = self.new_ninfo() if len(sig) == 32: ninfo.csig = sig else: ninfo.timestamp = sig value.append(ninfo) setattr(binfo, attr, value) delattr(old_entry, attr) return new_entry memoizer_counters.append(SCons.Memoize.CountValue('get_stored_info')) def get_stored_info(self): try: return self._memo['get_stored_info'] except KeyError: pass try: sconsign_entry = self.dir.sconsign().get_entry(self.name) except (KeyError, EnvironmentError): import SCons.SConsign sconsign_entry = SCons.SConsign.SConsignEntry() sconsign_entry.binfo = self.new_binfo() sconsign_entry.ninfo = self.new_ninfo() else: if isinstance(sconsign_entry, FileBuildInfo): # This is a .sconsign file from before the Big Signature # Refactoring; convert it as best we can. sconsign_entry = self.convert_old_entry(sconsign_entry) try: delattr(sconsign_entry.ninfo, 'bsig') except AttributeError: pass self._memo['get_stored_info'] = sconsign_entry return sconsign_entry def get_stored_implicit(self): binfo = self.get_stored_info().binfo binfo.prepare_dependencies() try: return binfo.bimplicit except AttributeError: return None def rel_path(self, other): return self.dir.rel_path(other) def _get_found_includes_key(self, env, scanner, path): return (id(env), id(scanner), path) memoizer_counters.append(SCons.Memoize.CountDict('get_found_includes', _get_found_includes_key)) def get_found_includes(self, env, scanner, path): """Return the included implicit dependencies in this file. Cache results so we only scan the file once per path regardless of how many times this information is requested. """ memo_key = (id(env), id(scanner), path) try: memo_dict = self._memo['get_found_includes'] except KeyError: memo_dict = {} self._memo['get_found_includes'] = memo_dict else: try: return memo_dict[memo_key] except KeyError: pass if scanner: # result = [n.disambiguate() for n in scanner(self, env, path)] result = scanner(self, env, path) result = map(lambda N: N.disambiguate(), result) else: result = [] memo_dict[memo_key] = result return result def _createDir(self): # ensure that the directories for this node are # created. self.dir._create() def push_to_cache(self): """Try to push the node into a cache """ # This should get called before the Nodes' .built() method is # called, which would clear the build signature if the file has # a source scanner. # # We have to clear the local memoized values *before* we push # the node to cache so that the memoization of the self.exists() # return value doesn't interfere. if self.nocache: return self.clear_memoized_values() if self.exists(): self.get_build_env().get_CacheDir().push(self) def retrieve_from_cache(self): """Try to retrieve the node's content from a cache This method is called from multiple threads in a parallel build, so only do thread safe stuff here. Do thread unsafe stuff in built(). Returns true iff the node was successfully retrieved. """ if self.nocache: return None if not self.is_derived(): return None return self.get_build_env().get_CacheDir().retrieve(self) def visited(self): if self.exists(): self.get_build_env().get_CacheDir().push_if_forced(self) ninfo = self.get_ninfo() csig = self.get_max_drift_csig() if csig: ninfo.csig = csig ninfo.timestamp = self.get_timestamp() ninfo.size = self.get_size() if not self.has_builder(): # This is a source file, but it might have been a target file # in another build that included more of the DAG. Copy # any build information that's stored in the .sconsign file # into our binfo object so it doesn't get lost. old = self.get_stored_info() self.get_binfo().__dict__.update(old.binfo.__dict__) self.store_info() def find_src_builder(self): if self.rexists(): return None scb = self.dir.src_builder() if scb is _null: if diskcheck_sccs(self.dir, self.name): scb = get_DefaultSCCSBuilder() elif diskcheck_rcs(self.dir, self.name): scb = get_DefaultRCSBuilder() else: scb = None if scb is not None: try: b = self.builder except AttributeError: b = None if b is None: self.builder_set(scb) return scb def has_src_builder(self): """Return whether this Node has a source builder or not. If this Node doesn't have an explicit source code builder, this is where we figure out, on the fly, if there's a transparent source code builder for it. Note that if we found a source builder, we also set the self.builder attribute, so that all of the methods that actually *build* this file don't have to do anything different. """ try: scb = self.sbuilder except AttributeError: scb = self.sbuilder = self.find_src_builder() return scb is not None def alter_targets(self): """Return any corresponding targets in a variant directory. """ if self.is_derived(): return [], None return self.fs.variant_dir_target_climb(self, self.dir, [self.name]) def _rmv_existing(self): self.clear_memoized_values() e = Unlink(self, [], None) if isinstance(e, SCons.Errors.BuildError): raise e # # Taskmaster interface subsystem # def make_ready(self): self.has_src_builder() self.get_binfo() def prepare(self): """Prepare for this file to be created.""" SCons.Node.Node.prepare(self) if self.get_state() != SCons.Node.up_to_date: if self.exists(): if self.is_derived() and not self.precious: self._rmv_existing() else: try: self._createDir() except SCons.Errors.StopError as drive: desc = "No drive `%s' for target `%s'." % (drive, self) raise SCons.Errors.StopError(desc) # # # def remove(self): """Remove this file.""" if self.exists() or self.islink(): self.fs.unlink(self.path) return 1 return None def do_duplicate(self, src): self._createDir() Unlink(self, None, None) e = Link(self, src, None) if isinstance(e, SCons.Errors.BuildError): desc = "Cannot duplicate `%s' in `%s': %s." % (src.path, self.dir.path, e.errstr) raise SCons.Errors.StopError(desc) self.linked = 1 # The Link() action may or may not have actually # created the file, depending on whether the -n # option was used or not. Delete the _exists and # _rexists attributes so they can be reevaluated. self.clear() memoizer_counters.append(SCons.Memoize.CountValue('exists')) def exists(self): try: return self._memo['exists'] except KeyError: pass # Duplicate from source path if we are set up to do this. if self.duplicate and not self.is_derived() and not self.linked: src = self.srcnode() if src is not self: # At this point, src is meant to be copied in a variant directory. src = src.rfile() if src.abspath != self.abspath: if src.exists(): self.do_duplicate(src) # Can't return 1 here because the duplication might # not actually occur if the -n option is being used. else: # The source file does not exist. Make sure no old # copy remains in the variant directory. if Base.exists(self) or self.islink(): self.fs.unlink(self.path) # Return None explicitly because the Base.exists() call # above will have cached its value if the file existed. self._memo['exists'] = None return None result = Base.exists(self) self._memo['exists'] = result return result # # SIGNATURE SUBSYSTEM # def get_max_drift_csig(self): """ Returns the content signature currently stored for this node if it's been unmodified longer than the max_drift value, or the max_drift value is 0. Returns None otherwise. """ old = self.get_stored_info() mtime = self.get_timestamp() max_drift = self.fs.max_drift if max_drift > 0: if (time.time() - mtime) > max_drift: try: n = old.ninfo if n.timestamp and n.csig and n.timestamp == mtime: return n.csig except AttributeError: pass elif max_drift == 0: try: return old.ninfo.csig except AttributeError: pass return None def get_csig(self): """ Generate a node's content signature, the digested signature of its content. node - the node cache - alternate node to use for the signature cache returns - the content signature """ ninfo = self.get_ninfo() try: return ninfo.csig except AttributeError: pass csig = self.get_max_drift_csig() if csig is None: try: if self.get_size() < SCons.Node.FS.File.md5_chunksize: contents = self.get_contents() else: csig = self.get_content_hash() except IOError: # This can happen if there's actually a directory on-disk, # which can be the case if they've disabled disk checks, # or if an action with a File target actually happens to # create a same-named directory by mistake. csig = '' else: if not csig: csig = SCons.Util.MD5signature(contents) ninfo.csig = csig return csig # # DECISION SUBSYSTEM # def builder_set(self, builder): SCons.Node.Node.builder_set(self, builder) self.changed_since_last_build = self.decide_target def changed_content(self, target, prev_ni): cur_csig = self.get_csig() try: return cur_csig != prev_ni.csig except AttributeError: return 1 def changed_state(self, target, prev_ni): return self.state != SCons.Node.up_to_date def changed_timestamp_then_content(self, target, prev_ni): if not self.changed_timestamp_match(target, prev_ni): try: self.get_ninfo().csig = prev_ni.csig except AttributeError: pass return False return self.changed_content(target, prev_ni) def changed_timestamp_newer(self, target, prev_ni): try: return self.get_timestamp() > target.get_timestamp() except AttributeError: return 1 def changed_timestamp_match(self, target, prev_ni): try: return self.get_timestamp() != prev_ni.timestamp except AttributeError: return 1 def decide_source(self, target, prev_ni): return target.get_build_env().decide_source(self, target, prev_ni) def decide_target(self, target, prev_ni): return target.get_build_env().decide_target(self, target, prev_ni) # Initialize this Node's decider function to decide_source() because # every file is a source file until it has a Builder attached... changed_since_last_build = decide_source def is_up_to_date(self): T = 0 if T: Trace('is_up_to_date(%s):' % self) if not self.exists(): if T: Trace(' not self.exists():') # The file doesn't exist locally... r = self.rfile() if r != self: # ...but there is one in a Repository... if not self.changed(r): if T: Trace(' changed(%s):' % r) # ...and it's even up-to-date... if self._local: # ...and they'd like a local copy. e = LocalCopy(self, r, None) if isinstance(e, SCons.Errors.BuildError): raise self.store_info() if T: Trace(' 1\n') return 1 self.changed() if T: Trace(' None\n') return None else: r = self.changed() if T: Trace(' self.exists(): %s\n' % r) return not r memoizer_counters.append(SCons.Memoize.CountValue('rfile')) def rfile(self): try: return self._memo['rfile'] except KeyError: pass result = self if not self.exists(): norm_name = _my_normcase(self.name) for dir in self.dir.get_all_rdirs(): try: node = dir.entries[norm_name] except KeyError: node = dir.file_on_disk(self.name) if node and node.exists() and \ (isinstance(node, File) or isinstance(node, Entry) \ or not node.is_derived()): result = node # Copy over our local attributes to the repository # Node so we identify shared object files in the # repository and don't assume they're static. # # This isn't perfect; the attribute would ideally # be attached to the object in the repository in # case it was built statically in the repository # and we changed it to shared locally, but that's # rarely the case and would only occur if you # intentionally used the same suffix for both # shared and static objects anyway. So this # should work well in practice. result.attributes = self.attributes break self._memo['rfile'] = result return result def rstr(self): return str(self.rfile()) def get_cachedir_csig(self): """ Fetch a Node's content signature for purposes of computing another Node's cachesig. This is a wrapper around the normal get_csig() method that handles the somewhat obscure case of using CacheDir with the -n option. Any files that don't exist would normally be "built" by fetching them from the cache, but the normal get_csig() method will try to open up the local file, which doesn't exist because the -n option meant we didn't actually pull the file from cachedir. But since the file *does* actually exist in the cachedir, we can use its contents for the csig. """ try: return self.cachedir_csig except AttributeError: pass cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self) if not self.exists() and cachefile and os.path.exists(cachefile): self.cachedir_csig = SCons.Util.MD5filesignature(cachefile, \ SCons.Node.FS.File.md5_chunksize * 1024) else: self.cachedir_csig = self.get_csig() return self.cachedir_csig def get_cachedir_bsig(self): try: return self.cachesig except AttributeError: pass # Add the path to the cache signature, because multiple # targets built by the same action will all have the same # build signature, and we have to differentiate them somehow. children = self.children() executor = self.get_executor() # sigs = [n.get_cachedir_csig() for n in children] sigs = map(lambda n: n.get_cachedir_csig(), children) sigs.append(SCons.Util.MD5signature(executor.get_contents())) sigs.append(self.path) result = self.cachesig = SCons.Util.MD5collect(sigs) return result default_fs = None def get_default_fs(): global default_fs if not default_fs: default_fs = FS() return default_fs class FileFinder: """ """ if SCons.Memoize.use_memoizer: __metaclass__ = SCons.Memoize.Memoized_Metaclass memoizer_counters = [] def __init__(self): self._memo = {} def filedir_lookup(self, p, fd=None): """ A helper method for find_file() that looks up a directory for a file we're trying to find. This only creates the Dir Node if it exists on-disk, since if the directory doesn't exist we know we won't find any files in it... :-) It would be more compact to just use this as a nested function with a default keyword argument (see the commented-out version below), but that doesn't work unless you have nested scopes, so we define it here just so this work under Python 1.5.2. """ if fd is None: fd = self.default_filedir dir, name = os.path.split(fd) drive, d = os.path.splitdrive(dir) if not name and d[:1] in ('/', os.sep): #return p.fs.get_root(drive).dir_on_disk(name) return p.fs.get_root(drive) if dir: p = self.filedir_lookup(p, dir) if not p: return None norm_name = _my_normcase(name) try: node = p.entries[norm_name] except KeyError: return p.dir_on_disk(name) if isinstance(node, Dir): return node if isinstance(node, Entry): node.must_be_same(Dir) return node return None def _find_file_key(self, filename, paths, verbose=None): return (filename, paths) memoizer_counters.append(SCons.Memoize.CountDict('find_file', _find_file_key)) def find_file(self, filename, paths, verbose=None): """ find_file(str, [Dir()]) -> [nodes] filename - a filename to find paths - a list of directory path *nodes* to search in. Can be represented as a list, a tuple, or a callable that is called with no arguments and returns the list or tuple. returns - the node created from the found file. Find a node corresponding to either a derived file or a file that exists already. Only the first file found is returned, and none is returned if no file is found. """ memo_key = self._find_file_key(filename, paths) try: memo_dict = self._memo['find_file'] except KeyError: memo_dict = {} self._memo['find_file'] = memo_dict else: try: return memo_dict[memo_key] except KeyError: pass if verbose and not callable(verbose): if not SCons.Util.is_String(verbose): verbose = "find_file" verbose = ' %s: ' % verbose verbose = lambda s, v=verbose: sys.stdout.write(v + s) filedir, filename = os.path.split(filename) if filedir: # More compact code that we can't use until we drop # support for Python 1.5.2: # #def filedir_lookup(p, fd=filedir): # """ # A helper function that looks up a directory for a file # we're trying to find. This only creates the Dir Node # if it exists on-disk, since if the directory doesn't # exist we know we won't find any files in it... :-) # """ # dir, name = os.path.split(fd) # if dir: # p = filedir_lookup(p, dir) # if not p: # return None # norm_name = _my_normcase(name) # try: # node = p.entries[norm_name] # except KeyError: # return p.dir_on_disk(name) # if isinstance(node, Dir): # return node # if isinstance(node, Entry): # node.must_be_same(Dir) # return node # if isinstance(node, Dir) or isinstance(node, Entry): # return node # return None #paths = filter(None, map(filedir_lookup, paths)) self.default_filedir = filedir paths = filter(None, map(self.filedir_lookup, paths)) result = None for dir in paths: if verbose: verbose("looking for '%s' in '%s' ...\n" % (filename, dir)) node, d = dir.srcdir_find_file(filename) if node: if verbose: verbose("... FOUND '%s' in '%s'\n" % (filename, d)) result = node break memo_dict[memo_key] = result return result find_file = FileFinder().find_file def invalidate_node_memos(targets): """ Invalidate the memoized values of all Nodes (files or directories) that are associated with the given entries. Has been added to clear the cache of nodes affected by a direct execution of an action (e.g. Delete/Copy/Chmod). Existing Node caches become inconsistent if the action is run through Execute(). The argument `targets` can be a single Node object or filename, or a sequence of Nodes/filenames. """ from traceback import extract_stack # First check if the cache really needs to be flushed. Only # actions run in the SConscript with Execute() seem to be # affected. XXX The way to check if Execute() is in the stacktrace # is a very dirty hack and should be replaced by a more sensible # solution. for f in extract_stack(): if f[2] == 'Execute' and f[0][-14:] == 'Environment.py': break else: # Dont have to invalidate, so return return if not SCons.Util.is_List(targets): targets = [targets] for entry in targets: # If the target is a Node object, clear the cache. If it is a # filename, look up potentially existing Node object first. try: entry.clear_memoized_values() except AttributeError: # Not a Node object, try to look up Node by filename. XXX # This creates Node objects even for those filenames which # do not correspond to an existing Node object. node = get_default_fs().Entry(entry) if node: node.clear_memoized_values() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/scons/scons.py0000755000175000017500000001360213606712377014112 0ustar kurtkurt#! /usr/bin/env python # # SCons - a Software Constructor # # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __revision__ = "src/script/scons.py 4369 2009/09/19 16:58:54 scons" __version__ = "1.2.0.d20090919" __build__ = "r4369[MODIFIED]" __buildsys__ = "scons-dev" __date__ = "2009/09/19 16:58:54" __developer__ = "scons" import os import os.path import sys ############################################################################## # BEGIN STANDARD SCons SCRIPT HEADER # # This is the cut-and-paste logic so that a self-contained script can # interoperate correctly with different SCons versions and installation # locations for the engine. If you modify anything in this section, you # should also change other scripts that use this same header. ############################################################################## # Strip the script directory from sys.path() so on case-insensitive # (WIN32) systems Python doesn't think that the "scons" script is the # "SCons" package. Replace it with our own library directories # (version-specific first, in case they installed by hand there, # followed by generic) so we pick up the right version of the build # engine modules if they're in either directory. script_dir = sys.path[0] if script_dir in sys.path: sys.path.remove(script_dir) libs = [] if "SCONS_LIB_DIR" in os.environ: libs.append(os.environ["SCONS_LIB_DIR"]) local_version = 'scons-local-' + __version__ local = 'scons-local' if script_dir: local_version = os.path.join(script_dir, local_version) local = os.path.join(script_dir, local) libs.append(os.path.abspath(local_version)) libs.append(os.path.abspath(local)) scons_version = 'scons-%s' % __version__ prefs = [] if sys.platform == 'win32': # sys.prefix is (likely) C:\Python*; # check only C:\Python*. prefs.append(sys.prefix) prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages')) else: # On other (POSIX) platforms, things are more complicated due to # the variety of path names and library locations. Try to be smart # about it. if script_dir == 'bin': # script_dir is `pwd`/bin; # check `pwd`/lib/scons*. prefs.append(os.getcwd()) else: if script_dir == '.' or script_dir == '': script_dir = os.getcwd() head, tail = os.path.split(script_dir) if tail == "bin": # script_dir is /foo/bin; # check /foo/lib/scons*. prefs.append(head) head, tail = os.path.split(sys.prefix) if tail == "usr": # sys.prefix is /foo/usr; # check /foo/usr/lib/scons* first, # then /foo/usr/local/lib/scons*. prefs.append(sys.prefix) prefs.append(os.path.join(sys.prefix, "local")) elif tail == "local": h, t = os.path.split(head) if t == "usr": # sys.prefix is /foo/usr/local; # check /foo/usr/local/lib/scons* first, # then /foo/usr/lib/scons*. prefs.append(sys.prefix) prefs.append(head) else: # sys.prefix is /foo/local; # check only /foo/local/lib/scons*. prefs.append(sys.prefix) else: # sys.prefix is /foo (ends in neither /usr or /local); # check only /foo/lib/scons*. prefs.append(sys.prefix) temp = map(lambda x: os.path.join(x, 'lib'), prefs) temp.extend(map(lambda x: os.path.join(x, 'lib', 'python' + sys.version[:3], 'site-packages'), prefs)) prefs = temp # Add the parent directory of the current python's library to the # preferences. On SuSE-91/AMD64, for example, this is /usr/lib64, # not /usr/lib. try: libpath = os.__file__ except AttributeError: pass else: # Split /usr/libfoo/python*/os.py to /usr/libfoo/python*. libpath, tail = os.path.split(libpath) # Split /usr/libfoo/python* to /usr/libfoo libpath, tail = os.path.split(libpath) # Check /usr/libfoo/scons*. prefs.append(libpath) # Look first for 'scons-__version__' in all of our preference libs, # then for 'scons'. libs.extend(map(lambda x: os.path.join(x, scons_version), prefs)) libs.extend(map(lambda x: os.path.join(x, 'scons'), prefs)) sys.path = libs + sys.path ############################################################################## # END STANDARD SCons SCRIPT HEADER ############################################################################## if __name__ == "__main__": import SCons.Script # this does all the work, and calls sys.exit # with the proper exit status when done. SCons.Script.main() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: pivy-0.6.5/README.md0000644000175000017500000000142013606712377012535 0ustar kurtkurtGeneral build instructions: --------------------------- [![Build Status](https://travis-ci.org/Coin3D/pivy.svg?branch=master)](https://travis-ci.org/Coin3D/pivy) Pivy uses [distutils][0]. To build Pivy, run ```bash $ python3 setup.py build $ python3 setup.py install ``` For older system/distros please use the `setup_old.py` script to build pivy. Reporting bugs: -------------- Please submit bug reports, feature requests, etc. to the [Pivy issue tracker][1]. Contact: -------- If you have any questions regarding Pivy or simply want to discuss with other Pivy users, you can do so at the general [coin-discuss mailinglist][2]. [0]: http://www.python.org/sigs/distutils-sig/ [1]: https://github.com/Coin3D/pivy/issues [2]: http://groups.google.com/group/coin3d-discuss pivy-0.6.5/packaging/0000755000175000017500000000000013606712377013205 5ustar kurtkurtpivy-0.6.5/packaging/gentoo/0000755000175000017500000000000013606712377014500 5ustar kurtkurtpivy-0.6.5/packaging/gentoo/pivy-svn-0.5.0.ebuild0000644000175000017500000000066513606712377020126 0ustar kurtkurt# Copyright 1999-2007 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ inherit eutils distutils subversion ESVN_REPO_URI="http://svn.coin3d.org/repos/Pivy/trunk" DESCRIPTION="Python Coin bindings" HOMEPAGE="http://pivy.coin3d.org/" LICENSE="as-is" SLOT="0" KEYWORDS="-* ~amd64 ~x86" IUSE="" DEPEND="virtual/python dev-lang/swig media-libs/coin media-libs/SoQt" RDEPEND="${DEPEND}" pivy-0.6.5/packaging/gentoo/README0000644000175000017500000000021313606712377015354 0ustar kurtkurtGentoo ebuild to build the most recent Pivy version from the subversion trunk. Suggested location: PORTDIR_OVERLAY/dev-python/pivy-svn/ pivy-0.6.5/packaging/debian/0000755000175000017500000000000013606712377014427 5ustar kurtkurtpivy-0.6.5/packaging/macosx/0000755000175000017500000000000013606712377014477 5ustar kurtkurtpivy-0.6.5/packaging/macosx/resources/0000755000175000017500000000000013606712377016511 5ustar kurtkurtpivy-0.6.5/packaging/macosx/resources/InstallationCheck.strings0000644000175000017500000000017213606712377023523 0ustar kurtkurt"23" = "Missing dependency: PyObjC not found. Please install PyObjC from http://pyobjc.sourceforge.net/ and try again."; pivy-0.6.5/packaging/macosx/resources/InstallationCheck0000755000175000017500000000064513606712377022043 0ustar kurtkurt#!/bin/bash # # This installation script just echoes the values of the available # arguments and environmental variables. # echo "Checking for PyObjC installation" if (python -c "import objc") then echo "OK, continuing installation" let retval=0 else echo "ERROR: You have to install PyObjC before installing Pivy!" let retval=119 fi echo "\$retval = $retval" echo "END INSTALLATIONCHECK SCRIPT" exit $retval pivy-0.6.5/packaging/macosx/resources/README.txt0000644000175000017500000000021113606712377020201 0ustar kurtkurtCopy InstallationCheck into Pivy.pkg/Contents/Resources/ Copy InstallationCheck.strings into Pivy.pkg/Contents/Resources/English.lproj pivy-0.6.5/packaging/macosx/Pivy.pkg/0000755000175000017500000000000013606712377016206 5ustar kurtkurtpivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/0000755000175000017500000000000013606712377020003 5ustar kurtkurtpivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/0000755000175000017500000000000013606712377021755 5ustar kurtkurtpivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/English.lproj/0000755000175000017500000000000013606712377024473 5ustar kurtkurtpivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/English.lproj/InstallationCheck.strings0000644000175000017500000000017213606712377031505 0ustar kurtkurt"23" = "Missing dependency: PyObjC not found. Please install PyObjC from http://pyobjc.sourceforge.net/ and try again."; pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/English.lproj/background.pdf0000755000175000017500000001472413606712377027320 0ustar kurtkurt%PDF-1.3 % 2 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream x+TT(TH-JN-()MQ( ( NU5Tp endstream endobj 4 0 obj 50 endobj 1 0 obj << /Type /Page /Parent 7 0 R /Resources 3 0 R /Contents 2 0 R >> endobj 3 0 obj << /ProcSet [ /PDF /ImageB /ImageC /ImageI ] /XObject << /Im1 5 0 R >> >> endobj 5 0 obj << /Length 6 0 R /Type /XObject /Subtype /Image /Width 100 /Height 100 /ColorSpace 8 0 R /Interpolate true /SMask 9 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xOA Q*PkFQ#2qt #F` e"( (D=-`>8C |[/:vS'^| f~gcn`X`X`X`X`ϷT*C8\nVrZ.,, 65u@O9-( >ݻ/>C@%RX"ؾ/ , w1{,^1 ND"YyGF`{e kCt~\h,"%r_DgO cϨ`M.tgg^M.|Ċa؞xcީcıqE y8fLEd2ck6AQÉ$ LTj!vݧd"0 J+^ IU+d۷IP a| VxBBሣS;% *^a֭[VTdG(GH }VH \#H e|@%: /Q@G/kx%^v02Ĕϫkp½R$zz)pcIENF1iոsnAB-5 KtƩM*|՘Jz GCW%ʎ^!7+u="s)j< J FWbJ' +NUsG؎fCᢰGfC{J2U}DKQW@r%\HN l$:eiFB/HBJ)$KJ2TFua…WRc*_,}ᳬppA{n?չ\ ɠ϶p<}y"#ϥ4gc Έ6]T8 Ȼ矯/,e5l\‘rYf%B zDzD0$|FTj?89fsZ66 7|AYQa)3I—mĈ"L7APtW";;5lJ 7TX_^BCT_-FEHketletUC^OÇţ)b1f htyJ%!*RhLBN5,--.Y$O=DVʑt(*ЎX{ VmȻfJJItr % v#ѣDupY)qRȊ*RT'^-;u $kì!i믣1Vn|Uw@᎞f8[=$fݫ- #VZ*Qw)|DN>ZDN}לmi:%TUXV40w,/5q(Z*3c Y_[Db~j0EyMq)7w + CBo<5-D+6XACt,Jʭjt2{#j.{DSSY;!+ eL4X8UʟM)+C/E"L4[NAfYJޝ=ꃿd\41.ş@t=b:^f7eji/ -npU[JØ(mt] \HG^:??]xF~HU[ HANAR,IGђ'E{F@hOԂ󲝑R6 ] d@f Kf nGwSF0HHހKoڤs J@UΈIC}tMW5> BaVRk{k [0SHH~0͑ +@CuJwA̤T: Qڠ`"wz; |ˆzYuv\F!*_~\ 12뽙DDG]mEQԵ4$~V(yWxƗB~/ EyLXT?FE2vxrR9!w*S39;Q+ZR( \J\s|Po\bzT_bݑ*e5 Lfܗtzo1^~gt)XU:' 0xdE,?ee3~+›(F+qV4ytE=HĐǡ]ZmmRVs([Exp8U|q* UJ1iևz#gbYx!$%ur2[^`)n˰U೸$7nhP*bdHw+W$WvOFw-kc'{p=LQCIE3c|`.'6߳WҸ~oO[&ELr$-=]1<0ph~{ CEjƠ5:WrIFuh~gln5yI@Ӱ])F:b898%.HB?ܹ R~)_xNW5Hu"x\3$)bb[YIGկzl^ ǼVgpz@xIɹA̔r} 1xӚݙQjyYRˍzץ.k'@qJ¥4}iiIӦwt4a94 ݈~gc*|k?1 D(<{!0.i!Wd/V$&pޤai2LTrGZ\V!JXI]SxrS=RZ?f\~\m=grU'`m/mlrf kNc M#.brT[4ԘzI0ANUXA C"%SU/"3wmHԾ6źRGL(ف JM&6]fAK dɂ2yf܁} xr?+6y3ܮkkkݭ0[e93jX=_W*ôTXHizq%z)zt&DC .v(^ɯPz_* {2I"%ˆs- % TJŭ! @]hc45^bk myqM++M%L$@!-INVQVTyT,6@y,(Ջ2 | QFPnZisX֤1(9qXQz- ;㱲(|Wt/pjB* X5D>$J~EIT358)TLlQJF|r+H*3ZsL#[ 4vb(D f}0P4,E єg2K|IH|$'v<6 o*TOqҒ@)@zJ2׹:&4$80R q{'ð Drz;0ܚ9p28Hg^nhvd!ȉ8T`X`X`X`X``/hI endstream endobj 6 0 obj 3971 endobj 9 0 obj << /Length 10 0 R /Type /XObject /Subtype /Image /Width 100 /Height 100 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x0 O{ڀ &i ߸@*Jrf<|Cj+|B1 7ӸJM"#g@@@@1vL7Fp9a72> stream x}OHQǿ%Be&RNW`oʶkξn%B.A1XI:b]"(73ڃ73{@](mzy(;>7PA+Xf$vlqd}䜛] UƬxiO:bM1Wg>q[ 2M'"()Y'ld4䗉2'&Sg^}8&w֚, \V:kݤ;iR;;\u?V\\C9u(JI]BSs_ QP5Fz׋G%t{3qWD0vz \}\$um+٬C;X9:Y^gB,\ACioci]g(L;z9AnI ꭰ4Iݠx#{zwAj}΅Q=8m (o{1cd5Ugҷtlaȱi"\.5汔^8tph0k!~D Thd6챖:>f&mxA4L&%kiĔ?Cqոm&/By#Ց%i'W:XlErr'=_ܗ)i7Ҭ,F|Nٮͯ6rm^ UHW5;?Ͱh endstream endobj 12 0 obj 706 endobj 8 0 obj [ /ICCBased 11 0 R ] endobj 7 0 obj << /Type /Pages /MediaBox [0 0 100 100] /Count 1 /Kids [ 1 0 R ] >> endobj 13 0 obj << /Type /Catalog /Pages 7 0 R /Version /1.4 >> endobj 14 0 obj << /CreationDate (D:20051007010005+02'00') /ModDate (D:20051007010005+02'00') /Producer (Mac OS X 10.4.2 Quartz PDFContext) >> endobj xref 0 15 0000000000 00000 n 0000000164 00000 n 0000000022 00000 n 0000000244 00000 n 0000000146 00000 n 0000000333 00000 n 0000004501 00000 n 0000005864 00000 n 0000005828 00000 n 0000004521 00000 n 0000004979 00000 n 0000004999 00000 n 0000005808 00000 n 0000005947 00000 n 0000006011 00000 n trailer << /Size 15 /Root 13 0 R /Info 14 0 R /ID [ <4ebb1a5f7a30e628c6d0b091283ae00e> <4ebb1a5f7a30e628c6d0b091283ae00e> ] >> startxref 6154 %%EOF pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/English.lproj/Description.plist0000644000175000017500000000053213606712377030033 0ustar kurtkurt IFPkgDescriptionDescription Pivy, the Coin binding for Python IFPkgDescriptionTitle Pivy pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/English.lproj/Welcome.rtf0000755000175000017500000000173713606712377026616 0ustar kurtkurt{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf110 {\fonttbl\f0\fnil\fcharset77 GillSans-Light;\f1\fnil\fcharset77 HelveticaNeue-Light;\f2\fnil\fcharset77 GillSans-LightItalic; \f3\fnil\fcharset77 LucidaGrande;} {\colortbl;\red255\green255\blue255;} \paperw11900\paperh16840\margl1440\margr1440\vieww9000\viewh8400\viewkind0 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural \f0\fs32 \cf0 \ \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li340\ql\qnatural\pardirnatural \fs28 \cf0 This will install Pivy, the Coin binding for Python. \ \ For more information about Pivy, please visit the Pivy website at http://pivy.coin3d.org/ \f1 \ \f0 \ \f2\i Dependencies: \f0\i0\fs8 \ \fs28 \ \f3 \uc0\u9632 \f0 PyObjC (see http://pyobjc.sourceforge.net/)\ \f3 \uc0\u9632 \f0 Coin and Sc21 (see http://www.coin3d.org/)\ \fs32 \ \ \fs20 Copyright \'a9 2002-2006 Tamer Fahmy\ \ } pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/English.lproj/Pivy.info0000644000175000017500000000050313606712377026275 0ustar kurtkurtTitle Pivy Version Description Pivy, the Coin binding for Python DefaultLocation /usr/lib/python2.3/site-packages/ DeleteWarning ### Package Flags NeedsAuthorization YES Required NO Relocatable NO RequiresReboot NO UseUserMask NO OverwritePermissions NO InstallFat NO RootVolumeOnly YES OnlyUpdateInstalledLanguages NO pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/InstallationCheck0000755000175000017500000000064513606712377025307 0ustar kurtkurt#!/bin/bash # # This installation script just echoes the values of the available # arguments and environmental variables. # echo "Checking for PyObjC installation" if (python -c "import objc") then echo "OK, continuing installation" let retval=0 else echo "ERROR: You have to install PyObjC before installing Pivy!" let retval=119 fi echo "\$retval = $retval" echo "END INSTALLATIONCHECK SCRIPT" exit $retval pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/package_version0000644000175000017500000000002113606712377025031 0ustar kurtkurtmajor: 0 minor: 4pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/Pivy.bom0000777000175000017500000000000013606712377025673 2../Archive.bomustar kurtkurtpivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/BundleVersions.plist0000644000175000017500000000027613606712377026001 0ustar kurtkurt pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/Pivy.sizes0000644000175000017500000000006013606712377023757 0ustar kurtkurtNumFiles 0 InstalledSize 22844 CompressedSize 0 pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Resources/Pivy.pax.gz0000777000175000017500000000000013606712377026757 2../Archive.pax.gzustar kurtkurtpivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Archive.bom0000644000175000017500000010620413606712377022066 0ustar kurtkurtBOMStore@6U#"<nfotreePaths "!%$76:9=<@?('+*.-1043treetree. dextree APCEfIndexBomInfoPathsHLIndexVIndex Size64APCEpivyPCEV&\__init__.pyPCE i__init__.pycPCE"Tn<Tn<_coin.soPCE9(e$(e$_sc21.soPCEeJ7=coin.pyPCE'7Dhcoin.pyc APCEgui #PC32T __init__.py &PCE; __init__.pyc )PCEt iM' iM' _soqt.so ,PCE%r}2 soqt.py /PCEC soqt.pyc2PCE5 sc21.py5PCEk]׉=sc21.pyc8PCJ=rsogui.py;PCEƆsogui.pyc>>#%sT 6,66q K""q#^"`f3^3u 3~333333304 4*4204b 4o4w4 444 4444455(505K5\5d05 555 555 666# 6/676R 6_6g6 6666n "1 pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/PkgInfo0000644000175000017500000000001013606712377021252 0ustar kurtkurtpmkrpkg1pivy-0.6.5/packaging/macosx/Pivy.pkg/Contents/Archive.pax.gz0000644000175000017500002436242313606712377022535 0ustar kurtkurt}\"hXXXZgja( (&(#!AE% &ﴴvΙX z\s^̼f53cy_*E>:pQ@~=:MM>گFsyZȁ|}QcrBDvU_Q?qbԔeq={04=#/3eJr{h } QiIaiylZNf|ɀT,CfRVRsI:ȐcS3S&dO5OM4d%Rs2W&L3LNL1LON6gZdHZzb䔄xdHLKNJ4dd?Nφ%LjjS SS䇲daY6 i9Y*` ?)9+D`wdRO!Shg$ kHffbHw$'%M͎eYȍt&Ӑyf|ȗȤ2TPl[`HNOM㛬YpM,0#0)IVS!ij"\MEfg'@jD(ke)!2d)2e}MU DI!Qâ 6#ƌd/ CGEĎ .EQaAc" #Ȩ1!QD֯Fc"GFF1G c94,:(dp@F(1j5a탆Q cJg@`HXHT5a!Q#Ԇ#]CDac c"FE ,T cGF"0̨q#/@!0  jPȘQ; 0N p|i /@ .tDFFFDEGde<2xؐ a"EG˦DX nFGX 4ܣNk6֍Fm+ cMO'/8qO?g6ܓm86\37p.?Elo1[WV;֍mGɇeì e'<?i Y-n쟚2FT^S{VJvR_ޤ,ͫgɆ>q-4\G!FQZ~~Y? 8u\ cڜ81*8&S'ˤ§ge';)7ߪ}s3a̹d$dMJO3IB&0 "0d 8o~6 ĉ r+9uJSbfeMA[#!=>ulF`Z? & cl2SMMvC9߸h0Ma~1'N΄VI io#٪+3"g0ڢLD@S0='Ng] vv(x_Ci<:$&:NG7 ) r2'fObٸU9YCo'fdg0r0 T0:ße&h ucRV4k9/piİA!6M8Q3vsrskhpH/T'}9.dsg);Y۾bXT\aEOHk?,eR&4d4ux 8}5mlNV]OVvb#$S&QB<#+/3}&-_@iĴq_y~3ryqrv=)uKv#~8v xqM4o$:[3?????????????_ڬ |s-(i&yM9!w|nd 9wwQ4fí< >GA;wYOgnGrgt-u\⸀\8n*e?Ϩcg^b}BݹXuzγJwX$snWrN+[6Ϟ.=Z"9^&μcs3㢬iw/rN`o!-nS>.kX 9=Gv~\CsK7-?8'/S{) XN$AjLsyO{ws1.E]rn8 e~s3wNgq+qF%O.el.H=Í4%\o{al 2C-s8/ymc& XQn~rl$4[oRЕM+ l9ɻn|r9?knyc$~ϝ]ə$+p~o~&w5_>"dz,&P8ݗ ?au])q7"?knyI3{Y9N\9QNO]C7W27-V̜jS'%e,{|#m{nSou,II~?BHRS¯iĶ҂7i/Il{n<#?k8On{7# d;L'ɲ=WQ M \CGMr!"s. < lUrſcm?_황a$ ݁9HƔro<e{D.V;-퀜z\/|&;~Sb*eyDZC풄’[؂dEƬ+u\skmN;WfˆtH.N[$Xz mh^}MŗN*=Z3Wivnܼks?p}|]N3pZ[8蠖$-Z.Z. s\[ zp墠HU2P+p)ԿiZky3+Zp. rr7?k &\uT.2;*=95x~6O \s1dO?ʗSAZsr=YQd=/.[<=3VmO{i Iy{a;/EA[3pMƁ w-MszmQM&]$;4w \h}N:$"ʴRk2ݤ[{nJZ ["NjI z0n-_9p}#3>/rq䈩BED*–.v 6סk9u\? ܛϝAu}C[6Bwևm}8h9r|(^Qy$Y&ulȭkPY p-EƂkbm߾Z[._}/=rWsd=/#Akj;q2$ ߚ%tq5%֖? 6my3 Wjßp}{L?W8rb–P]? o#sAWCAW߫)ȟ3e;Moh? Ԑ!Op=Csm} ;̖h><[A$a-.. _o= l@sͱbI%R 0~g_[3 gY/߇?nBF 1?Vϯ`ÏcS[eKl}Zl9Q#}{ W1EĆ3O<(gLڼݟ/oOs07+?IecbŶ.ھo>͟[ئ(uؕ- /~6j+ a=q\}2F\iYC{O)B]~M S0~4> G{J_h<S?k{~$ے Fw^?6e;ekw|I Ʈ(`+'{s^bˉ ۾3~N݂moDdFC6skmߵY^xf?eoZo~#|EF>x8ۇ"lCdR_]0?#0I(_a8bӉy\Stb?|8w6?tbvCԧ.kQE+ێʑzI< s>ngRNWۿ? b!_xYlł[-ue=/t00W_<,ZI kc<)fg4y굏{>1D ?m|B[Q]H%q/6Ho1^BmU'k[kxFṕ5J6?m"Ŗ>$ q hQyB mm1_۶#CIlٟ¾'~)#|//@7}; q~b_!v`~6"~d0 #|F"~mc:>n?bF߸Zǒ$~y*F?>-ھJG*f4;mv?%6׫?:g'}\k{G;pW_W1=D]Z+t.zۈ{#_Q|Kezb?Iho{%qa3‡~v"m5oV|N\Boa$?Wh F%qֿ񿒑w{>1sȆHB _/gK3~?b?#~VSW#歹G F!`]ݫ,7v5@?] ob߬??|Kg/.?W7o#~3ڮDgc˝nCEo>;Ow4>'F#_e4C7m?w@D㷯2ܱ )F<ſ'2h|j)#XG9]HЯ#fgzqH?꛷ (3ӀO'Ʒ {EFۋ;럟E>_񳐑߇=mH? }z~⧌ߗ'~T1/4"16࿖liߴo u۰o0%>/}6_:4>^hweI|]QQ:'bhY0Ɂf2_k`S|98_vA5o.<}~>߃~Z"I@ lO/} 8Oğ{˨>Ym)oƼwJk2J͋R&ڿT߼ԬρyAY4oN^Y} 2R˖]뀳zȆ-r!Zk{Y퐧U{qގ2= 0ﱔ/i7`?\Ц?/\t5}vF6J*GM_v r4E@{ZI񭹌߁TIu?c%5 aV`ORt+~9} >['RD{1O6A*m:l%ߥY:7B?If3ac>Ylz?oլuXy}Zl:w5մuP؈5?bNۓ;^/nױ+ZW|S_YsgqA-/3mqSYԧYM2I| S:߷!O_}>Gk{Ci W%q9nR:6@XZw6?N -#(02") ^k OIDӞފ/|<ͿI~^D͚v`;G1wR7곽KߟÑk+*3kKb;ւト7oD3ko=W<`>^=n-~t_ׁネs(Lw:_c<\̠NXT8ެo}&v|g\8 s9~\_K! /5+Ł+ۂm_LY_`sHI,?!?0<-?+g\^uc).J,/ ^bItcZa^_/_F>RLsu x/1Mo^Dk{LFoo>P  D_{ڻDw'etߦ@?l>^J_#]5ֽ^2YuKog)Ou6ԍ/)TkzIxWX:A%oi] ‡48}'Xe*j(G J_McWA%Uo<+?h/J[/8ܿv_ сPG/25Ik_ߥ('0ZyDg/J$_M۾ /!btJ4^+MۣI(8r_Ϩ[).NԹEy `/F8F_CyA)DM݁lg kNwE$>OZ? :W^姠iF󿯟|<+\o9:i1[7&0}o:_l h~vBe5 }?נN? o]Ql߬5G)7Ot'l9Omfd;*Sg[''*},<_3:iۗ>R!Os#Cf_"e~&FW=v/WG&^'9 |,<#f :2Q[cu,3Jb&1zq^ /@_ej$N#<@u:?񓱌_%cR(BwWlfgZ:RMsQ,tGH:,ulߌߣYrHcq I2>gNw1Tgb{#w1'bGmE;M}u6/?PF\( h"=^%1XSG2ZX DS)e|#L&SlggI?خsB7&E)ńPeM!]0Fe1O?Lꨵ}2d" eo) &(2KC(wKWHb`BDD_Y6qFo)3Owخ},`!Ibd ubտ﯄> e0_$b>wa%5XDa\"#:ivF^8Gpķ\`?|_3Z5:JD"A͊wx'!17k'.OFϡ͚l~=/Qf3*G/6WP=͊iӒ8 cO9~@A B `OV3P7'ο""_FB?#ϻ Ӑ`yk%I83D'?D8#σֿ8qF/!"0 9cT a'~׆H/|q8ҧ#0_~?Fp=c?s0#D?7U~{Ib4b>#Ϲg"c9ύ&"1dI"!*_pEHG$1?&F/E$C@_.cP#2l`l?1Y`&IM&ҏH~M<#*D_D 3,?@$"6|F/y##A< GHiQQF7|7" dbI '灌ou8wE@F7C:^@B~BÈCX_|Bmп??<+D9*_,/W>?? пA?3?Y_|B_>*_w!_DC?F/;gB'T~2I? g ҧ#Cn8Q'H3>QigO'0DIF!T~aD0AÌ<3AO?n(0ASQ#m|oFK|BތK}ތ{ y P!Fυ+;!HIDfO7{3sOcoFOC^'O_刟^SG#{2N$>N'#QГ/>1s/]%Cu>H_ !<? {0DmFZHYQ8пmHYLSPf`L &??D#(~F1"gL##OkA@H̀OvOwFfDHP?*_?g 1F$DTuc SQ܍ӡ+tWFO@ ߕп/^Fz4OW?2:';Qp/#OM|B #O׉??]? i$?]&be|ЧѦn0r=:beI|kS^qoo4kS$>f?'4k|OD'}  ?67kctf9X3wnP߃ߙX|$_OF|X'~OF'l3 ].FO~Xw?|~{?EߚaNFO>&}k'#'C_ ߉CqhN }/BfTtb)"|F#G"}z0_'{/?"A'ća?H}`H_QHIQC?~GFO˛@H7_L@H[qd;#'BiHh|q#'\ ֿb|BQ#/6|Fw&_#{od'_od$|]gxQ,{>_\9/6>9@,w1?u|MUh?|$vuX? Ͽ/yhknY;?t7kG&׼sߙ Wu]xq{>?d|pHoks ;~[:i1{!܇_Y8ϗĎd/eX"~~eW*ަ?WAbfwy[w^Y7߆?F\nο-k먂U6ډHgvzj}ډl"۶?ׯ_G|b QmOa:j<=_#?"~.1yL݈O"/1 \7b";bR|QH/'gCO>ϟ?m "~~fp%ֿm@]XHa$ѕh>#>1h}F Dbq?c/!~.0V'ֿ"gdIt7~֟g^O~F3QH#$ eO?|6Gב>dQ߰3i'6|F|bO:s''\ߴ#t4]%>Ͽ֞k{$XYFRYFhwI'ף_xW=Qp8k p/'DhcY'?Fê$ֿ/4x%>1?HoBUӌ| EiFM#i? FC1E7^A@Daon~8n>uҶ]'k]AWvGSbcϿ2^tE:~)<?B<>>\~?o?pO('u|Ic#9Gc~=E]!|t7XC6|F0>ֿH$*ֿЈs>ֿ_i~Z?Oi~Z?Oi~Z?Oi~Z?OQ Y#f=, oY.Tb@ q &3$ǂ*8/Bίsṋa[rk\Hop~+{$sJ)~+`glww_iهwG:K|㶘Sm#V>\/Wǭ vT2~b;^8w;<yb-σ]{&r#8sb̓8NTqHNҮGr)Iضi6oM.C}@d*ހs"sNᦄwVj]~fd\t 8ɹIrIpj=mjJ+ of[Yߝ4`w5Z,gq\V.uݿp^6{'pܭ{'<^^2$Xg{]sQj-KnSl9T_n]FyiPQ8)'9n]WxHBu_FWgHo(s[smB{ g{4qmP~%K¨SiSӧZN9% W_9UlcgY½q3}x~*;YE X^LQ=+ yRaR$햌W*ᚗrmU|m!-NMVmj_jy ߻7ɪ=e' lMѻJy)̳et|N҇ ZH~957rnօcn6J{Bs, Wq#\j܌Z妮V I7]!-7Nv'oCܜUykqSj{ww_xUI'<s3rK H*}H? %}mK(St[iXFW7Pf7JQd-==PwRsP<&쨖W4EQtҎUI+SssR\wӗOB)͗#p:uQ ·uQ>Z,_i󛘛ܬrE܀F^p& ![܈z57_T:y&l8mZ7i=07!ܼers>n[{ύb-^]-rSi}x%3nZ]17U{7a`K4l V)kTyku>n}K,p_|~T|=fZč [>jbn.iY旵5À4mS֗~GvM6h䊒7w RfE'7QZ.{tԟ7 2ڶm`*3m~`w4}뒰ʭ>lou∶pX_<52h !ZT$k5rEF!}WJ>@FIRÁJ>,(L.mPۊan0-7;C]C6*rGQfa#2߻~cT5W i!IzF+8PGCnC G+|(Bj9[_J{{U"ܬX|>nC;]1>;?lCzC9Ku[n6l J:QgRCo@q4EGnan^[{/M#`[Gn+17Zn_rsn>nځ.6hLJ/p E"_nk{-D_257WqeGܜMe4z#RtB'57{nbnE!nZ~8]ikMGqcyuqZ|R_jkiA_xҮ_Jil]IB7~8 烑/gt.Ő>.u>B+D{ZNzۮ?NRŔyLgzjnn^Y썸| fpM62b~c Ng /m(_>Pw]dZ%kZ} u,r>nn]ߑM$Uo]kˈP˩"|o8iv>'̍/,JLS~J_JiO:nyupݾ6I]F)u;.v.Ң͒}]:GyDw[NU-[I[xGi_l-ɒPCk+$ )jnG ` W{ߤmȀe_-7RAuO6utoo\CP >ћ7,QS6nژ_ql Q6nB:Q>|M|O-7_䆓5NMŔ} ҷ{"~Dyt I7R H;O7wX/.F8 /ѯ'Λq-7k9X7CZD~C~,%\J:w;Sm$nX! +ADٔu?uJJc I? y6'gGPgD?^ } u#E?΢?x-NV\R=6j/:DI?Ug.]g"}Q >I_V_Rk>OQ[=B.jAn`:S߾i~3zIx }J|u(3O W)Dn["s69v;[c'pB/'rD?6Z?Z7٭Dݦi)دs/K8zMw+5Cnwx nB-*񽥝ss2nŮZn~'݌+k{(4bnf\EԆZ>}{aKsn_u-+!-;16?~tOpJ#ϯ.KKk:X+Xy6gme/oEIXl|X&"#"{6jϥ?{t?6#~RmBڸ[v񙫑3(tSϋ-.A^,vanf:Ps$Vkk">mm3}(evLy(K{JB)<ϰOD_:e` `Я.[F-79? GGC5~ >+oI)qni>]E<),dJ9,"$q鰩7*{6y&M,g2&k\քM6eehmЦ&} 7$aA#m=2Oyד9_qa3E:E5vJP&s[ osZvWſ&OJ7?])zJkZfE3C07&PكsS$MM~ZnWhn _N~Ǜi\+ li@7_QY:S9O =u\lJD̙(y\&[m^l2mVE؄?\gӹPRfgSbAZ:nM *Sbu% /$l-ݦĿ߱[Kj;SOg ܚ×620%6s3Ꜹri-끩am-h;m< sO}=$z? eRk8qr&de]|g*Ȏcf+O)+;^-sgns׭{?5Y9V{g=iN\ gdO-$#o7])~`+;yV'?&ug=P(]_$no onP˻CO yUaϬBg YC-[YGX.g=}߇ 5W{hW\O?Du$>W=J㚽Tdό]>pMY E>+.[|󙳒Pܗ(ӴC =Z)~0my޼1MkLZӳԚv;t7j]_rr×ydCGuNdy?4'0:vi0T3UC'PKm<$3b<4hpy6'a%yOgJۥCkJTk qN\nc`K"$f^!f:mi-a6ٷtkU~r)pY/4C-5|MQ" 85s;Bn;ƛQΰjY{_?uwq[>$adYYP$s={Z{E _Rf]C=O?l4I'r'Q`uFJ#kL=&2g9~l 1w<Sõ ;N0;N#(;Ζw+⊔gbJr.r%pneCA7\2| gnn}p3>KiQ(o_N߈ƿ>|DwVѹ(o9/ǃmh?j/h\]B_6m}Vo׷iPciPure.;2o(>I9sn"'`nbc7GB-U𽩱Jy/krS/?K 7jnSn`nb7C-{/HB5717iWf>n0CC᪔vѽ17 CUh7.0R=/q%i[fA7k!M^PꛩgBOD{XeYmoZ*{S\ss[2(jhW::ҧ]T_`!IHW}DQֿs%a*m+pF4e~cn"m_b<lSb`n~&sC_,+Ovga[07cl?3bgR ~V ?>|Mr?2j[ugڟX~<_}vjZA/0n}M"/·Ѷ/ZV_$`1ui|BB/J%e c]G_脹@_;jy"_|yF0^2Z(@/H_R'ؕh f$Pk-ShS_f$e:t$$_ssqj#H[h~%  ֿ G- ,$ֿ=قo{HBzq^?ŸFYPPiߠ9ֿ۟&߆omC-eua,e[0e[o{Lֿ7?(ߌgֿ=N B mpbZ717? r敫ٽUF,V9& 9z q{n Usss}w-7Cܼ|L7 )DIJzAo&^uޡ!jo8i 4hYP]%az:=G#OI;p3sP[{*s+l롮o-7+qpCp3NQtn5uc07ň`Kg|o4dmjn*xͷ˓sͷnRyv͠4ɨ O ؈.S/Zn? P(ح&O4sx?2wt~nvVIB?IeZnPsП p#Aڝn:LPy_4j)مІS'x-7~Jtq4*dڭJFB̍'jáLPY?7$az7>&V`o/>ҧ&Wf؝6fy 6"2-m64Z71~s|(ѹv(ql渚hG`nBCւ߶mv9febB_c_WTDBڂއ>Cz7_Uˍlm1d+h?{m@ FD[F`mnc ZnDot^FWtl~6}~/'BvE /Pn#(ߵIwv]< ~3B'`6/xK/F/f% /G+u{vK-W7 scLE]q&wx~nޝ/ #O|AQ':?yFn|&}17F n̡gFf2IW!t1Ll~Ah 7Av4a?t @#|`^?7_>Hr3rmo7C vy{먚 h#17P;]j'ο j@ T}-B_}>Aˍ/|߾PşoƣovGߺ. ο l_0B}-FwhO9yn~Al?GwOoanoݲۀ!v{kG96O_ ο:P;6~M_tm[8ֿnBRg|h/\UHpwg%S;$t݃17>;Worhwu;.o>Ƈrt߽OQοg7~5]yzl!ο{߽-m3Zn6@i܌E"y*-?CZ3(s PhChb;&I+ԒMׂ֛%a?ec?ޔu⡔61(?hWPKS ~qz)(vO nJS/JS˒% Vv{#P}DS/6ԒN?-IOF͇tO5>-FOڭ⟺O=QKie*$ im$ ډwQ?M!ϲK2ε;_x$F?=\C-iD߂7K]S >ԃ3M_H*vG(+?O?`]bJ3iMI73GU:׿V/<@Oy).i_C⿼PKD"k@ ⿪nH u 1~u%+EgW[-kףs܌@__Q _-~.NF3kI(_NeuWs3u&⿺/g"_ VA}'㿌17(_])_uU^eQWx57P'u/r _}[U 㿠|cnR⿺P⿒tUzIejelwl0⿜/Z/U@]:?H{EJU⣴zH[⟱oB_w_^(|%z_ol/a>u%+Agghwm仔PNҹwuI@[[*[K_bhBӂ+36_>6SMYӕK;4V?[??c93:l!?n`ܼs\ˍ'8矖{JB%v2 ҞwOٍW+^E܀P~nV@_Lwvh뤖Y ϣ3m Pt]n:cnplK'RI{JM%J-7w6hyz>n^o"¿H}{\TU Bajab5-Me!HL0c 2 x)T05-,5---5,-L-KP4Ѡxמsp֌}|auߵHEۂ=FdWAk!TĴ#Z5u\{MQhk;F쥟+ț{a_nBɺ7!ڍ3M.T7!uS{p=l@#Fv?\߮Doƿ]/FκJڊ\_lmF/K QR_{q}}I}ÞPGF^+x}Xl+bU꟯g! 3|OotN+ӁŽ=MQ'$XV|-V[aV,2ͅ8ۑK+oMo)c଼i4H?P[6HUkmo7f7p[0[ g]-2dDi1woHoFpo"5-㬻2o70F5Bݫ-7cr٘o o~]u0Z]FCFd[Zk-̂nYw f7` 0B/kpӇԗ!?``/xüj/xal,EA?a?7K~a>dwGs3? ;1?W_ϫ!9y_[!?w+ZcD;Mg#~Hݾ/oA&{g@!|65y I?3ƈ ?voZ_6+90eWWZ ? &mHw*Wb?Y ^77Yo^e!oVig𻋐_|pU`ۅVg/LovF&w#T#2K7dWa|+w}^r?x ?p!ko(F5?^hG/lk25}_ypZ?N ]-Կe w(ֿ%V>[ msYcc=2_zx?_lyf{dphֿk0w`pNj׿kR!x铌XCìl);:Ly>xaߛ^F{Iַ1#뿳\FUH7|ݪJȯڛZSUm^&Q=<|=X= IͰM@۪n+gngkLV=Y7ipN 1Hw5RX {Ax6/0=ea/?!_?VQc@'m*! 7ߵL9qS^g0"jhɞ?Ey߽@+jj]d;av혚\HʴÇ>:sVb4e8lu;oRzvl% v$es*?H z~fFκ4Jpdd;$a:?w?DRN'M3 U/_ZϵSL6Xudߥ{CZ1MU[l[w! 1ԂYxowYÀ~9]%̯>k HF+Mc4?ke0+Q4.{Ej-Qy= =j^|_}ŬW 7JXo*6BPW;VXbg-WtW;<_9FjNve8ؐofi/RlD`?ϰjsk?}?v xI@~m!Aߦf)Fv~=LNv03w3a6CSS`i 8~"ID~MQD/?9w{ $"CU~W/?gd/Zr!>h]/'s7 b/w7{}-@i?B}Ul sA'N"|{ Om|!KȏN|/ƅ+³Fmf`UK^Ͷ:xezUV4.1㢝ɗz(?y׭BbC6CCalfS?Σñs_w;ۤ_NG&R{RKYKtiοՒ+Z)3560xo?U ~_L}H2gd*o3k>dG 0ǟ-c`g]7ԪU7X351B ?cGЍ?g &Q;NruG*f?3!?!Ǯ*G??q6z>dcY[77Q*d ǟRLE?!ǛT>c pFWgij ' (Yw#?j .C ̿moiGx bt5%lb_g/ ſh/a PV!Ays頂OxY= W;P}k=NֿzS<|W|y|?/3E/#v*BsUwOO =zKB￵Sm,~U_ p /r ?V5 yĿhy|Vg_v3}%p]G/ U r38{/PC7HB_)v!*OXo?_ k'L8;FG}_/݉ՊЏ ?㗵?-&+e_$U"5-=~T |L1Gv/AP_?Њ1oA^r /F?dς?j aV"_&뿹<}JGBNRU?2h&[n_/LGLuv)Io*?QOL!ۈ&O߆@%Nt$/_,ZBoo d_쿣+8$LsV??G?X1^|vOJ`Evx2SVXa?[\[*,D"E*pA0oL?)3(}5d>8o M(}@sg$[o0C/6#XBwȇFX?c77LCp TOQ.ܿmB'@wPL6  )8CEwROoBwX{-/ 8߈33?\?7"coBy@? ?O3o@;!?}k?E B4sG) IR ο!oWA+ }O),!ğr=m?{!m+?Iyy!oS'k0Ae9SpF`F u?ro?Vn!b~Yjkw ߏy׺$[?_V@8 K-OQw [L35(|p'QAEk]ǟ-Tx9b '?S?< [CN~m5+@PCh!`OAcy~v_iF“Ɠ9qĹ'dX*uc N;WC;NV24Y'_<+aQf]ڿTc %NDS' N:y/˕_Aj/2-yqY yT֫xY.zv^c,d9>௛񵜙BbYg{MHħX$? :%U⬭8L?γ?Yҧqg1rPkT$Cus>UsvP[ꃰxJ?zݺ xGcVvp␚ny?dC4r[N(n $~~L!5TSW񺞿Iqj3gpC v`WfqYoUB#%:۶S&ouZ@6(X{`EO^ymQ-5_ E0|C=;}؃?anee!7 =y;컺niak}㱼^ϓf=@KxyґבrH\6I[vxm-ü:/g WAs˚n4VEdv"ۡH:zWf=W][2Ї>2av|)Ws?;.C_ƥy;ɖS,ǥnsd;AZgC_COu%-;/g xkCffd;QkzL;WCbW i6ǙvxCn pF*YN?"R yt8*ܿv(f huH|gd;v8Rf zٟn/m&BO^unO kAؤ }Qd?vC?*AcM@td1ݐWþ?O4xn|ֻK際] xI?x~XؖNYZg;y?{3d;R?t=U1moD3^u}sM_})^ׯ )d>8IO^|\V{P 둻@Cbw=GV^γցt-hkYpFlU:xb$e?#ၮjvw} Uj+ow~0;GX5]w|8f|uPuM_;:X)}M,N_BϷ&(} 9}xbޒ yfuuy΃ 7NQ ʯ/ ȿWQ.5?jUtW%#_{6ϿZ?S[kәtÜ.%ߤ_?trݣx yΛ9f!oϿ]h#櫙w4|~w]/&_72|֜(T<Ʒy5_\S[ 3Z6gUڨNjG'%fw5tZ|gGq9r];0Hg^vwYg+3 PΓ>-w *dl3+6h?M:^gj t6Iyx]<%擓j `3N s*%'cjpOGzQL10fÓ,;;k7f T5نMa<ߨ&hw}!l}"j/0e!p>iuP^e]|NMW>b5l7FlZq'FG+O-!'qAMg 9?]O[5ڏNZ~3xwW=|p:w<¼4n#",!X ?]U- ?̢ώiy]uN93f L_{gX:XXib1?TjgG*^ǐ?Zy74?ct^sQ#~C^$[@rݘEEo?7Q*}@5ٖ?,2bZE!svI|L-ךpgfwʥ{ML, ^۫<v Z~~5;\gSoG(ǣ ?Z#)?}pVe"?JEw _eHD)<v})ƿ ؇`:[EaU) !UI@+9SY]dY2dYWSrwB4/Hwo8ߤI5HWY9]GGȲT5hC+i e1w;6 [^;k|p~Ie?<.k"N}."o+47|,]"R:kʲ./V50' o*,YHoa Mb_:Lm?SkZߥDuX,j6Zcp(_xY2[O>_ޟ&ks@+sQYwȲwRui DRES@K? #?y :4UuIW5Y6-gE)*DVgbOmO1?/eM@+yq|5@5,Ej[]O .e}3AMVMOze2VFɲ.گ(kCg,1j6(ZcyEn e-8&klCwp4^!dY ReZitVɲIeͯQկПpqZ^e9j\އw0oCeYOBd Q'Q%:'˺p_4+:([ua5Y+~Gjܠ@YdO0B@_Τɲލ?-Pc,SAxXD0QcvvwjȲ&m&H@_C5LQVh=4?yS|_@P|h53SY(<$$EYd*kN^V0D@EYVc^V폢-zW,jz *k7/]dY_Sv jڊ_O#dY+Гe?R7OϽhZCfZ?R7wWY)>z-kseY+ g|{}IKFƲ~b/e"&h /o?V?QLBpbiT=eY,˚[&?s = o,kKQVz1cdY%!e5ުe?&˚M0_֎eG(; 3 HkC>_`ןۑkb__;}{\qҧ>͉ 0SvQ6r7=!vǜrGʴOWOSzX1Ltdx1^MH?;ʴf'<<G?KqZEc2d!?:MxELrXvc?SqX_Q\M2 )~^Y}b <i}/+W4C6˾^eÙ+6 z&vQYKWo5CU 0umG^ˌ˦پ_iy~IocC"za^Ȩ^[mLMPC7Ŵ͞7mx7x0Ow&o123;oi^=aϛ8iGYi~#)_\"AbD/Esg0+_P|+?]'󟟡WC4?] _+˿;2(?K,ϼ!OD!5{L|?߂OS|: vy_h H?S*Ї0D$_YSTg(W}>#d>8o3yw]%zjF C;5tg:-G>ӹZtE/)_}2B/"/"܄_SĿ]A/Z}&"T/n*r#yVr r~ p?#9Yd;)F/]dEI)!wA//' vucB/$E/N/6$E/.%_ESYD/7 g/R'߀_QĿ(Z<1v7u;<9eq(GvB/O+_N-ֶ!Ne"8M/zcLTĿ_YKG2ArY}(Ѳ/k2Ar`_ )E1nc/CScn/s<9~ۛyvGa޿nE޿!O* %w/k[{Qco4SQE޿+\ncyYÑq?Cl%1ϐp{σ>} Ñ'߿1[o^{ }=w&O߿)-?v0f:qrțPydbCufݴBM,$5YR~2M c+J}Ͳa%cRd Ov(&OsV0o>'{eY[Wʲ>6SQV#g4l /k c%jS8",룋d1%ԮPym,룚h:QpAZdcCG퀰B?&+,|T;zfd em?O=ܻ ݱp~ ])˚4BQ@kK0e e]&k6C(4eHu5YK ?;0GHkϏ\1N qx2}'-l=? C瀋9q>b v=`hgde%Ez?n teCgca@ٛss7O̥WXQs|a8`_QO]L!2%2)Qq3 -O~?.'à뛅J$o+}kABRC,/[W!CbO*~*$+:u 7C0ǚ!{8$t~> {Ne !!H?B1x!LD%~#+A`>m B+a]_(ɜq!ΟV"H?\1?;1I?vIl%#0@@+8)a ۙ=$B3  )߯LqEH6CY-ԗ4Aܧ8e:Ne e!+˲6&I@?:^_k|Ruh= 0Pc C}{-_?g`o__^G f _)ӿ<0_϶/g#i,F+`{_{EڿZ{5B_y!v7zvp5`@eDg=g[Ua1CoK0(?,Z(lvu;| {Wh?/wg!5;8g'm!2d(?ڑG? a~ygsOfQ5aNfѕ1ht>bw*(.Z>2/Yr/n͸p~TnFjYv^WC?vX-[R; @?nff ;7GOj ]-;to n/+ 9SxT8?ϑXe!of7HӇsU[q;>m~i-p xg,WmStR+PC_.Co&?5`!O"O}}?yfш*ݴЮiʶYvᬍ[E?kUöeB`avvS6hNt~6Fb}?x{k;,S̸woΧv87ײKgSC\ EG0CBWF >^^ vXfhUzhwѦ4v#ȲCنvbE0ԅd;ܦ9`38S_Vț vǚyKx;Yk j,6%tu;l1|AI1[Ҕj!GG! 6C{ܴCw~)i_՘vuE?VC`CoFҏoz١(h5R.S>ld;ܚfV=WCC h7IaviSN2`@?kn:z`5K]C$К|́Όf-3~c;^kӱCVNTQ;TTv묍JYGu;l 4F㙸Tۡbl(69Qf>e;>&6C0K@iN5p|,$3vTiL ïŲ"?no HGwG rϷвvƦS;*k^S;Ԕc Nv} g|;#s~x w>k K+%$PĿ|qُ_Ay]_OV=Ŝ﬽8E: }yk~1ʳ#|?Ex['~y=+\6~yo{ ==}єԤ)1[F? \#>|K)|ǔD[إ@,H-o]]L-;v- ~Y#~ {PƄo)L[k7# c4Rww r)y8t?axq 5?h0q)2L;e=`=r\Y#83N%2vu~B2vnZv ﵌C mj;L kg|S6H\?ohiMmxf@O6#Y{c.s mq%jڅ&1#S~Xz^.s!O!c<`DV[ .*-%W_9Q ݭ w=ӆ 3=fƸB4-|O q[=1|rD[6{% cެ%>wMFYt'[t{0o#C~zKVf8k;'G]g/jw̬nƲf -1Z_{bކnmXĨ."H oØ~ [6|-ęjV6НdҽolFMhImxdegm%j6|\Ɔ- mD3ׅaÍ&YنAgt?x>wR9Ŝ rOjS!z器wo|wCi<|~ww nr@sky3uxCcLpֶ@usznV wf;A'V,?;~틒}:E,C;s&[5ӿv zh/:{ r3C:Eo'VNB m)3Z4uC2Y'*ˏ)Wook}z1T6wCyW|ݐuJk9'[T'Wb2XT1: z1K}~y; $/Ös|x]'でF_k%t4V;fhV0:zfc-SV~H=XY}I?|"M!_ctf؛UN>_o"]:: TĴ&f>?E|Nz0')6uM)O@g6* ߥ|7ӎzpp{;8^ΆvE,.|Q;D{XϞdW#4=ln,AFI_hbgmx}%J-kyCz@֗-R}5K_K7™0w;w= 焭;&ͽu_D'${t{]s6ھ`>Wj8tn>}\8@о_>`C_>F_|׿xg5 hBn?tGT/᪫Kk3N7n^˳) ;Оl?Z3D'ޕiG޷l5={S[% O#Oz}}-BLߦ(Cv7cMvoi<>QvܴͼMց>d?y'-d]wE tCNU ?|WAVQ'w;na AVQ ^f|rllx|!O}hMI{O.aw`dZy{w^M:\Z~lΒyf6_̒wY2k,&RC?lV}?:0w#.G6 4meCk= uՂ{߆;Xٞǎ%3"Vy?{yukZ)t{?gF~;sߗ]7?^-?vxf(hHUr.dqCq#w7=|2Jxy}%s"W}ycay)S XqEG^_BЕ{qW8ky Lk1=3zVy_~G9!|y~Rd]ZLyv]r\.;|Oas`ERoؙ䋔hȅb<|6="|!0U`twi/CO~Nx's??g~{~Z_o>-[-?]0?o\ou=@G{ !o*E$R"x,W{/}s/}\| ^Fnح9$&72|wW* 3#"o3;rLpW*LⶹA<͞m6ziTt~Ʉ=Z6vJɲnޚ+7^2ἴ8}>K\fmίю|K eYƫAĈp\B\nw~9N뻨AF<įX^U\􃈣B֒ *6+} O̿\,ϿtW>S~6\,tVykTV:O_2D?2{7_UZmܳysMK8>ed'_~?i,Yf1tz6V ?lG'o?>a,m_"g=ʴq pk`ZY;K&W9 d>%y? 歜;2rɎK71g%cGES=׊񧱾yy%x <PrG㻓y\ǎy|-COʧAw+.UJ L~ zUrV" Ip]~U|\zy9˚ŗ長p/ʟ⮭d̊usH ;|w;R7!ofo܇T >3uJB m͍ o^!o?uL "AEZch˅.HW*?MYb柾l?W8SGz]d>8Z0__^q@ ]˄=d?_Ov6yY ް\5{,D5?_Yly{^u=t8*i}* -{NcN~f~|)β' %ǜTO m`&?EWӀ(Be='jFpF݌5iB}Ӆ@.Y{"xb]6Z[~ﴂ zBn!/7{Wzөl%5ƒHkb*<ӬF!ַ')'rdU ƮZl/ng=՘4}jZ"ߨ W(?#4fE?3o?QЍYPUn{Iؿ`9fV@8R!׿wԿB4S?{=RݻT } ~zD~"NU[C.+ӤȿSQG!O_ h]BkE5 m`f~D_+ʟ\9T+ Z/> {v1S6QIv(ƿǿi~*>O ^~- C?XU~oVf?K-Zwz o.g^N/0Ǽϋg[yO̭dph72bMeSb<0ێڜ:Ƽ_^B^G):ږG%Bl|5:kʝf˽7\k.oӟ`h3zD9ޟ+64;N?.`n a۹<ݖqZ{ 9rnCΝ-y2DnJ7sjmJ562mq6WڍΔ.~-_6l@i̹4{ Hx"s8[oRk < w 7 w2wuDݛڦrph=oKf-E3eBӳVD?o qȒkD}b^jY/E|$rY7$sy-&}ZiD?ziIjƞE_G}9I>O!Fz*y| Jnh{;y㉸IN7ۦ7K}L[g}H G9;{H)~%|f;|CL}C;e3_ڽV[ᬫ=s'sbuoǛHC{3'Fn GA?<;Q{cm>/UPqOOX~lE>&Ho|W_߱?:tJL}"3.LL=\>l.ێ€&%Ű^klc:[߱\Eו{-={AB%g]MXbAw3z{]pf>ó<~;t5m]e/mZf`%LHmkQF*.<)Km7?=4WEi% EaS/Ҵw7@x%u]$f/[ z'`_h'ڂ>'nn t6N6Gb"v7cN]!AAm@B~~߻Z4g-ioo-&OYI<%oNBH.Mx ̶=]fͬKZ|f O]c֡cOs驤>r~\l{oPkwBB+, nsx ЈbIԭn`kuɴ< @>z{s@ C 5_]҃fO/c)|6&:~&E34m7l!zSH(7gqW$4 cSl o#mm T<+'=;""om ѓ]Atly,IpM[$̄SAdҏNYl&__BκzT" -cgm ߃w$Ye[fX/f#\$֐Z`{?j][y5/'ӛH3ȴ0d>_?<'D-vּLxIK KSJr"YOd |gػB+&<[Y?#y] 52gR3L<{[>h fkAX4wĀ ̵晑;."-<7g%ZgzbګJ)[ϐ;2w=%@o;sIT@j߃9q,+/9FfMYBvO[9s(pkGSCE?6b{?YQ.tx4EUPE]ho.|")]溰tElT=Q[=}brGbA'fj_/)gz˶":Y4`N\ @z8l}Ls-HӾY_F/n`{۰wt Y~~ 9C{^[mŠ${Y={gO=cr5+MF=猈jrGbpk9 7Nnл߳DžܫY/d}8g]L߱@o}SHFrhg IJ}fWCKH#}{Hbȯ2@O{x&kz$9= +8 }xVh7O z/--EKKKmbLb,) I9 A<ՐZEim{g=y4'sdY{>;!81onŹDp/\ yPoxޗR7~$]DYF姞'?}q,i֌FOsJ|w_/ZH^]<x<oW5ֽ7C3~߸x^t뿳<6{o?{7I7Q:{=7*  y6$g]뉽f}ck'\pYurzTthSCPas<7% a:SgVֳe5)][<\~ģ=Y{5m#M{h SS`ҴkB>):/wM:+M~hrVZTYs_<'`Ҵ㚚\SJS5Meu35,r8b/)ࠣY`gMg?9 ApʋCEgj# oY`ZbdreL3s=k\|O/}oOqLIWa i>P'A/}?k_קlJ;ֽfXn|wY]K|꽩gbֳΦ`uOW&e^?I .oP$ QdEž΍cewwuk؃cI";ūOC_7ӡ'\;]͵PJ@F\3")BuJ|300%{Fsoqt8Ir({N_϶{-9{ }"F[tԖݽQ+fZ΍m(4ţ'Z[_]"\]Iom{Hڊ,eE'J&ۣӛIo][vzs=2_DTjNz9(zQ$G9_;D_^<'w?Fv̿`OuxK?("/aY%Zkm+0;7F-(hkĪˣ1=~L+VDgZ?5Z'ΐ4V]9Y`V̪zz{Nmi5lr +SoZZ/fej[z-c/~~|QEy5%'K_OS+k* )у$~e 6b2a:jn^{䩀#jd^Fv-y8ણnmY@b }-~;Lc̅a?Wau"O^:w-.ݧ4͗J2~uu\/9JFg|&!9Qe=7eԉu<u_R[ψSg>2f'%Ƌr:2]:4k>V;"du;N&5i[դ(MJc+YCщʟ;;;؈ޓ?)TI|IbdQ==ʗgއ/lz:2E g៤X8wO!2E#6Msy܃$w"<4]/5Xp= ?A:!ֺpup:η3UGǞ\]֒_%b6`3 ǎձ5:{/sYA} h׈--&IGS~t~c8:[d5ɡRZ+3UP7 fD8aLi\WNwiw7/߉wolڌvJX`# (5KX]`] 2 VX*a= ,H}@¦;%aAF`)J,FavX` ,~fߺW7kMXq̃r73< vCG*<(RBQg~[3/1q-\j ~pŵuExཁ: O8bZ"&C@8"\;^Op6kbk#gӫZp?Np??]p֏x'g 'Rѓ7`94=)~&LQד7`!s;g ŽkμvX- 0+SV_!x|ww՚ X]֖0w*_ծ,ڈ5nk)X~5P0w%a. ||{\(~j.`u0N+ H_ꚁ4uֿH_V לMq_~4|BX:kv ܯ a`uὗ;58EuC\פQ79~ tAΥ*q}=g!_\o٠0a r/e v[hs֧Yyh{ 峰(VvX #~X! kL6V0a,Y .UsT6a{9GQp1^0+Bba/07TXsפovTG|~Ek%MouͺT97RWߗ2I_U.Qs]QWr_] ]؋Q5Ѕ܏_vAFf' _7@mq _7@zou]7ܟ?)H yK_#X/cTMC ry-,[ӂQ:|U,0=0_[`ׁYW0_[7W_9M:^Q<a]RY|*au _P;}u_;.@*K`Wi*c_Ӿ?0jڪOU-_0`x9lY/'o=g` 1c#o='` Ql:%o=Aw8{!7ĺ=Q#oTq#Լg7~Sgg.#鳣T̿Ckl{!ou=Plg˫cقjCy[J;w<1m#~9_i14|9ViEyJ{-ƨa Rk7^ ¿,"o}_4"oZM]HiERk7A^)/+5^)/Uk5~m`M9&_Sh8Ik &<;LLg+N?x$3LUIgj}Ŕ>'Ja#3g9}yN?y$k< 3;NT4arA 9t \|4_3P|A uQ|A9s Xc[9sk5A\k_sgqMxgWqMgGqM!?k ~ouxgV' AMY~/?+# OiN 5Z`ݞ{`-0.[\Z.8%WBu){_e-0*[?Gr6_ | *.o^-m򿖨wOOX' _KuN·򿖈cNF{|UoZc(aM}{Ǩ*QǺ_%GQUogGQUozhI9hIg1G(CQsGoPBQ88ZJ yȥG<(r鑣*A\zdCoP ޠEwdCSuzSuS<{SGp::S&PބkR593R}j-,Əua)5GU5R/4[=H_9,EߝZ=H?usXg$?Gwc_~O/IO?x*W$?0/IO?,&JR4%5kÒT5DTVT_瘟EllW)/R{UHO䟝W=q"zzgI{8ݙEEjCT@CV =;k8|5{݁>X;C@x.ށ_/P>4T܁_%{}eUܗo?%y~C}IvuO?i:hi o\\vYe]~<`©8ثl_ơ8}gZiwoZw?Ҡq>m t>Ol돟%8m>iT|8V9a[AkSr[*֞䄭yPmݦby>@>:_T B:VcQ71ǞonkǞ#0[+9alVsT l/{AX[Ψz9!RsT B/ X,F`|}˳jQ75fo03oFk1#nFK1ߜkR7*J?gkgfE檸&?C|es1Q N oo 4C?^p!Mۀ_Cpi6[S}2#:. Emo(hNb m`"6ZWK0C6Zb 6Z`(FK+PF#5ނ C> YF F7 { ?a\6Xa8`'0^$k?7XLt1 :( C`|  ` 0+0V"pV*8lziVn:PG.[o#z{PjuVp-/PuVuc_\gqqf7AIpuA N?k{]y8^cE*8?ñf 8c,צ(8;t>qO~?y4V!8V-8CCC)? ΕZE QZ Qȯ+gȯ+gZqY? 4i֟-8ۊTIh~_j4/5Z?BF|oNGcZ FhxSU!տQ?ZonUV1Tf:S;hU-տc0NV[G0`R` c`T,Q;ܪ{Fr 1վ-?տXG}[>##˻`>#pܪ FܚQpUex/տ8[71 GXh_Q; cGXx2|Ǐ߱+?ǢXjտ }KϨqw,rRŏq8ZHտ})?󾴷9C3zXZYs8R`=Xmt1^b F0.)K0:>%E=pPiJ9MSl:yOi~F`dxx~JU}fod&M+Y٤_ܐ8%_㿴Q&S\KYx?G?h@?0פ1[hܧlq4sq4aș60*~A;߂CIi7[i0ayBbb:kgayqEa+?Qaͽ7a𑹧5& 2wxV& vg C þa3`Ϲϸ0܊f aK-ko ٟ0s(wu4gY0ҜEf1s;w b0.sTo`qgTV1'0˜gU߉' 5* $ 5s*$ |fu;5la-{4}03g[WD˄!_϶Yø̶﯂yxٖM)!$u! -+&X[='X-°LyJh_qC_-+!U°LzIX(:)򿒂 9dNOfY`Yooe#e_Y&SgYi&,^o2ͪ޻&e_y&i߫MFikMUo2%gZWQ0ɨCfZ`3-{4~%yi_%i_e+3-{S0%_eU#KzU#K?̰` >#K̰i/{o g3,3#|6?`SPΰοj F7t`S[_F7+t#}- 0MM`S-#To*rt F7YW_0YӬMųi F74# , 6_!_O`p1FMC\O`0,k"45ojũMO`0.S-k.4ԊS- 1çZB0>򿖂Ma#Zx#om#|6򿶂MG]7vMi#5P; (S,  : F7XI0)uo:.@NN`3̈́3c fB{Lfb\jz'򿙨iJ'o&d~"2f'cL8)aso\G N"f7SX)Za=pt{c' =|Ą =|{GӮp{G_]#UB5ҿ}_kT-@}`)AS/'F#]_A"8G8A 8G?2' 0L _:e/Dq' ?!|/EAǂsDA'X QZ1Y?ΩGi _OQ?Ei'gFjgZg~Gk/GƷgZUIH Np? yl-O? ux'Iz'Fq'a~/qckQ3/ Na}/ Na|i'Ы3NVpҿ?N4.EqZ/Eq:o NN'I"Լcu]p֏zr'Qۏo#_cuCpҿX41j?i1X蟔*8_ VNI+'&8_1'K_#?f W'47oHG'N E@B I_'/AV%xF5Fǿ싾a_ct֏ds}ct?mX?g'ɨ_/ҟ ׿ԖH2jzK~'~O@q2ZY^0%,}|4/~ެ 1efEhZz|]0%cG7_2|lެ,CF7c%|K0%#ߛU_2u˚פ?: / N(?ǿ"8`F9tyx+N#8)+#0Wp:L=П4bX#?ayy$'/tIRП!8_5B뗺+ҿyk/uW)Z_#~Αk#~Α#~α~ #~Z9֏/y_c~?6~:ۚYҿ u݇: Na_eX/CPI2Qpҿ yoIpҿ k/,_}p_rܗ;\<%GKc}%}ӆkgp_r◬g,Z/IrԍZ/Ir Z/Hrp9'\&8_<\[pҿpIrx0__y я7L#?k_ciu'X?ôzTaZ I*oNSQ NSCT䷡Zi&Z?Cꂳ~P?Xp֏7c|h'+0CƂ?C&!ZS MI s/u_I `_Y?Z՟~76HJwWpҿ籃??%wOpҿ5*ݟ ʢI*'bg/SZc N!O' CN!Ʌ'0‚ukO N!?C|i 4>f~Z'\_Tpҿm?=⻟=⻯=C_=_BpҿW4Z~_Z)Y?껾ZK~O>ZIO⿏i!0}W'0}t+{oҿG׿2GH1ҿao]au+{zW0ä#e~zk2IFe0?\pҿ5L.8߈ ?oD?t?4~$=uYpҿuO]loџI7c~{@$ RdП {oF~7'1?=?A __ 傳~П*8?w-ZJIZ*8@|;' N ~k'[CIoA|u N"?t N">i'[Qw7FߊֿIpҿM [i+nZNIVoֿ[pҿ kW_ ҿ /o:߆KNKN_jRm߻jR.ZԿ;]~IvOtM'ۡ/~ҿEw?ߎKo.zW@EISg u?z(8߁zi#;u&8߁ZHzGwbYϿHNo'=?;iYt4ou Nw"u?cIDp֏AGQ?.8*84]ZII.䟎Z)I.wG3I.ߎZ炓]ZiI.濃濃i|1~AJp֏-8jgP#8jMc7ߍ/ NwcC˂ݘP[In7濽'1R7uk(8 nqMcG^Wg?5Y?'_Ap_Qpvz?I;uIGvZcIGvzN;='aNvIO;=;'{>='{mZ Ik Ӫ N-Ok/8߃ҿ-O 8߃o >B~G[NplwMpҿ믍]pҿFaI^W//h'{1?m0I^o{ Nl#>[k}gZ?Y?/cLc߇'8߇mO?'j qق}V~?he}1`}WZj0~Ǵ]Ron~U[ROnV5K=*&8zo Nُj~{[q?Ʊ|Ap܏}|Kil2=On"8OG'7cB~Spҟ O 1!Z6~_46~_Rp֏}^Jpҟ [ N3nk'X7͵~M?Z IMs?͵~36 ͵! os>\&89s3_F֏:/yi#iK@L>/ G3|3?BpL+8?4~'o ?Bp˄Ig8'6Y?'m4QLoH^O>3I]O?3/(8}CO N<'w?G7^Xp>jVNd=AJ:A} |i3 F==GӪ M{NI|?irA0ukI`79&RYGޣI`#Mc-"U l`LԌMZ 6Z0L&dfLZL?e F_&⺱ Fc4bf.l;g@Ge7\ZD̼'98F'\q; %9 Q$H,G=hT#(m GW'r8 9BKPM9ñM_@sG`G%F\W|d_uspD:SE"^w5oFEF;jGw1[Y^~#cjYލ~X8<+nkMG[|+F!(=˰߷u9 sciLy-£rOY۬qWbgn|%+\&:·< ;eܟ8Xu;ԾƢܚk<{=_jc:3=Ʋ)3Կ-\QA͔=/x\g^/9u/*t'W%~t^Hxbgg'͑QR#垅+Q51UO9k,Fj\N^g[WC"'wֿlW`dY׶:?TdGDO>GlC?wtl?-?[?h%ѬAGMW:"75pX92qLK{dt8B߾vlv%Zd.wC?46;'Izb5n;ZtWˎ+~o;J&,q\@Ux_PO|${QSZOQH2eN㫏/g<.zH\*yſK2oϖGdHCƧQ+8J| oT:#י8HΣ\QӨr;jyɣ)?~VΝ]QtØ1_z5P\{qFv>n}&o [jwSwYsi3,g~zA٤ms%Կoia]?X{\q-|޳bɵq^/$j]Ӗ?竬{z,Tު #Mд4_c&:"Mm뱁e,t?I=XvNrP]e:w.wCK- /ټoܷ/ܷ1;yy?ۻo=rk};rߑ>kqF/?af8WUJ13':VY\ݟ+6tnq=8;i?/R9{޵~>xwG

gaWY!^7C_e_R#qoV^\,붧YF8Fz繱M /{ն\H>ى+q݋=(+_Oo^vvS4{"s'Sܟ*IRgbKܟp~0W>&6]lGgKgܟ-*?ՙ?2QӮ>Ϯx]M}g'^g?zgMW>*>JR>[5VARg p>4 ^;+'?w?9gGlWbwz,vyω;~+^s9':bծR[+3[ZzԊX߃tt׍s+2 N ~+u-+:ݿʸ}oYk&tn^\+'`[:8yMӹFNsN '9?ùZΕ|\3;'99];翄y8>eWL99O;"~rwĹY8WΕp. w9|FδQ99O .89{΍<+^9\99B $y\T8?s68W̝sKts+KOp+y8v>%kM犴'O(ȝsĹ}΋99O: ns9ez8#s=/+g?;\ù:M7˧.m;gGgrwsN:o:9.]8KW

?ŷss9亓68{٧Mgҩv |r?ȝdes)/elp;nz89q\?'8sM8ݰy19hNΣ7 g]ΝyĹF8rruO68WΝW8Wp.z>焍sֺG&JlyrΗr\>L̻99$ G<; /+I<^sQnyR1#'Gqq1-wοtp~}L 99qO۹sy-qnΕsE/H]gS;p.2>縑s; gra΁\96tNy*u˟ssi:qEs᜜*is9:('v6S:x\WƳ㯇\ùp}1LgBjNC$OsNKN΃Ϻmp.;= u9 rݡO\[ y8%g9:tNy` aϦPn?vyI9xN} gϻO68֜K 99y m亓>/{??~3Φpq^wGeON38j:#7{u6?|)8L99]aS=;Ϛ){\E8|a#q9WΕp. .dc?g㾝gpa:#Fܣpqg㞝gp?b:d}:G}?H?kE99w vuG}?6~ ú]pq<+O;ύ$vy9vN]g&>6֜s=/+ w|lܱ ΃Srr.k*GgvyyṜ; gO*lYs {\HW3g_vp9|HNC%o?9>xvy` ߛs26|:8֜ 99,lcljampذQflN38tMɹ}pQl0q l:xnwZ8niSgv5g|9|lbǙ^p?9|ll6?)A4>L?ke6WpakpO=?s/ϭ[t~r{|?6~ }v΁^[%I-Z98֜sׅsM}???sKsB6w>6n$FͿG'gput9N\]8{).>e磞g;3tx?s熝3>xo?sLKs*u6GstlYs."?*ltOqN38wl:{+m]9l\ ΡLg7/ρ 6:ÉgpnYgI_yٸhYs+?7('>h㻥k}??]l{=ƅ>w ynqtRry85gFgUEemEjw#%^Gϟ9ll#6^Gt^N6kxΦ^O>PSsVe>SsfLg/اӦv8x6GR>wg/ϯ9d 89W[Hlx61Gs ?gNYKs$lrdCs-uWp~n%-rեqf>GޟggH67y1?Cqtx~pOy?CQ]8{~pq;Gs?CsHlpq4Gs?Csc]/e6 g=>R,E(E}][ܴfqrEXZ,-ҽZ,ʪEQʖX(bj?s]u:Gv޹^>}~=*s0#As(y'EG1XX ܛP;e(|,K9?@HWԣ Z,p6?Ϧ%+bA3>5?gSJ w;a96pOrB^!?G֢s:oB;qp ~WHϑ=A3; )9~K<E_K{_99~Sl-4ϳ(M ;uOp^.?JF}sм"p͏s{+sכ? [g?ksRqgy?4gS| 9(?7X'6Ac\,?A3ns5?c'E[A|݉?,o͓(E ?X'7?,+?w@ Th˽5SsEO.!p4 " 9Ϟ?(3h~Hg%f|ekN?c~&xĽg<_Da V,͙<[n xg~3h@υsH.>?קy?cE\vRϠ!~^ ,p6 SssPHX'|?kYse0,0 3(yh@g1{m  ّ>`gX75Sskn; # ?( e/n5( hfϿHwAs:?ϔQt>M 05SsTaY]Ϡy,?KMa?Zv8c(y|&E1_cZ?k2dϿx`Nn?<]nG|֋5As?Iύ? mcM5SWn(@j+> vX?)yO-R[Ϡ>&?43qg>ͣ(i L63pg~ƚ)y|jRXͩàY63hs%H=ǀfqp?k$%H=fnPS_[ GR_1?4 %5S  y,0 S(9GA? y*C5  hf{ \`3h⟟LG y!p;5Sz?_Mh'0߸ GP&dϻ|C˽ Sd  yw?@L?c-?-F \v\s?4IϏIϿG_ ;Y`??AϏIϿ p@(Q gߦ7qa y9'IGA3=Mpo, p*Rdϵq0دoG$_+g@( H=>R,JKϿāf5,4?Be;qg|7p$Δ!w|=Ps|0438f6 ?Wý No$*z?Y vxguy??$? 0ψK#0; 䂻?#ΐ"W\? ϷRsQ@n~P aLh1~@!8S8 yd@ЬrD'?6Y3W9.?@ y+,U8Gqx-?^ yK.),59GKu#޼چ~]|?Iu.7G@xc|#?/?'i6r7R}[?oZmC`j< 4 X?R( yWR2jY+?Rs\{sUY3RsMRgu}9 |M"hfcY`O.Bn14 w_៯νHcm_?AJV2%Y w;?׆f\zl܍c%5Ñ.?+E |,p/G?/@ ]) ]7hfϋfqJKϫ󑺎?/k៻P[^05yq(-?s4/$w2>~5 4 p!BV~{ R2W擁kϝ)Z m5 yA,s ?L y˛Nc #?X\oC 99#?u2痷z|>?GKo@3~9ڳ}+DϪf.RW3Ҽ hiϝ(YoE*<2`-9 yyhf О?kkiQKHC; 84>kiQs H-M\_o@J^??wk$A3~7!(Դ)\^ yn6h-9s?"-\TM|?C$>?A{⟯e#M<'ukkigSU*.g/y>Gj?w$a?Ϯ&4[ϡW^ <;4 9s(?Kː.?l9Ϣ>kH}??_ S=?_)? =A@;S32A@{>Qso yQ-Ru0q-?/ 9l_9#%L.c0G BqLϗKϯCRl ̑`=%WC@3~0hs=vRe+H]&8'vRs/ ya RKL/9?8{I #5_ϭS^s~,t?R^.f3a k9[( .bWf;nK$痺f~{HӑZhq&.?B [ sg(< ]ϧ)< ~r?%p]9 R˯⟻Js#u>橛A@|?7PsW yn?ܗ9ܛ!pN?wrdT#ΜPEH}ڮ hIo9$9ᠹ]'aL Eϝ%H-.kRIO$?w O"uq:8  @ H,08OPH}q]Y74QsuHˮJ^8?/?? {14f9s=?wge!h]d9?p?pz *:g]sv)hV-8.?vv͏́s-8|p0 Ѳ?AJϔ"u"Gq^(\ yQkÛ$N៏RsG y4`h?=>Jas~>Rϳktn;?#?؁5?4 1q( yFwܕG(l yzRgk~?sk? jrA΃ٮ9 Eg-C%goh;ϿRY"ui | ބhϿPY"3A<`V,pv >DEgfhMhxo8An'?Ss?Ůy|g9 ?DsVbל›g}#@s'@sAh`h~* G14'f?D+ܮ"8៉) Hk4~G+⟝"Os"hghP˗y??;Dg9f5gﵵl?*?OEӻbYଭ?PAi} aY% Yi៉dz:u]oBgJL4OBjeY`s,?4vi9u-s=4Dsv RMh/m{ Y9#?͏!%vρj៿Ϣ4DHr̮>Y`y+mi٧94_Ќ? ܩ?6gQ&' 5g](9-r:VDg9OkN4pJ)"OsO܃9?+D#H}|]ɰ )-9-?Cv,'yW>YiN摇Asy[>ϵ៉Hr7qZVNDsf R[hלu JL4O8G5]8}c@Ќg?m_"35߅gc"3<YG!p޽?X@i}vqg+VEg9#fhFބV8W)?B+,5Wr/s)"3@R'2;f9%n"O3 ~ބ#c"3< yXA{rVDs~N`ɛ!> s/VPEg~?'8&?n"3<61SmϟL4ٌ pg,?4f<S>[ Y9"?ͣSρk}"3ќVsR! ?Mi៉O"쩃qP`?jʯ"OshfϞH,6pO YE&+D8|[ĺ5៷rH&G!5?w92J P,?1gL4f!u,F8j?+?DHoVqMf٧943[f^t6g'hg8RG3[pjVDR19w7៫2)"3ќr3Y`m?+Egf7hfωAsmY?6gGh;13@s9[Vp ?w@(4 joq %f٧;hf ,z?WO&Gd 5?'forJVD5H?- r,?4;z7@X?4geL4ߙM.X[ 0CVXԑ \,^קS%ams9:VvK\?y:: 99w34y9|'?߾w1+@{Y/4KϷGf|Ch.k YV4`7$f;8ZVvICW u8ț}@-K9JԀ;{/h8OY3gVNJ 4 [3g S;u٠Y E)~⟿oۋa *,WSm}@36 4 WQN yH6R,pֶ?3B 9 4 w/P f]GF"6?%?ߚcѱY S ~⟿o)CPf;r<I YsW9 .? Y rgWPsXTvef-B1uY&?!?43,pp^NϟK HIw=^)y?/,^M aoS`O%?o㒑z+? 䍟ߠ$Jz  s)3 H<\NϟJ7ƀf|U,pm.- /Rst,".sl Rof}V5(y43+@1?/O$HM`W",UៗR& UHgWf9y ?ooBj4 ϥ\-?_@3ϛ*8s)?WIb#s`!0G_%#F|foB@(ϋ)c ~?_Mh'^rEQ6eؓy?/ HeϽ*@^s7HA3y9*?WJ1H{yB)8]6 ?$?'z=4 opƁf|I78,^H%gn# 4 Gz?/u10G=?L$gW$hfCA/:?DHQYH?w|?/?_S R,>y>?/?_ sףY`4?SZ p0n,MFWh%4 0'yy?>T?_4 0yE~O Eݽ u^"?+?_T?_sQH8\^-?݁T4 z?Qj ow;;@9^%?@jHcT<ߑ\k @\?#?_g?rr|EhfcY`)?K=f! Ff<$H?Iy?/U!2|Vh`/8t^&?w  }=h8yT8sX,Σ%s2d @9⟗H]z)!Oa;K%.?; M?c|QR/a`g{g4?//Ej, g<K 9(4 L?\^$?wDjwL!p!3L%s:vcώ}g?H!?ϠI~U 3,pvƚ) ve-^hx P+sHk@@Ϡ9Jϝb@3n5㟱f^ ?{znJ9A|^ R/dgVf" %f| 4 J?|n:R;34 =cX3?ϗ;Bjn,As6?ϗÚznr?(XC?7,h3L$sz>'4 ܕN?G)E H ]k 'Q@3;4h?,+?wAj8> X3?Iϡz>Yo?G(H  I,b?4?Ls$Rz.>o㟱f~An_Ԏ B,^3hH/HN"5?w?L-? x$h[z?kB 90,,pOs?4O%:SϠ!~^ P,3hOIAYHܻX3?ϒH eJA}ػϠ9gIP?)@v GY 4 ƚ)Y 9'pϠ~Vn9v @@?4g$7hfϿaY%5SL 9! Hh`?tխ Ow3kmޱEf‘ko~ zBs/ ΁ﻑ~6ODڷ4 tg̫*߻N;f[i' &>o*izxou.c9x[v8>]z:jrbcXjQi Oҝ6_ڡ]pzoF;p#.c}7ߙwX;=;0\glK(M> EsBcwrR8w8w#~HJ!Rq_Cc:vEa3:N11ѨcҠDl3OK~RGoi%ge#eQe϶/r4W/Glބ_V ڑ6^nYu6Cc-WaCf{e:uꔨש^6Ngԩ7h8 MFK.оOmkJ}kn=K}7 7Ei6.^ijw917۔R P&~]^Z xNMrBq8᎟>v%^z9">Z@x yKZ|OM9gܓ;fTyO__+\^-'fO[fbakT9w$w/5bp/$vDh~^ޡsCo~}m0ⓘ@+7VٸaH ?~GzZmpjISݤrN5FB&m䧘0BRc!ƑҤǨ u̪FOq\ku K[ lHNu%޷Q6f'cvo}[]1Q0f'C1Mt0t5ZlFb;oy6OcdO1껛wQǖkq:q1nSqcܾצĸ)]Ǹfc܈POw5ǸOiodԧavcrGO1f'#eBc+ao?.@z\=S.éd{]vgduXrt.W2rf@z]`^.w4rb=Օuyp~? .2IquƸ{6:R2wv8[ĹMz|CRq.Yns=#wlܢ#gضye>GjLk=.Cs;b8g3<8|Sj'w/_iةa= w&|Wf܍lr8wi!5~΅RD/ K6B"{Ud ;){_8jn#6V )9J.5jwXw#^ |=.z%W۩g'F]BH]R]u5Rj:u !uItd]\F]l߸M^1SR^_VsQSC1Q߄G1k2sc{Q_9z.RYkjtQϓ}8c="aEI}qV6KRO1F\ybXmk9;m6 )_b.dDV٪ŜNɵBCt/Bj->1Diϙn+aE|E.A?[w*.P^&ϙp2.~ u)BQ˝mJ\7ss9r>qT7=h+|Owh{L {F_g5tɅX+W8͚->ruzGU=Pa8 9 R=O>ʴpޚGMDWsAlS݆6Daž烦Hk&|e:tm}^u ߟs!9tevf4◥d\h;\Ti3~5Hҷ{6tEhm-mG=Ji35vruo;sӡU/}egoߴ'gN]n ]?J Q§p]&@+u83U)b{djTn#meVoYi~y搡Y}L-6ǦY=6}fn{5|x"q@a?Ms#1C|@Hٿ}aKa^Y'un>ۍzU30+[JWW8(0coyK޾:=~I|i>GĪk'O8#FiMSQ/I_c~}tހ\6` si' \WۘxvצTH$}GejO*kw@0AT?D38d Dvel |R`|r.No9n< v$h3"6H. m0ہSn^y[r%fWO2yx]?\_:),asFQjiø%arU 5OP̚lhk롭!hkI nHKˆ 易<)m]Υ~BACX( )sF?q+vV5>]~SKRߟq!Y6Do KFx\jq9=m0js2߼yZ[C|Vݓ1q;ľq_gT]Oْ~m9eq!j\#1m:sLt=9V1mc]_cOlizLx6VҞBi'w=#D^7`Ǹ65-u a? ԣTGPmޛMx=b*#yI2x6R>`,_5Yp}M֌OXH'nGC(;+G܆/rg3z\[sƱM~qFZo?^\A:5\?'KK۝dxNme <)kgqĨqf%Fʚ]rIt̥q.WC8s&9}t((#"sz 5VKvlwc̾m*_ oލ1&?1?m6SZ7Y_5rWs#ݝv؞3zT)2K;Ou>zgo;U ̾i'RVps7Kʥ|s(w\bfj!|߬J}?]~MFxoi;Sۜ?ˡ ϴ;;;ӿmv`ύVqS?M9ʥ3h7RiKvfQ|]Lwy~ ϙo9_ĕBO$ge?sZvs⟾mV.X=S.TYoB?`?4RK+?m͹rO7:n8l.v^mV."eNn |O?wyߣBsFc{;*d?6G ԶF|_Ve;2`Co5)1omwE!kӕM_lέu"mmupzovBN<"PD>M9F1EwG~{=+Z2IH`?$5m8e;rߛb^CYf`.OP럭y=uF`D|xS 4/xxw¥8-&\Z6. xZ[kjsyR6R$ չu#eG-v8aIΠ]a:?1]cnd gy)G:/"xF$ m QcM`]3~p1>#$|y^nYo} .Z1>hoij||)0U>_ :J,#wHl]vh`ζ~Uc fi ""u-AXK\~f ݊m9݋R~TumZu濙֊7oiRNaOO&KqjgQo'A=^dϼ>z7oC^Κo*^B֛E7Y?83~pi{~0m&f458`"gp ӿτzRӡUl`Y^3M5֦Z;=|ݩw 5Ν.sEw[<-ݩȵRq'R(}{՘gi.iƶ4wYmI32^K,a;Ir~k ATזPYVf)je&Rrp%vF3+t9R3Y"9G7BW_* ݛ2So:n: wʲ=B/\j8n@5+/36xs"_Y(X+AпÂsr;ງ􂲠WDA,z71T\6)'U+ > grxԶ;mu`spD-Y~\-ǹڞ=y?. lՁӍʻ}J-Kꌔ)IfJWS^RJ|9 EU[$b|^q{ :sݷγ GvLmO8FMא풴r0f>ې1#8Su[1-?ZHA^}*>{Z{R65.G/\@ `_:p/}u .F0DF\:cD5?|`zz0r!Q,{"<' p}piHSI| N%_u^>̷XlƼcf:9V|g+hՏ/Q뇄u7ǵַͯ_@ox}~0"A[\~cԵ^_s5d^YfCW'xՂzq wɘO[9YIz_&)za2}b͚q_d1[YMF01']4Z69 %S@{]:r𘗌ZcZi=S6cぶ-%`.a֐Ste c.x~$ eY;<}%{v/9&->k{/m3;s85D^Aķ;c~^0Wv$kʵ< &`|(.ydw¼8jFL8o3m(ꤾ } #mD#{uqǗu`cP1wPŶ`3ʟioc~^Kb̸:ʴ~:A׃TN8-R _of~1.{~ƿ5dsi(g\w rm_Ŗ$ »AX 6 8Ӊ@9"ˏ~gԳ#znwqhV="e1mu[ids"gk}@? 3ֵaܭ;jj3o.]O%iK[7g5mnG>?\5?x0.9`#~9DJ.#|8x0.Oe9^[2ǃ?ǃ?Ǚz?nE%f|g?m\\?]PnoNn0}k'?vi]~v_lϡϗ <xE7ijyx-Z?:;>,I .ZYW-g,KD}0t"Ln\2؍m4 dQO'ܾ֡97,B RZ˭;y6>G mHj;O=k;?g]PXM rkk"h7\wBsw_"Roz }$ ;OFʳ$݆ oo-}r>s%}kj1~٠*wyݞ?-B369̴D@ ;ˇ@?HA蓗"~LXv'.d}ݟM3? ʑ2s/4s'ud?r)^0ʝ)y'z?tԻCܿOsvPrB?/sa: U['h$۱\//4b{HHg㧯0uڅyK{!WTrjseϛge[EeH7flo<8bk2o!PGj;2_RFf{(v{Ś>)g]l/6Y6ns׳=me{o,ͷ}l{_۰w^_o]\mޯTSF՘})1γp5d`w[5oug iu4j;>=ưөfwi }9ſ~K r\sO jSϘ1P}L8]By )5+N>\O˭Z#xy6럧"KFC+9ˑ2u;\bmTS.ov(sa{h5(HzGټ%7 OŚKg7KJ濾, W/g!jo|)/!PBn,cgTk:kUcF HT(˘ kl|DK,>[/Oa_vs݆'27m)ucu_M6j7_9+4_y(3j7Y_:t_M{oE.9fϋ>! )Eky#%bmz\HEFӘ+H^dEYnE.?/rC9/rQW{ʴ!#_lmYm`ev"~59ES.?EVv:NjK$lvҖY;DEF:w7ٗĻgjTUKW!er r->eϋQk}/my~9Ւ6ȋU;&y3w/FRyv?̷u-/k3`m!m>=Ȯ?SyuOαE&q5/ឦ6/)*lg%?sDcʹ/YmcϤZOsBsI.27'uvQzO]`عT>GTQ܇q\l5̑Ӧkm1Bn+¿˛mp;~ôM#6.;Ҷ/`ۺҸdbIf[7!r3WsYliuS_?h*d/qjgY¿8ʌ40Lv|x=ſ~n3NN}w5iu?{a@C C Ly=WVPk$}]/\zDo)3`>9j5:XGvZ]2@N24z|B=xfixNlNi mX=o&iD LmC`^s ;Zl䵷CFۘ{b|Sxx~=otoǯ>)2jvkyC}-Weo-v2*m~/N}ioa꫷A%~vZRdgu`%TNpyj?2ϦOি!eLI{pgmޣ4 |5<߽ cxnP5wovv ~7=ė$ľJ2|cx//G/pe? V91]j=a-oaڝ+a+= ڻL n&cpp^xϤwlr.gVt>T'{Sm6o{fH~,hWUB+l6ƹx3G d0t=)cIxvq%ESb:A{gWu'r|C={Sr췽)>#ct?۔g;^~MA]8}iuW/>?(iFc׍)6651-WmFیfsm(8mx4#ȼs%1Y؁-&Λgʵ#8ݶޅ 0'Vy?ej؀q>~b'n/%cñY^E ԩNn:6)ϦpMz%=kp\x.U˧{2vUuQ2w~lESIwf}QHo jm~*$w}k˜"sƾf3]MGG@S&oRz֒DжK2DZ d}Gb80(>zM(;BzjqLUc˩AOOo|.77YZ'q⻩t[?NQ\I_K>#m-_.ƏɇHۡ8{ߺ"%՚T\_sj/Y+Kn:R{q%~:˝KHK.]^W%ϡ=ϵSǡaȕ_no_=#?b nYHgn5f>ިS#ʥqXr_r^?>cCǮ(kW#e1?)'ZF˭f֏?j?J:SPvM0C))>Z[m~W:_Y~HRW}.#d?$%n {)eT)?"^7ؚ7[r 饣k !;zzC'7gѧ}e>>8ha=\/n#]>a.+Ik#>\JOX^{{w޿^b*~Ov~mqy}G3وZ25@pmLOӏ[,{Ēェ[c;ϰoZƾRj7_YenkksFd?|__nZƴRj?y֯s_ O~]~ޯpww89kTowlI~}Kޯh;8bjb~}L{Wa׋~zX_^is,~M{PC,|YQ}|sAtgqiWR:EQqޜbb~ؓZZåd t{! 2-G0r=9;0kDn?lދYEkDWc1kFV|s(濓_5roFˇY'w< ZmFa5~e5 wmk6F~ul5ښi=ӈ%t=n|㰏?pPGBh u둵T!sy׾,UzI15Z;Py"韣m(Ga!C} 4}2w>~w>l5x)CǙ}0wx>^s>>E}nd}%w53PE\C)&mxhևkvDcTO/S/w{ oMWQ7|_Ydg8^&̲NJBږҽT;"ږh#gDdokiFS߇qZ4zLGcCN6z)oMmn_DQw`ߩjޚo'߮F EkXS_b{1W58\u.*yT |+D/yJ翵K<*m5}zk2{aOv E}IGm N3ZWb} (.^3c2r"6ߠ3am>δ"mb.5=\msS?R'{1LģjA N?'㵎cf_66l4}56}y/o.6HI}@I6zzRݾ^^kڻ{GL̂u[_G{~H6~\Gt u$m/2?nw`JOHW)*gy'/ޫwvkDb#9=\xf؎vyޑL3ӄsB? A+|$,7,%ew~zFYg}])R=9Sg>H G?3$3,,]ܟ`(gnFM:N`WoWgzpf]˳̞4;|KBZn4̯JˮLWoGq;c,ɕT%9;D:0 +$ݯ<%X7(!5: &0==Cm왞Poz6xskNɆ\̨ONX$fpO,>Q,?d&d\S}rB@k<=Ct^[呻b/'z-/]o9u!gy`c\&ç쀼rB2<;;Cex=) [O\ T)u^qV}<);Sv0Kֹvp]t.s"C'ץLAkX~@-x ǧ"؞0Mn~ݱ-n: _GPj,ȴ۱b7VOB~?SK1wf V0sB9(i1v|o6~7oe<&*y-ż}ay[sbϒyuȡ5y$]0q\?nz"% l_rdaREed? T:=X9߂M#Qd.Z8ŵ=f>,ad1L/S66%#>[ ?Wmـ-3ؿ陯C;m9D/6l-\n!ݿhv=AA%jMh"sxl%%sݓ+˼b%O*q$З;=g>+ "}H0"M%kgFWr, mE9?CFQ1?jatD3˩{I*H<#a@kG0ߟ l;pϟGw&OpCgYc!㳬 XYcЪVg!BחONffL3>=8mƻ mtW^I{-2;g~H߫v؂ٯޝt~ݽP;ğA|OcRJp;Yq)zw"vxgޣV{ߣzz N͟AhS{Ү^s51֐:GOFgR}_eyl'|3C\\ƿQG#1{\t:p}ĸz{}.ͤOyvs־|>^7-9it'0O0Ow鹜'cjNSZ19ex4`{?W>0F-+oM鲾GJGqez دRQ^{tW=B)ܶb9+s9n*r9ꎟ۬B|(~UQɘӼO5A~"m>,e~[s 5Yy# *nxI 8+ 3|ggG66a)?i$?:MPC"C?dY?r1G<.sޟ|tc$% әP+]%07C+os$.N^B'gzs :AE<@Ţ OS1yEt_ZJ~vVl0lBmhN!A[=9H] 8bX?Ixf>4[%*?kIQ$URB+@RIy)uh |qb=$Ǿ 6^H] /*|ktry +:B{q$ğB⇮;{dWlZGgAzry X#qC5ֳR.2;ȿ1"M`q;ߏПg#K*M%wyZ~MVLX>=gاMܷMV3mZn!vA'_Y K Cc͑8[xgX8 ,;*Os7Pjυ!9wu$4Wc2K-~]GbzId&c|W ~8O{sӨݧMyK#rOkZWO /gJMȱ*奉$!K#l|Cx*,Jmg KAlA_5XVqSf <x A.p!?ȥ(6R]jg/{B8*J@.{8 X6b/D)CHeFnO >8_]{2nnG?Nknvy([E=QYyM4c^X |]#rq̿ˑNOۥᲽZ$rL6{W,[TOtt7 9@˄WJgxu0q6 ,!?H_%d4UZ9^}d"GP}G2tLcz-kv?~H GytZ]NiM\iumr\ /X <>Ô| W]*ix<-R|,N .|au'T`}k>ax9~/o C خ9*rL9P|C97b쭡[du./fg:ۮo 3I)ۮT_@.)}&.$c8%Ky_gn}5\RW*+c44d ^=T+egyS5 GdX?t m97m67ѰΈ}OϐkG!_ _1UL2!>}YU<73{#b zoJD" &MO5fkG}ZosnmsN LO~ V@`O#Drrg*WG*)"ڕWzP{)R-oXm.[ Кmwо/ Ow^\LKE(^+ߋB:5",Ru &gu=ہ/vuԱ+(b6WNlBv,J= aytIHd5*Kt<Hsg=^'xqb4>c}>#YfxqV9.Be5>Cd}ɜm?S'8Ok?"Ծ=> 1吏bO+'gTV1UpԮۤ[H̒۞;#TҌ4m=Kc=~K 8X=& ߒsWͯ^qn1)e_UU4{"n~j̧w5_ ͯVM*8WF~\9r9%2zarwU`ӄϣ*Y5_0ȯbq~%*!i+[{{ maA~~XI|LϺ?SYIg<?X[ޒIKoUxfYϥYq Y/JÐ/ȳT!_[9ϕy`Yr Zl?1c2ϊWailoW Wkd\31Njh/tVBmrRD\ovBNY(yodr{cԠ|\,~IK?ib;.. !0tꬪ+Ks$፝~gw<;?Wzα}(ڳoqD5GB-P^b^C)oX ~y6ZW5|uYz_=op Rj7r75Ylkw1YBF(p?l1<ѳCCXo>}|Gki~M\YypXGhkp/ dOd/k^^g)iH%g\^g}g fxwR8c}M5llkVz]$Qz?l} 39/^rKI<t5Һy2Ϟ,\HxEQ03Q\yIQ6T,HTs^KA6lzhQ6vVKy0Y6M$˦\6O " WpK1]2TgW2^xk~zN> 깻ZWt.L}$?/ROڊyK/[/n3>?Ѹޛ,tډ`d??dXh+ .e0|KM,5i@ )~NM><7_~5~eOXIg)? ZRWK>~R_K 򟾟X}YXCAW>6߯[x~0KYP # Y/%wMʼn%Yc/wk#N8P_9IfV%$NЛ|O`{Z RtbA:~5_Ng$_|dž?$J/#TfJ_]OR.\ \MBgz$)i}YUD'S>d?Q/|_k`}bw_!mP}Oa/V鍿H/tئp.:lM2ﲮ(a Eie>y1Ei^YqDvysŴ^X#)ձHd۩DORFT/p^Ozzܫ}%{{%0m҆1_ N9 iGrGF.`cat:ʜ H_]KIry~/,b~;&C-ͽYBV}opz-訔|%Dk62տF%H' XYgCj'0 mHG B7뻉 VLM΀_2?1`2?QKi?P]G#AlQ-%1?8-1w^vdԽo {vȚBYs4 i_/!UT8NJE+jw>Pz?=ocq_3UKU;'K;R|j /6!2|hD2Dcqf$??Z~6O;%d&iynYg觘|9[.:{@s9t$ȡvʳ: :y^(o(*ނCIV#zGcIiKfjyhKv}Ӝ@#VP'xR /gwL8Au} .TXz}I>7H=|':K/G{t8P|o=Pg0/dP* BHk=YT km G}-itnEQDCq;o'GDo2˚x5VQOTk\/eP'*<۸ Ȅ>Q"޲Cn jo >-p(ly=|_# O O57gd57~aKET|8eWG|YgJ}93ԽMd}&-to{XaOT:|_g:H%yk|Ӫ˸ֽTk[']:t"O%u؍z9Ҿwi6~E|_+ {?} zsyZٳ1XfS-BC"gW+B=/IiVdy; i&>V \_wv[x?/seFV_Dsn޲_ ϲ<>3-˼3s^^ߝ?To)i.|iѠytLs_>y|_w_$!,ieɃ? ߯7n>iO1X$3 K߹Xͦ:(QY '\HYI9]mBEoe~ǔd`jo-9%zT1p[i6AwO%4פg{!4oRO!o s.I/hgIfH;?3"H¤ xKim9ºli䰺B,ZSU9%0gbR?;n?D{9{ `Ei L_hޣY Ezmd*rܸ>y4}RͲ+۬u7omgKA6#eǵ(o?=I|nXܡr/1kA\&~>GF^*<A? [Ot4?׾g/qls-beeYpnϙۀwm$b@O^>iR}5YN!r_;OC[;RuӚ:Gi5{nc'fќ2KPWp68gpx!`}&lx2>+%<Ɩ brsܻYLϴoi FwWlg'OBg\eYsɽ M&<޳[.|_ nP%_a8*; w7wI݁/y|p7]V m\/ |l~X=SxFg!G(y& ґ,Jgy!>>Ћ>i.yL$bﲝ^CQ\S;z~Dfxygi'u>HOB#XOyJYQ6ږb:ב}Hf~8gOWWf3t.b=os\_}?Ve@s ĮCs̿2v"oǍP|.;?Fp0-ejNq:2.W/,ͻ[w\]NgzzG+-)By߼uw0-F[}#w>]l3. W!9\tq\?n]_[y%9#ﺧȻKǵTcK]f!mWwIg¼+dp2D鬡R] w͚EiEw}_).. ͻmLa2j.^yWZs޵̻Ai0C']_[]Ӈs]w,G,;#dMD'|:K翢Uݟ}?7zYUD ;Y]5tPnLW4QL" +!G{E+ L8ЧBi=i#wC?9jL'[ܦ@Sk= tv4q1wAig:kKJ55oS$v{xp ro.\'.MRޙSz0|Ǽ(YSӷAߥFN9=-po>}>j~efłpoj~4#rgr,< ~Lpop,]?s{QxtN"ڷz~WwԮyT[QwnCZAзNx.UJxSωze$T%[RE93>U-?"G ̆yaad?n~i;+f P)l7o^8]Ʌ*G`%[e=8jsl\`wma ukG*0#k8Log_#Rwp~۝2E_J۷Ep~&se~޵~ ?y~۝~a¯crOE?p7']vaD7&v?\X.?{^tCbi|r*^8\Md.G Bُ͢DkH )0Ґ=i*^2o;D2}gJ>G .>Lq4fE\^՗&p4kdKOS ϓ^ r2Cڇ&/dpt~\"F8pa L 2?X$Y?g4ys81SVl Xp#9tvq8S\$S[ekn&Ce8|۞-p{p-i9F8m g!yP,Η2R9k3e8s9ΗcZ~.Γg8Vm H{6!jm2䟥=; ˿QP~"^A[".eY޴{"? h]Yg<}?D6#Q[X4`SO(OPOO Ugњes/m y.O2͟NpmA n=:>xxJMxIe ޟwNdxuޛND& u 4gwmwLQ}Y |JZljA6qn}rhI %o527-xjd2 Yl}ox\,J;Z gϩGMH,?̡.Na7?XgzLŹocmOBn[~#2~)o۱Y 7/l`qYcBà=>7@n$ 2XwRًO9#Bߧ+ezr d^.[s2e'WtPWR6_!#RAurɌ\3#g6z,b6w6{p-I&̥3{3p(}QB؛[d\x i ܽȸ<㲹I]P?J 7\~pr~7 g3Y ȿ]K gBݷZ,n_wEa~:~CH6dcI'?sI3Fڛ6dl̼]Joa9;ߛ7:Xx[u+\_1׷^묊=+zT=ޱ-Z4_80| @{86d˴wC%Ҫvi2Ns|2O9G VNnHw[VOj0XF:o!۽dp83׷>Y*[)rSmP0v-6x_ N?;ztºOal2^wV $wPJWvV=m{{uP3$|$j,mOr`y^GKf+5^R~YWq~;MveL~& vM+>V<1o!x&x~}$gBz=} +ȼվi<&H uFZ% .c]B}rE CU-==&=I9o)s>jY'nRFq:\-ki=dzm@9~5^ǑV1LOxw4s5ցnY񲏩3;X:]]{HԱ\\G54GfC<ס:|9?9wwrn'Jv'}"9H{u?9}/{k(]7fc]/](в:+ J#f;졔`=g,N>#+Hؙc ~!d1meeX-lI&3- BzP*"r2Cϖ>='пz j_Řp5'^WCF9<_F;u6,W(>KuMG$P: wV]_CqF_{:J%HvS"SAt4qlۿRȷӮoX_7ۘ{TZYƏ+Í2Z`}.kWKqgXFX ޠ@&}~?TsZz-cY5͗<״)5-{J'_յ| mVQ&?X/4T#ͽ"c"4ܟs_i~Ms?4l%5a2ͭ 4Ҝw_@s ϵ|Ҝ@ii sx9e涬3\Y(laM `PiNs CUQ4~#ͭޫ##Hs|#F[YicLsc)͕U4WVf9タLο4N4}rs6干\mU2EF{C}N0kNsAd/?_S_ |/@]k.:j2J }#?Ԩ$60iAb?SyZuoI}v>jKC X:T4s_]ckw4?`5=> MƻU>?7xJvjvj|ז6Q0Qk/Dw_p}7޵q}ߵRryF߻iO ƻWWboڦi.ύ|zJL߽[|Z8_U/?/NxN?rҞ/3rEwS?.XnCseXaG0o~Bzߥme/á&قQmgIgZ˴Ģ/g10;V/L`3obq7"m[!LJEqoaE =is=Y/Q߀eKlSgm% Xqy[l9U/C1H{ڤw]JBmd_L}J)_Yj䧶zdaa:ÂaP1d0|Y![`҅?.?lVd3;u+"ƿ}BM%SH}#+W,ӜWײ)kA?#ǐᐟA_.H(YS)Oy|Ԟ & Ëyistz!UoJ6_/%-}ۗKۗݳ]ak_ |Ѿ)JqT%یj%y&(0pu{}SFvKy^Yi<-&ϳJǜr8wJGnS;d-su;lj YEbV=fc= }Heqa n:S =МB#&B7PdԿ"CZ]Bg\)%k_(bڕmѶDp 9/>gl0{ jRϓyƈ }Cu֏+? _c'I"y!@V}] @ƻ2A' ~JoLF@c&=\o|ւ7߳i7꿫D_>X]h>;eUwQE=Ї{@[&ﳊCIpԗ;꿏Obv }tQy$MUȿXkTH0d7n0\IoF#'4\h?Kk4`Ls|C2坠4,aJGIFS[7-2]ݽ  6sǍ4VW~#iQ)S_F!,a,AL7??~\j(Nk(OؙxV0gpv+xϖVgf;`$XWuM_=.俬b]f^ ͫod}iiUjR3 ?o`޳|/DݽXgRT7 F?_{6vP7o4¹Xoi[)7|/?ל<|OX~~wTQH˟jKd\ /K+B9]v w?J,~qEJǛ"b153X8oJ|۳ik0g<9akouXB꿀 |g Q>܄=NzN qC;տ%]C`34~f[ds =?Y8UK]?:Mل9{XU+dd&|-2Wd*">eUN9XsXj2#?{B )C]!2|c.s8f0&3[ɾ<%y;I_{1oo}G Y. '3әs+~+οMaH)/̿|_jv@.c]ga$vM|{Ƹڍobe 4J ϰm3{a83w2mB3` y!t,?,C1H<>U}kdr>ۓ^?S nt:M}e ^sW JPX}Pda! >/ L`Wo 9a1xu|z6( Tb<amb2oa38# ]@4F=i^?k.u`5ey|˸Bz}{t,XOh]^>Pl8`J<s01=gQtZ:ħ]i 3a.}H{j$-V, \PNǟAgvuq| ??b׺|H)U%zOŴFy \NyA韶 M m%p[?mmօ.'*}OetYIgQYbR̨rԿ\jłq ƶ4-we^ڗ5 ]{傌Ԫ韛+wn}E v鲛#'>D2a]3藶{ SW>tX'ʑ6X2i -"(Z}S㷅Ogs|܏uH{PtP$X"%Zi?h={ (<9b@X~{yi]ޮܦ!{:i3c\g4*2'QI'|Y _2,9,g h~Ow8\Ǚ|e|jW+z,^`Y2w =)Lkr W ~g{u<7؆K|5wnysiK߀` /V`y*؆)TF?YMeٳQo {@7+ {6 EԮ2Dgza.#~5do /'qy|^Wk7B;iND l 9~AO&ǭ0z3,{g/SH,oyQ6Mg@ ^.fw-o3~l^?cP[`e{{NMamp6]&ҰMeY>zJ1mY( v =0nBQ\mǩj'UKH I.0RE"cv^?+EZƶqAV`7;n :+F~o+pDq67ũk&VVy{w.Ŀ -]QȞ>30~o].wm)2s0Ớ .dw/;W;Z ]-CV g|>,6>3DϯN:H잏Hq1#Xwgs|> cޓw׵ZB7ɟK *^][i$.#{N|^]Ń2 OxuOq=X/Ys:3~$7}Ʊ8XǺ;K\t߁ {Z9ř>Ʊ՘DZǺ\cه/9K|W|Xw,k`],W^Ǻ^?Oqc}:xz:DZ:7!m+Ӝ0#=M*iHkre0ҜG hNOO3SZLO!mzϲNau Fu⺀uBy]}ӝv7:Mi&I}OP0OO=l`hCk0zNy'!Ɉ}]"N5- pzE;fS||9(> Q#o>'>N7?gǸ:ǜ sS_}ۚ 5iX7|?`F"{:G/ cwPjR vw?㵧^B};]wiZA^1jS1?_zzy?LG<{6WuHK=߹_7bt}ի_|k6Ws^I~sɳw([*$nz4HӈaV"`}t ޚu5Fg/; ulW>8> h=d L[.=CEa!':wQOMEH(ϳjdyQ<0]B ӌ$K*#𥉉Z>n]?BsX ~9c7?J]*^̧B߻]O?p>8Ye˦sg G7|)%sZtdO|zzq>a>Χe]{uR[ F|~*!#=HoJ߿RyH̭FI_$H{)?<ο[<ƺ[_U#?&xk|ƿEZJ(D0p:P y re$; }Fuyw] ϼo e ,C/7,"N7I{#mRe8>'= !O+dū %ԗ>>Y2dăw_ͷކyri.3m=e?MT ?7L(!-w[!?g_yOțT&wrL{vX9w)~glVvZ -^]g֕dBd[\ d^f%oz&7R[FiV#ZAcS7y!k5}N$AtPmJ?nwͳ3H +Gɡ3_hY7mܻH .)oiNE\."ߴLN q-/;H Y2mxFyLBJ dH8b y6 f6+`V/FB9muu2<І cf H7MS_Y&/7ʱdZ" i%ΪԯbnR_Lp]e:}//w7"cW >ZϓԽ,;hćS{+'JRo|8ېsXkć=B}aNJ|Qo )2Nvf1_5m/1rzN3ۜjq_'Lo9Ԩ?O5x6tnQtpiۥWn7^u;0_QaYDܫ@;oX;0'՜'ty¸F'|܁fCR垝F+;^. tT$'CyqΪuRP:'H= .Wp^50|h;" 2~>q pMԃ׍c]C|=}gnwV;3(~|:#~ g)q*0'ϯ=#_Og92ohBf#\SO_^`$ziG5S>6YcwOG0ni7uu]߾ Ч;QHs 3[#d )0|pcd>u`|1ن!MsrR|2u>Ұ iF txRfB檹6>MqRX=Qi6ihrc?H=qm,KV RŰu_u]c;5E(6_3 s3zCd:Egr/ =GgCέcdZn'+5J}ӳ~̋w\Sxqx^3ÌxE+:#^zǀZXi1یxE+vq^F볌9^ xm^1W=(^fɸ/ຮpq`-/?!:7 {D.}@m-יD="?x8#̣1?4M{ͭpG^@cVp`'Ң/qA?eFflYYb0&1B/Tf9 (z}離/YfQ[a ⤫ݺ QA$ ͿFS0W`yוaqj` aL*[&Ү]dDeN[;&sf̨ 5f3ν9 )9;3j|g63K;ޙѱ=xg;3Op:U8e~gջYz~LC qkwې6*HsZ|5Y8?bvr`y>3+y=&.2|q}>9?F[O!-J~riSXoExֈt<2Ezns$sg:gr:oZg]zlooBZY:GP9r0?y%ϡ>rokWDWnFUj[r>B?ɤJ'{*Jۇ$o te?oӮ?\)#}ױPyuLޥ9' 8߂b Eq^㟎?C~P/"m$ȲozJ)i - Q>0mE-h jF5_ov3/&[?Ve-2 c-k!+g *5jh-kIw_@[Df4EfBGgS&M qq8|z7.އbGOGB31xm #??7Ta.%G iv1/<|BX?#%@?ŹO-JD{@=5[=Eh#̖s0GXCBj/kbFJ au Njݘ1"Ou !YpY ]M]ifz  /tEHVuڤG[z]-7|#|_hޓueI06^*G]=!ػN+^㼜521ɸdzi޳_#~(Q{Bj7 '5>g#+Y5XǞBl^Zv*RN?(NI^VNfwQ/Y]D.> ˚A`z/g=pnAd*qYGXvA=tcto.{: .>> &?3 AixY>Ri@i(WwEn/ kgzz^-,;%ه>#Ьۛ}Ӭ^fC4z"҆iZ:Gs#ic9*jM5|"JgRւU2 i2҅w@Bx%ךkcFidwcmmvZ*ϒҫƼ6[S%+ym̥Ks^&g#{ 2SH:qj~qXܘ̗4nE{r 4=] o .sO}ĔśؔH9/i1,Q/kv~c2J!˷YSeb._PC4PLo"[IK"T9SG[H_"Ǥ34&1eIIh cS sa{XlC;)O N2ቹ^v I._ Vy`ܻBTή>y_ܯpIA2 ,A9J7ʖsӦ~hV$^\#q.6T?Ms/2x0(a?_а,sXz j3ǞDt2^9l7@z. zYXwEG]/v{7 ul8ٗ:0ݤ$ꯄ^˼i_kncXs7b? ܫz6؀T ^>R]1o8|‫J L~WuU3K!kU*n#X}I,6_ vER|0 uˍ Ur OGxݰ=me(uÀEc\ߺ+M_ExyaW)҄1GK_ z,E#a˕TZ4?1JBKQo*M2Ǐ?JZWқ?ENscKiXcԛ`=xVSژ\A&T=/MwOQKm/v^ݦ!t]ߧ3x:W"1K,6.qmeb\539O Y$ǤǙS?QȺ#\kBHm`+Gg d|,c_SH$qwdѸ5Wr?3xa9 t^I띑S1.4婋ܤY4'|g‚Af$NS ]y%Ŀ" -C{/.+_|ޑ_G1+)gYX.xz^% jKz`٣ cY0f^pXˢZϚރ\0%6ausC虺 @8p3 ϴl*k3Vˬ^kN=P[$mYt&?5β/!qp<+5z,VOb=/4\7Hb9ڤ*Z|y'Nk1H)lg0/K \X?Ni u/BߔKV'ӺN wULؙ*&쥫xˉ`oX&n4S>5H'(y:ֶ<my,Ol+N;Tv\""Ta0eVK^My޿]9pQӷ/ۇOvN`ZGDeŐoSBw2i+X׷/윑~q?}yo56-!)u_XYשߺ`sQw5nLޟwo:֋4Aq<gbE^:xg}p@Q~*72:}u߬1FsD 1kPy[%^KuSJ( \ST1{z3g/翻yl-e~*MlG߹ ƣӸlYWAleX_6\Q6XGQ66;/F?ӱ$lCeq4^67y׎8л^,QwAp5? O{9g ϩ39з˅WL=|8W z5sb"!_ݜk<Ϻ$ "]Bo JqF2uXޣP­\ i?[pE@> \Q:y>=ʢ!P>h3W8i0Cň 8Bb>xXWi}{ldX~6_2?A>zJb_9j>EAK?2i>Mo_WALTۤ:&?94?4 3-Le/%(;Ho5-#k) 2̿ /5 4PtH<'~~&rf. i f5T4|:Vo?9UԱSw6'RGC''s}{'6q8tϋb3D9'F#.4#{4#tE9Zo !%:F'ټ\gB;_Mvx%{}l~bxSW %~ d{1S߱ξgd975kN kNCkvk5W~ܖ%kf5eu( h9H}ͅ8$aMfN.;њihTB;|0}9+I=g+k WM+%ɍ|Մi`;t(OGτl)ȜVz'bf ލcE=}awTS+8+z2gz$ׅ?ox056grgouIg9 ,x WcGrDDڃ f^YA̳Zp?;KOC8גmOg޳:-0qwVC =#udӌ :R)yb1r !/M{ŮTV>.o^V#YoV_Q_8c2fJ)Qf"5OAVͅyD欚 OC <"8Nc-sX0iw1\-x|#98%sﳳT|!>Sp/n7Ha{~Ha^baTokG{6_gFu|W^!+}?QjZE6Ǿu21 C?NIsPN`o4EDC _\E_ֺcum} /u2e<Shw"zxvاafFkT_yo_]B{!WCuN5gn ̳O$lJYRvX;QoU}oc"oU%9>DՇֺ.AMT[~1YGsI<)^x +Uy?Qn i*ft:_'U{y냼B(6}#Q'9*J}|'N4ַ}x/@޿wMNr+cG>a?[rwA(~b7Q?m ;qC_;/潲y(?ig;cvơؾZc#͈rrW1;~xl] { 0mjlFX>N 7ÅIқ۪ɺ;3~Y]nOwx;6y.~42Y3BfgܻLջ?h(n7m6OD 4O矸ޥOm}4$#柌Z<x6qx{?˃6OVJf?/}gtRZz`tv4b}RM1LN*/j5FI2NzXI[w`'_ U'm*[RȺT[tRh]GIoUS.STE.;b<7h_txU'hl "[ERuSDGNU'm'}rۣNaP,RU'pʐƱ\Oc:?[c\;8,\?4UO 4̺sa|b><.n` Y7>q*'~:ݱԎyZNTwpR/. oF)CUV/.4_Ao?t:|-C> 3|]"Gј. 2gB= !|= 5~}>\iLؾ1|V 0S᝿17tHP>+y 9 ߟoH_? y4Ch A6w! Ŀ'ſQ2@+fЮ=_&'M?&~'Db+XX0*l R,46ŬlGQf M|B/'H5̈IȺi`!N%=Zmmok=oo_xTjs:\oe"{@v@6eLtῩ6W_ke"}Sֳ\Wҷ/%\3U1KD5<ŴM|J?;y+IOb\qyȟ υDn"Ƿ/ _?۾択~_?*7qޕ8<H?:=3燒#ÿAoa߫?!\Ƅ}\翡O`8C?_o[?U0/CJ { devٻM[+YI_Ёk_=C밈$8wEd,G憮D/;p[%!kQ'*Moxy?|gBCRrؗA]ԹAO^ 77Tզ_oGsCe9 7Y|9Q9\TAD8fڗ*?z$X?tY}0|Vr %6 KgȎ[V+} }DSi֋/ÓjWM;UXOIo%3ǿ+ۣҵ|ZWK(c|D(Y_H>\Ⱥ}U _+SXZX>.Kܞ^ 7^~M<]1EG/"~?6.\ͬLǺf*`cPo_ Pב(\J~ap6}ts+"tH,YAYE^.fxmfl62 )vk->^/ywQyxG|RD^6ec|TKkT^1ku"/_<*zdOct8|85qxbqEi> {uq6Ǐoq0)톾׿B,rQQ{ ʩY.֧视wP=f/z9R|[W4!犯 ;ȇmhNP(_T/tz6EûX} >ESd5_4)?t:6Jw 1+.,qx"sV>,S]71_#5_t>~.;x27+B˙ـ35z?_Ub{w %O?:[`]Џߡw/dsws͔'ĨzXadGXO_{oԵY*`4`GW06~7Ԩ<D_[`S!aa`/pi?7{k&k6[V69#ȯ*osPޜ_.My*C|s},;$a:￳.d}N*5aA~=S-;x_qFOex!5fE*W/oy6QruSy8U??ݙmg 4qg{`*s c^$ca=qfv?b$=dۚ]c=ɺQ݉]yv +nwIzzW~6g7r|?ϓ;2Ll0Cw@eYzE\zyueLQdoY\_(Lʓe"zߌSe*5 b QsPY|ƩbAM,@?o,Re-eSɺ  2r XqIT$q(Κʢv Q Be1t?$MMc ÿC?Z-`jCX*_SbϫˇQSjra4v4ƿ%Z-_d3 \>4s|fS]SУbFrGxm}cm?Ԩ<}Ta(C&X|?fKc)yxl)y8&XG1Wy8(lЙiHFa>`QE]9W<߅wX%^qݨȏ}r^F6݉h'"rP,зwzPg16B~a~b> ϓ${3ɏWlT{?1flxINpi ň>˦{A(P+ fXu/8`؉OV0?9+6OqTR9CP Ec^ePC:oEjҘ9dC1Q3؎r8Cigf*Rl9GΪs8bgv &pwOQw?93aNBwI4~k3K;Y^Js8377r8#H mr5CHm\)3f7,9R F<eY!s2MV6¿*̳P[yGA4cK>p(fFK94~.p6{;cͨATo>?~{pngP۳RK7MuM]nYU}+EϢè`hn\^h!?iXH}ܦ@OŶ9ͭu;Ⱥ6 D, T?c=~?&blbj+vy001A=m@ lQKi:wMR t;_d_6qz,?{R>N 8&@ƶE0HvϙJ]R\rdg s]ژ#zb&13h9";Ie#tL)%lEy)CB/I_XF\ *DREOodXЮ @8HP|؀kzc}JpCy/KF}۷<5b@7ID'V#LG?Okٗku'Od5Rk5Qyx͖՚N1"sZ}=}q:9TQ3aȟS~_o?3D__τ">?wsGoʟ.y*|g4/gB=>cOOVlbי2 }f+ 湲-T8=znޛlo7[Xz.m`ُoFLSbJGzGvqzhٿ]!vPzGV{3=C7}^tO W干|S`;\b"s.ԯ-"XLTz{\zgo,Oqre@o{NCO3%5aFxp֝F]L a 5DYFnse'9ؾ|,F/iChÒʬuqu.(Q0 6\m7+?{(#?Jqw5/覆ϕ}Iњ͕ ,C|ǸpQ>]T>NnV3;أ"K3;Jqq[ dl{b/ 83ݟu3T 'dJ(;<|J|)7W9LPeݢ#(?켆ܱZ]e΢EeEܙ`o ;GV_Uv3#9֑ReǷ.Ϋqyeeg';w,<#7WXM?M DyclIᢼ1ۑߔ:E6oMoFIj4?}crsʂqa?uy"Rۿ=WmĖ69nwa߰0]'{/v8 <}7> Ǡ--bK^DnɽrV^ԛ7[} pcwӸlk(?#0{#D3M3?&/$ Op9ȜԵUg4FR/_Atzq??zA o I~ n~%{K"1fɛ_,6m^MuDf1y3g 9/>7lg0ޞy1Ύ17bfߓ?dXˋp k=9€?ՈfQ|Qrt%gRn#ɼd6+cw\w^K>.Iȹ8`x{1~s=- Yٳ4׊w$6<Ǔ[0Bwq}Mr>w¡yu/ѷSd]$\0Lk9^3u~Sxfr'5_sC|'m!0a(/#Βη׌L} /n<1jLye> :扵_Pw Sa)]a>;ӰV=BwozCh.ԗnFa;Kxb?vAχ1/GwWa#jy~.*<s'.Tp~sJ4 ETТΫP2#퉡CSq`'/5+7㻊g^q?k]s~Q9Mn/BĦeT2տӦ%I)PR,տeT2ĦeTR_&q]$'O?VחKV- \_q<%q?9xܟSNjDr\'kErn.Wu %{`< =CZ_}+^/&Pg Od џCAcsTrp?~.x?־I܎cqe\W^֝"k',Qi}8w u0֦0mA77g#q x^3mCOvk6Ɍ翹^翹^濙sZV~H< dL s]yL;oDs\/zQAiyQߝg3m(6濅o ~&\f~(~7d#|[6B"Q~TzyL_x0&&u޽F@12ܽ\0?\"~p;uC.~8Fn[nӾŪ|\5]%~uʃ!'Di|\5R6qeU`o OaG:bW÷.к*W${xǻ9}c_@ }RE}> S6oM󽉾` 6 l MfMCHaR'c3?V-jVnxߛܾ _ R+]Bh6Xy} U^jR3"/zROy,>[xy(\3Ry w?K\*ĂG:X'b,8xd,ZIc# U`c#hhł]kȿB&,&-3d[t7i, -HgՒBm|";wA8f3 ݵĿ$(u0Wʱ .JJK0p6blrYiC#޿92YE`]'ٻjѓ mrBN뿽c[T4l(?s7}y;[o({|?{RGi69(YԕiL(nA޽bsO泥@vj~cf[|-FN)im!1bIWcO//o4i0~$ms[AV|9]g#}Gu&u-mܧuì~7 lV$Q֔GjhV϶%wײm{k-l|ۜ}fmI¾x?4,&;07,ra}#s4ZǼ4gq f$܌<~~&]xqqwuSn@uT$-x3УoɨwpՏS/sR#sF1];ՍKȨ܁I!QH8,KcŞ/%`:VzOm{? vxr^P\~J} ygtD/&ͽUIz϶9[7l}r$xun+ZJp_dSr>(q iw 4 e3|1  zx_p2P:ex?\#ޝ T[ֿ}"mf׌QsH?zu*4iD܎h;okOώHc5#-5'x=3蠠pXgwbv9PkŽ/c/ܼbq;| G.l'1Xz^3t%~uާ"boϏ_ p:_u0-aocܕ03CA=Z*ĞusP뫝<ʬq ^Ӹ}>保,Bl<>xժ6k$:$,m,4nq bE<~44ǹ]8jmoiiQoAg&o69mc j=C3.j4s͋x}5r-s<+޲[FsKͷ6yLh:0'&#\%u0i$;eSޙbӒCp?jsr=t 6j b|ԥYya FH| B3ͶhMȿ1M[ٜ3<ǻ:7Ў0k=žvhh pA]=:~a Ll "wNwyڨݜw"ڏ(4us;ydTC.У>3>3\M}XeGq>xQI{z1aC=׋߮'e%к0wɺZu&C?T߹u;7\:i:⶛۲QG/br6?=L䫯>6:Qg)Ǣ+9)>?KBlQz?F ol{ޙbKX}/kd/*ڂz(ZK$p%mB=ֺ?{9@RtQ=aԣ2 =ߘ(={ GǁQO߯,QlU>&'Up֋1/Ѓ|"-VWRZGNC:`]KTp##MĿ=uGP*AT ho΀ gy`pnzOojGHraf`y $03+i{Нxg*ERL,GAn9.-RL`]d4;j*A^Ѳ^de$FeTVlFi`o +ޓͿb k 3 `;;ar0L뉜9NxErhʩ }0DO>n5E5enn!Q.Mh$'º.Mo]P/r/'m'8ztzz5?\ ? C_l6X7k[d !?Ya Vr,YfJUEFVphTgCk"-o<ܝa[!Bk]m}-oD̶!3;ߏpSe}t4gw]8_acƏeʏds [-|ȏֺ{uX4^%+r(?F2jwK~"uz៫K7x1zװbN+쳺"#gRǡj37b=U=2xo̅px-2h=ohAAkw=OP#nZMZ=< % ٿ]u8 3AùrxΠni6똳8CPw:C`tO&f?EN0r -VDԇ͢]I֏k%>݇ "v\ ٮMiLmi:4rxV<[wHMq8r8}8}j~6O#G Z:7Zhsltofe̯HoUw?z3of\7.i7 &Z #"I4j7u 6G`p,ȺTI3PW' ܿ lhG4WGҹپ[־g{.ͩõ٦7m柝^@w;;mwPEZS'cdCn*ӵsh9psŷn<(u; TQF;oݘ"iU]"ihl.?ENJoϟKj2D48ɿSd+fw2\UE|;ޞ?=ތ˟g`s?omIa]1} No?Mߏ@UݼTu胘}~}?olB?;?R,Gr)F??y‹~ՍϙU_b;G?.?oogWgx3QmȴӀȾ>0f _ehUNtߡW;ݼxȾ7 .@ud_ei #PG*6H;=2L;yoP7nnU'_=β#㝀OڡQ;G|L,5lH(WӍ|X"8;' WAW$Q>|C+*jT #?=J1j  (GJ{oJ;zfooo٠W7)T(*:,Ds 2Aj8#{\{:.ًu5p E!~ 6.{&Cx9]/?=6l|``aVy.Л2'_Ͼ𰳧?&_~+aW_c+j xFwޭ!`vjֿUſsz;rΊs#$:ЬwߪcFOd#AɆ+ Ìj}By9߳Ŀ~_=y)9yO3ѾW~jJ@˸,~Z=]; x;3WdW8futcj9b{􌳛{p2F آ3ݭXΩh9 G0DE| V]38~9]9oAj"Yfo]Qh]I+s6sQܙU_?nE96kQohZ{$ \*2UCmpN$HlM3?/g ;)y(Vuۉ[^: %4n~4ꒈlCW WwxhWw#0Nֿs> `QD[ď#8 Ϊ~&[ΌLՄ H`&(}2u^޿1&|vT'nz!?;#hL4F2=%pNBG*ӫK&=AmY9 pPW"$kl:ih|daz|Y0C5,ڷlOtO|p}(] ۷,gt ɱQPֿ_OWl^_?#bFLmh,ʯ32Kt6vx}_zݴf4>Y{XzZ>D.ܴ7RO֠ [~1qe*=h f>ftEJ>  ^$aIi6$G;FqL~(o8a~ Bwc=a1b+])f/لAG5mb;s]ߐ'o74}/S鸧VysKsy?07Y<ۇdM}$_O!)Ku-ZdܿN.CuG?^2]}z{x}]W༨.L72HM> )&"{Mo]e}Ѻr+xIMNl=we6|KO&n)q.Q۶N]= d=lGGd}#ϿLgq[QP t$;JI?k_3+tÐ<_9O/<7e<$̃0u*<'9gZ3gUޓ0߷;%q(pm's")~T6chX72{8 9 sPk6 Xa]  z}mMI6&]29ƑwbZNaHdBΊt7om޿gƞrwGA]-ۙ$]pOSvxyj;+C'FIoa<}"ZC#ɺqV`~Zij' k_!=UݲIאAn[*2Ez_e'[m?fxqIنruuq[ĕ|QߪYo(5 ":Q 9K*Z3xO]KEsq~]T~Z<r6rwzDggu۸gʏKwuKO=S'xPoޝ[s&1m/ΩĠsFo.z{߶Kvoiw]9}BwO[6wPg(R "5i.AY(Y/|oCߔuP]?/4,q}qo4c98}])wx%v+>)iVpBۛ՜Fhr< ap8 l?Cep2ӿR@ b|+=_g!\?RȺok|[ oAF+3M .5ov /^>gہ>GX큅pxdϓ\H3sSI\g_΍'ˉ?9zSMdo{ú ח͙\Z%\Ƈz·wzU2:A BP:{7b.M0bٳښyٿd7.ۿۿ򺠯S-,|W}0tNͱΌq+Z#;U(kCZZ3mhby5ȱ̄#?aM\g^Ӄ~)&~D)WNpx:W>jskY>,'_-NS߼; aw!i8YU#нt\st>k݇ :bȽnwtm%aD溃;U*iҹ}J3bA]Ow#g[2UXޘu"J 4Թ &T{-Rt.їaD8ѩUE{X<$+myrC|[tn=:}a7}Ǿa%`9]i;W:ג; :\TINA7Uvē]E|ʨ΍J AqHYVA-gx~~MtN,SQ=>E= ^L~Q: @{~c'ơ9<EpwC4/*y7_I&IzO#\؛ׇP?,Nk(wk"9AT_"WZ8$DmN?8B٠˹]l Q\z 27>DjɟqPRЊ}=҆kW7a>m@O.޿*?uNocGbo0N:(?g?zкW|>o6 :Wn'̚dw#>j~#?/x8=}1`7gߝ1,9 #/p<;ol4gߟī1KԘ2H?`hqĎ׋5@Z p>$X%b+y](_ts(ߗ)m5מve{yH;˶{H:Y.kCȺ*|펣Hs |Kck\&q-k]irJu"~FelǶ% ˁu;u]Nplb|K*ieyTx* q$0UfݡW'Ua7 xO(92'Ԍm[V T{8SЖTC̓"o&ݦ'4a~~J9M,/567v?J?./erF{~hc#%VmzWs̿}C̃h?l-zQmd:H,z#U^ʅu륩zC~t}{b_4quάQbЋ{.xک u_v5^Z̃j? CU~Uj`u+`AoWʯEFzmUf>mtEW0~5eejg/yVTny{Eu[@g WWwh3^/yu$d&o8vv_ھzp8[LL1 V5Fy7=V_zX]_ta?Mi g韲^.\FSg~.ы yU]E|eN-8Rr_8|␎#7b2xFCI֑{'\q3>|gCg(/\8'çKX~5g@RY$om#yɴH dDF|[jL=ߟO~?/uP$>sH`D љ%.I;Љ}-=U}wa"_{ڂD]xuoQ]xL|~g5(ww_ @J._ }-"k)bT50ߋZ{0N|#[ oŸTFgx=ߑmӧ]Qʼho='s6b z[ ׳ڶUojJ~g"Uk* .9NKR'%lw?,gPGD+co{k_dh,U=VU #U[!bi_#v"s)pm2$OT+8!=k3qUV¦ ,޴]&.0܎.,,,\а@/ R 6]iĒ&SK7m@Ayyy_.~?(<9<>PynasM'\$s/yMf x+tY ]Cza5I2wy.oj@*N sEr|GmgQjA^=+\M= ,ߗ΃H[gxeJ$[3k)BнEerλKFS|rލ3:]j>\tS y6s ߌIf\&ȸ )$,U_ f\&ȸ 7\>HQqi74zUAnhLP+ _bz)`Ǽ'!7P. Y.wB#{l ׿p!N~տVߢ%zz zg߾#S0-=p) GKa +H2ոU\;d WswHWA{P4uKq<>'5.Wqt PiǎFJv6j_+u qSC:gJb-^-r,^\eC $b__+-ǻ8zSͳ+ E / zWzq+-a2_da/VOF5vnw;}k#S7liud}WO#BHXa^6&|wNSUwz!Xcޞ|{wz&t2:{;ԝ*NiԗӛvӮ ȗ* Q]Rbd_R}jOF%YRxd_;U׶|=ށ+ƣY,PlC9|j,ZSXL(Qɘ٫}2g Do/ʔb6 lztR,XgeJ w7-S_zeָ|Ř{DTg3._:(rCU:\GN7p տV躳=nG%F2qޞ.*pq>k`1TtN`{m#dT>BbuFu6P@`W%zM-wBqqȰ{a6œA.Or9U|r+1u:Fc$1=t 8X:I0Xۭ#(?~4q6_A"L8gs hgC~eziz&lp&"wAAw"qקLGP!.ޛzz|h0AQd,2͎q| w?~l ̓9sz..s ΃/*PM(oS> \M [/8L8S =?iO6|?BO;7ϝw<<C׏]wH|HGC)c_*NXd97j\sA澫pp<̨=2hAf8q;xv\#>m6?Pņa),?ao(zKo`g/nmo0V5)lVC_@3I_m&ѿXg{&>wN-di8>>gDGБ)ZTX~ZѽN-h]N=pA~ԢO.D2bE _ *o 뙞>|FNv[a:G-lwT+RLi_bٯ!_7r(+>nXO0dz.Qӟ+5+33M3[dLYIߜokRh3'mdgւy9LGh[PK6WmgV@-( {?sA/R{ ]ׅ lɎhP }8^xTd>S!l/NEZ?>vWy^=,ǧ},AGvf wi{{( G7ׅ?˺_Cq_L:nԅ }lm-PcO>SI 7f磆|iJ~ky9)>ImS ߐ"迺o{;pJ77!^, v^x Q&D=A罱 qec1iOF{iG,ԍS=NeIB/|,;$겏o_ŋIH:d*z?&{-jS)B#~j~%3_*S=Ԣ&D;*|FlK_i cj<};/=hsPe{n^tK:iAvfηqNtjcfV=ݯw=AC`NWYѬ8vhfOqK?<?@%}h]J nwp{:.w"`?6|-ijC +V⸱̑v,U_{-e W硚ի4>_-cG=m|Q^ rdb db&oH~{>?@??"d}mgZdOŰL! !?͜WM!??.J;(gcQOß(SOnNFN_]'&Zq]PЅBgMux$✞l2Óochg8Z(P/pAZr2;?M8%Y*{)Eazw% {`r}6?zK>I_]}/{`g|M GدmQjHsQ>?s4zbXkP[sr$^9C6h[ٙ[Ʒ. ZNS9A3 o]>o'd<8l4P< 6_ie2o^o*n K#={5?S5Mg; 2KP_|g7_E$ԵFOsL|ti]4cθi#9=ȡw(7f=8SwLgF*ܰ#6uh W18]HtYJ-ova22 7zBp=# @Ub]nQz V2?ȺkNeG8(]̄~hJ +d}8FK8TrjPg(2)"Y-S˽ qH&A<9WF~iiִc_Xy"ˤ#V&fM' Pr%\$&;QQ#Ƿy!9 x!:[¾e){v^S}Eۇ ݻ@懓Cf='(1o>wtNNpO  gOt3-=p+PiS8h4zGl) z,8RJ({W`뻄lMjq"8h[d'@賏Zgcd}dWM>QXF[hK`:-N{|G5fՄNOӍpcq:c][懠눣 Nڗטst=N N7:~qc ٓv:QYߘJaL^q{˫w!oJ dZxޙ45U_j~ϛ~8O;RsToC:|BqB?8K,.m7Er$.mezt焼ܛJn,//xy-fjKϱl/96!C'0Oc9%̂;|fMz2l8pw%sf@4?3gM  L)/M.>Ж:vŤ.,f~n9 u=C}0~oR9;Fd§toffo|x:#n;2YI$O%,71 ]qiuocDO"Iy%BKo&vB>M 1V?? 7 \3+/ r{NE>3a [*P,[ rIe_C1V.k;I1Le] 3^Eo&6 Wi;8B6,󭴖y \f^ 2-ge?̈́?" VC7hd0* 7yrzz;ގ3UY*~zʳf `zzMewԶAOD[x|g[ȁH8E\.qm C .~Xׁën7|BLs3C.ĝc?P '=bdt'qG.=J(1~kpi[.$!7t>LFy "SO.r}cvwY淀!"f[s;4cmw..C^DO*?in;D1#LI??{+bX^h׷>LמOrC}oo!_=R71'*/~~l n6%AM^rP|DL1p49ڣ>DbſP,[!@ ^s[º'LEy-zoYE?BYzDӮˎWNuR{16ʳ6Fsy?~{>7Q4n3TCf'#>&>?Cfs;/ [:  %[G.i9;ݞ8[YzR?;.:d[s.r{]5\]l〉Bgt]O4b:\dk|<.ȡ(5՘t1.8]gљR*^.ϔbk8 E[#Uܜ!r&ύEkγtoUzCj/tGoa{~S"̿Rc*{ %_3iwZl n?߳ìDzܘy/;wGYcBd#jaa+D߽7Hg=D{.eMWg~x9-Q {~?Wۇs B<7Jh7NOCqhu' 8v#6G|TO 0׵~׵{!Pז-:Ozum7/k4?I7׵/I/D vu$#յp K'u繨=zyKT^b͟Cیi6[]sQR]6'۷YԵل^vJJ nHg9%RL܊mgs0 j>X FeˤHmn~iL_ZLuJϭMonukTF7[h ; 8!o͕z+F5,|dL6Edt+Y^_#gP+ckNjv6X ={E/Qe:@v=zvYoMhv@O] qުM w!3}t>.wwhnNf̐a}O>o>#eDaO4J='|u7,h-9O'NԼ;QC  E[`gghG'Y"74Vݷ"JLYgRŅޥ3ZĀ/`4s|>a e-TsX4T /1;}d|=,.2}"|o{>q${|6ŒzOG#e|36 |0]wRM--{P>߫6\c2ޘE}  !+\οYUb藋5&%FSש`p#ט XeU.D:*y7)󄏨ķ5B)}N6ydM8.(ߌ6yTL'ɧjش+5vvmknx^ Tk|D1'}7VJc4{ׄ;V;VyԦsyk2 'g9oF$ otX3Qy=Dx7-vV9a6|*v~/#%c|SFd#/OFIP Dž*fS6|v3lggv^m6ʬ[jE;n]*1tg7cW<g6,z#*{U\بZEUL)UՆCmdmR5{!DD\i~6 dQ,'?_qCvfg"{087PУGuy/0XGecUzƞtww 9 4߼V#Z߼ޏ7AF6s27]п_ 5Ǯe'/SA^6jYA |˿ho;7cȇt6$[}K:H>? t5q=_^ß_G% h6s}S~˷w ߂.Asg{Zk;(˰u[H7n#kypKqqKq6=GSk87 މ{ |@D\in=LyT?v6=rl!δ: Shrf\T5Z,Oܓbѧj_|g{xgM[7Ya ;yOI*2I Q8g[Z;Jz;c_Èogs@ğ:R WgpY, .!ΰ-gTgҕ{Hlx}I>;]b?͔z<bWhpEq.?Vu^rW8U'Ag|s&Y/MyNN͇D3bd?u5WGܘ]߹_f0^uݹ1vgiwLGo7OE{l}+-虎~9θcq̘m@`GXYH9Vyy,oUߍ)n O.kƱg]Tz)w;|9vf?+7@U息Wؙf9vr\)bgNN;bg!y4ݡz $@~h5y)b3Bh'Cg\}Y/a{8730Asl"m CtsP C)\aJ(6# K'ǐR:FKg k> oS/`>Mse?@ȥd~'/]NBy<\&Ʋi\h>7-y#)x G!QlG~_GQ-U W*|9,Rjp@?Q-L࣫zc5 C̲}@y,3/:Zo{7gt9&wsL.(Qk9`7*S?TsL.!˥Lþebr6;Б!&7`onTm_sok,k¬cr^)Ř={g3bl[/hI 42C[? zBaW_j_߇cl:vݻgaf9+bq;d>aJ׽#r&_=%0]c+ozk?3.7&+e?u'`}3~W3;.,L;R[o:.)- ;cy2,d=݉wOg?X# Kpmz3ֿYA{=ޏ+w?fS>}PmJgP ٓ sx!ob1g!xhd q==A{A:\"hd:;{߃? eN3 7Ϯf =}Z#Zv?Ե7Ad C;VQ|ӡ< ̉v-:V޶b>I̲K!P搜my0<#Bf<t%nsӟtbm nYfn'œf1UߠaSLbҞ?Y?j[/$[?~oR^ap J 4ſN1hd3.}f4 VT\q_>E=Aָ 7;?QD43.2.Ǣf\pY177pKzC7tqy@r>k\?Y"ݦG!*3'.!Yw.،3p}̸Og팅B9f\rB EKJλ PqYb{IƥP3..rg2."̸7uPC͸\ށ ̸<}wq0k\6qyꀌ˼@ۢId ;d)bOp@Ӎf\+}IƠ' eV..מƥOߖȸ|h̸hq9J9p:\v_>NZ?\Fj͸6wf֠}"o!~-oVѾ] >Ķ2nG&)|=~Ի{|UіndyKMy=ކ_}gxcy'Gzux"W?i4 }7cy'zܯN<ڥr?^& j8m>?*G"/ȢpGeH_Fq*Aˡq-J[C"]=ǼM~i7-4)M_߬nںn)]d?cCxMkvq-n55~sW ?,5qÜg5-+kִhm9GF5-_{̪!?w#=F6iIn#(a3$9>+#ˢWFi<ǧ6DM5յAM-BmTˬix5:NiG2FnMˊ# ?FW[.y;w{⳥ܓ]f 6sypMoizP4[|ۣD5`˛Y~h;y >.w"_dEO?8Ǿ[ġӟ o+Gl><ǏExcGHdt}(eVlwǛav9vs8~V@-[3:1uz+& \}!w؟. =g ?_a/|ȱ :=0[xWMh[x?}{"D(188O?K92a?"v`w(3n&3>?"n?j7̻"]s}wqWj3͸kqH̸;߰I3tw^|w!ݯp5d.^=`q/MCK`w\"-ۗ&X "︒7d(!]q^f}6\݃ӈЌU˸ O-53twRp3=kƝ.\uwc8.'[[28Ih|L-Y?ׯqB>?f!j3wh5eݞ\w&Z_pl9;ی=2L2ke.G(W@{wݞ^lˣ2Tc:KEJkE'|U_ڮv|_ v\_AR٘[A_h {GʬF4+a2?h;,__Tx F\~9-.pW# f((}t'Wyh)|Ո'-g:8>lY_B_>Rhn.T}hQr@ ɿ/ۡ% RC\U;ֿ ^q]Js̸'n*Wq_߿&qEnjm`Ɲ.nwOrmԻ:_ 5 W@ x],Ѷ[[4G_a 9~!_,+h»鼯+hXԿyxcj;փc[XWEf|1_9>hhr]LzmS|s6p|_ikԾ\hS"΢3Eo'Ǥq|O)؞`}ߞ{2:@?U_CŇwǖݬV=aE`="kz9_mBFS(jǙ㧊rD]]81F|9=iE.X@Ѧ[Hd)^&ۙYsl>(ql.g˽~8Mrнfy^5|-2o^^?(}B "Sy}[+D_%<;GlKlEp}7g(\6+o%|F(?R_xht[9]d;+9nOX&R]?)nKjK~r B |t8G,w։$;m#@s1)2: bbNrue"/gq%\:zh3 [\^޹.󹸳hEkܨa>t {uL@p.z/bZ"$}=(A\/MıA&{ⷒGR\a1_ibL|Ş|,W xK9dj6OjguwR8㪨td(?Ru5ǚBW{']wPm>ʼnZjϺ~sUYG(n(XFkg\O0 c3F9vcpFyNïj2*y-l)ϙ繎mޝnqr纶LRk[>No16jmfwzo_dc>ӈn:SJ:1d#IuψWٌg<F/k As׀_EHqa^>IeTPDS:ӵ#KKJ7ܸg.v/پ΅ʾgU}3~eﻊ텞tߏa۵?̞)xƓ3Xm>tv:mY@^XW(.${ȗu{%LYSw-Wmȑ \FuTY(os>*ٵPc^?a=IC/ߦnؽםj=۫dWdgg~_8Ծ2Ӧ~r9q(m:VPZ1u}]Cd껒82:3mS>OIkA*] W+A/z~?L?/w.״fT?0_ -EO2]%oK5Fz5j}B8ߑϾ_xgo8~ghFeг}]^6jNgV>dt kl|hF&g連pNHd:qp_Fa<;ͩ} o11\R?>&5\1RZ&k2x+{y?1ُ1YE(  a<5?X@ B&OZv*}j G/m>B9_;g49TdsPhnJggbm3OqF&x~<) qA>=JuOULtEmIQCu$)0O"qџ$AX͐74uql5~"P?;ߦsj j bu'>}l}w$]_ulv-3DŚM_m"n jaFE=V > 3r ]oyy,e(ک,YcREGv y/:r_Бr֓w5rplc^ok|u2;+筱zP[P{|آdf݆ƠgWgca;y)&P%O$7JRel&ɣ?m ܏衏zGvB J$P]>n_hiD?}ts^?-hj.;'߻A _ }$~zWM>.+/{>h 4) ]cі5x w">}ןk=3.==`{S+t돤xY6 \sOVoYH?VF\2ރꟷBs@'STMӢeK]?>|yot<{N:Q&-/E_Y_I?_Ε-Z>nzfYܽv?Md09A"G^j+VSߗ=OmCL6Mmhd+=r~X6rsg#@rO& >"# {YY<-lsaѳdl-[k4W4l3?#Ϳn.K?{r:\GNj?;Xo4zd#-|] I?'$Ý KO.ޅpaScPdW3'G8bG6nw,2z${D[ս?_[ GI{y *=Homv`^ wv\GI{Fosr' Aqsbw/ =$6+(^^i^ eoxE:+(^^ $߯{ݸWS:/{dYyI.D6@Qli|^ -=<曣/u]}oR{/anS]{Ip殺D~JP#}nQ7W8%Z>d~DNfw6vn0n^y܉Q[/wNw^:ەy86Qp5Gcﴌ(c)*m)p,FW<}{FW3KQ5PQTWB_F|:7s [;: ęZYkA\5WU{hemH~t#HoQG;}U]`iw|ۨ&-e? ;;zv۫o6q6_*٤g` .kd`'㇑__)@jRr!?*CAmiiWpI\SKYH?M.hxVB_)z"q/Ս}sQ@~ {Q ;P}|{H"s4L[ľZۭKwBq7>gHSxH5\w*?_s{plgqW!'UD݌Wɸk@o͸%5 b %l/&>bQvO?Zm vk<yDk/r_Y)r5Ccz{,o-炎繠9%;x.h2X*sX>()w |uSE>c9ojıj!D;<F@Mi9{YDAXǙnAs} b?A_^ܧPs4u+yI~n]=E3>)5GÈjkfePG "_}qQd&dC&J f\IvUjŰiG6Ⱦʷs_lg]׭=C;~iqd0ĐaK.T%Pb3rK^=_@zI}+ƝʅgeW}ʼ=rS4 e:y-Pg.agԷqLܣ>$Էobkytgl*p,N p53 =pۉ_~c_7q9gaz )ָ{wOq7h'qbbK[̸"gl5wOoE{%%dGv[+OmBj/8d|}_*_Pdqޞۇb{r e?OO44E-RYF,+*F4`q?kb=O3֖h-P̢wܟO>$$XƉ@=翃DveOX! ;u{.{e? {Yjkg0V00@ Þ)syNs)\f[עpLȯgx<坣f9`&V L _>Ȟ)0Y`03r~-?">UsY%@D9|w^Z '1{{ | ǡ;0O Fg*KDl}8P_4|?'OdVTt{['`61̶hO(s=SPAYi0g?W#EQkp6z?yY;Tu٘@YQ[љ{KɛSޓ|<E3 n|Qukg+ wθq=dz%^khٍ;k(S{;g!0OF1W|u] y,σt>by[8qBwTUX@lL|&>5 žτ6p/Gr(V=*>㘽Jyf̎& qbv\8_6Ff%9+v;XfpՌ㾙::Q;?wm9Z@Oj 9޳f/\rdy,t,nyb9Ѳ6sgmK}jbW-0>JϖgAWz1*BJUa<ԃ7۵LUV3p)-}zu3<02<\=rlc׬)8A%ibp>B' j"9#)}\\?zhOA]YLTx#SǹslPY2qGX]c{j#OuqkIY<۝oO@zq㱬Lb')F7}qh ,/x>$dl9\7_0f50JXf1.&w^&|#tl6Y΍#Fh?پ>2+t8;;M;ՏfeK%To.;'[ ]*wIٕdL} [G!GdG#1 њ(ns<>6 Z)g)o; oc4%Us>~ oㄼmY-.ׄ}d8KɆaNiYOFM:K"ws?qڟBe=G葈\x?!϶X-}L=_孒W1yuhAf(ֻ~ۚN5=~h{|z hs<7D?\INsSj~WG&~j?~L߳B~q9G#?x}8^w/u{bsb(f{?wT_0?f&&Q8;6Rᮚ!kHu9Zrѿ 1?1_˽aN} U2UDq\*֡Ej av6ÿ"_'V뾐tny)v`QR(s-Fi#nCg bd|~G!G %^Xs!} B)\7 5(խF1m9^WZ8˳eՃ6_gcP,Z?G,wtֲYaCuぶz1?4|/͇ǰ%=lbGKﱙg~=3h/Ɖ75No/#Vzw$ޯSMZ|?<ɣ~'"Up6hރUXe+s߸g0k>jq߰9j{VjJ>SzFW[/}!d3!fp}N.'};?y9so6~S.M3tOL{:zFkdG3eLS P`cc{E#b;?ppoI φBM3t }LO}~VaMXϿ-(jUj=0c%{!Ipo(k(Gy*U3./Kb }e$>C[yL'd4Q/]Z'OÍdi=Fߟ ٿO{2~~>Mvys/0t }2e=g OcID=,ӪD3}a_9Kw Vs{8}7j38}{.>{*Q*}2dL*}nlM5fnLvwPlאL.O=5^^NN%r =Fq'MOwy,,zg.s"ݩOɹj@ymcWL;ԖSzhuWLm=}l8}CߓsALݯLOLJl -w-šGp4w8rgHW4=F6 G ̀^g +{ \+r'$q> ]08jʉ6qe~t6O_,N 4JiYֿ3IO}V3dfV]|q$P8]‰:(4[f/p +08rw Z"S3 8CᬦM"2zPd?sg4> >|;ru  q XGhojEπ.J8(w {C[B'yQkY"'d?HbC0o= V#O\Q0_ Wq r^9 !CP5 !گcq9~SEl.ASA"67w'Oq\yʿT߮&C9~e/'xK4F:Ɂݧ'ٸKbd|crJ>LwSFg4BMcf(wIFDi ?}C$IyS'{!'ZNN:н.CO?i|^gz?w=BO?|YnFRWVcDwuwAh7m'a>iz]N=&|(靧χ>{~ߐCn.]s.]sGoY'k]~H_|0SgP;m;^oh]Vg=hc._P\:6uϻ Q`΃GzW},g|z/cuyx{/PXaiTº,T..,,,,(ܰp XZZZdi…& ѥ 7\:qirQyyͅ}%\>1'im Sm%1*Wt p$]耿 %!|g-Apf_W:6ZX9e6p{`ܕs{ϲ~XzGާ<= zKy'(9y@Oʅt,|[~n">}z;xn>W9'4I,Bª@w{P]UG`)OPբԮpR֋wq-[sM1-y[y]Yn Bس˼ '^(1B|YZ2uu|Na]I𝝾Xr}9$ɾ9$ίCsH^`$?E=n'ͫ$Β\l1$* Olr|hQpI#|r2öN}qif{|c }8sZ?|p.QGc˲_|ގd>LƢ\X o](k_?i :'XC̕ek Њ)kw/c4e&,qTxn 46zH5$*@ݺ;5s Ovw0npCnT4'=YKKAEB$Vaxbu 18#G-)XyP0Zܥy2oO?F?(O3P X˾0. _sOFq]: ҹHS Cia}qY9;PF6|džiːFFaƣPF>Уq\4.hhγaydZJoql,c tAl7Mt3@W#Ŗy_āuhw[ 1}y' tl]t*z}-$σ~~>WKf9N.㯆vz}A?bR3.sjwg}qv!m 5o.3̼ uc뫢9Ѳۜ&-/5buݫW72ü~w/e?Y_a${[?N^5̼1Jk!ZT:i_co?ܢBUo$QX2ZzN?ܒ'_1⋼`$}n*~lFu@]̳F}}T˪$.1g!aߍ㸼oB_`bQگәo-l\3Kc~ ~kHf:DZA ^>lbt{CT >OHئ  x=yb84^Kcdl-XH'|G!BsorB=zz^2G#OQ#gz2/}5;l+I{~b:h躎@W֍LuZjlL8N{_({y9sxlsr:one}947qrbxk]VztVTZJX` X+m̗ϞjJ_~zp{e3 G5v.2I-/`~`<G,m;]^8rh/нnOḽdI0Y>׏ʇӉ@qQhK2]f>.>.oqYڍCreE*s|'56cBf0^4|鱟"mL|fl@|b7S2?+ ]<NjFo%`ס-1| xV1h 5dPHF~=lEp{.4hd3$G>^><2h X[< l]lЈ/mAmoiƼzZ|v{k6L^o70$?_}]G?KAhpv5 4?/[HTEm6Bh5_4 'Q5}4peZ 4p{wMS]-%:V\3D!i/'ZN5\ƽu\Wa/ӝs;qyHa <oyu5 <2#).P}&s^kruH}j;>8lg)k|^9U~h-睻93>;j=39>p|Kt>1sr sT3>e|g*>$5pri{s#a|劉#tmADep35ۂfpx\Ia}m@?ݸ>B#] q] º|M`}_s4Py$jiqX c]@=+;WH1)|_'k]$˿x?o%ȿ!~_ _A KߵӁ;Y 7' ºB%L`}ȿ!~䟴FC:kw ʹC?ݷb!]:xovn!t 7Bm!~.?qȿ!ȿa?i}(17Bş^f3o"_I6/V{BJ?3 5?w@ o%ȿk&:էe|g_D}F;u/ubxάO.6q#ri>i8NJ>=茬O?*ϬOE|#Z OtIh?Od ҈6q1cpz>kx R(ncө܉H˗dXb6"[#Q^ku[gmmi=YLcb}K+Z_kѷ26? r2(D$ldQӍubG[™>pTz<5/p$VD9 ﻅoN&Q1~Mlʡ8 xadw}rEkZ|A˘bq S }~y?psZ { Пy543H;gW׹5?Gm7*|)>*/Rw{tErGT.(Yq[YVaޱ8*a'Y}qYq>YVdOeYQ?͓̲b`9X,+ޜbrYq>.+bvqz^EBGereYi.+#8;>Mb|\YV\y{IYV虌ldL{<kst2 M/Lyor*=AAVG}>ofi>wI! 2?aDRվε| 0U}S470 N=z>|y> SV|^ۯ0ga:_'Q*Bw1G=u9x`s  \~,w2\5v1Ǎ !׸|r3Vgrx+Ϗ5Sg?$8D9<7A!Fu7]gt3YW <?U\qM%؛Ǚ$R? ?/(sI(Oaš2M#Z"3)_(6eǾ9ߗN I*,L3ږrFu|,9qN1zZ.b<jk%%a0溺t[!7\cp>hmM>]̖[9~# eKrkdY;TDZ;&7[g7wnojy)wPoqLGA 9жDuts6{3mצЗj0X33l,0dcO-ycEYD}憂r@)דl΅Eϫ=G/}H8;y¶]Ǘݖg5ГEgr}91mѭbO\cmM*> ?o+FsmUW:w`1|>'QRCN@ ڞs؋< D@sU꟯ȷpoƙ8^SLȝb_tN;rB6;?!G&8~V4[(uao31. O#eeހ3TcuϞr{Lu!Cgz4+A11F~De[OaɅ:+`^sb<{1PӇYZw=H;<6Ci F݉՚Ag*F)UqlzW}ByXPFp^,b?qҹ..0bMs@G~)Wyvoݻ{]mm1} }l ?pQN)WOtL5c?r\Guus,Ψu([Υ>]uS2_=?=]b_ߏRQ}uwUS4]T_.˟kY:c_6س^f2,MK!? ڠx;\Ewq6 y_n/cwFK8wGu]xoT?/`1}-q\wov/'S{A?ۓGO8^B v!f>i7J{:W%r_ _׷mu]c~sd CE ?d?ˉ"wF *u}7N=Xd>/,&y ?,F!c[ci[B>,5H̩D;[-̻ۄ'jQFqq< 3 ^sg_󯼛*9,euqdxx%'Yo](G CU,ۿ <j-q{rye&j i4&;l9aM<3 Mi8֐k4kYha0fd0mo]HB 3 fZh-AM29w{Sh=mqdjĿkG:,[-B;@cϵ Kz3x7$x ׄۍ+ˉz1&pfog sPC fsW"^ñ2ȝzS׆V?z3zu8US_8]7C8% '%_ɡ=T$~QZ?Z|~>rcr;m{w|&swX>wlwgec䮝#s_>ws_(a}Yh>w:8w͓NǏp 8|d.nK.n|m``;||ks7۪; er=F̺a~#=]5lMmCKej4TL)4lCY2 \*p7{w2-C-E2Bǁ`K]rܱdz/ȋ;g2cW^5y&1_}J@^qخ~A6Kl._2]Qjγ4kkse{W(}ǺnŶ:mW׊wd9O ^M{zߞn/ SYfG}uUS\^쯞_L6s>{GK?"b 6iF/{)p*ܭE9 !;VDC3<_!ٝ+ _4 _9pR徳-D988y3Zsϲ(/C=&+P?qz zͫAc#Q#ʵW:\zߙ 45WA0J,BO28{`W*U 0b 4^q99c G2cVt|Nn[d}܆=}h%W$.܄=!( rׇ=_x>{S=LxƧ)C x[k)# q>$ozY'bǞlF\gWCiF#'Nqno+j\20ɞհF)ӖC!˕kl+i\I[B/_ ޑK2`O,a󑊬azayk}~>r&ٯx_3pR(/i#]?ЊɠUZycޛ3I!y>Q+d|/$~o{-CV3%!x\+IxYK?lrOv=Ejh\Bw; ^}0NRs^OwF9_5U"l6eGA#oؖ~|VgVt+lP}]8t-tZ`YO[N(:CTJK; mB%>mALo477fZ6wlIyfz :Ų=Ęެcߌk؟OgpS ܮ/ m"y6h&8M{y3Whu>;izf2Bw@^}?V>s~ϋ~9qY@63>cge#@/|(|>}&rZsu_RnS"7i3`Ѓ9zA#V? @e|=ǃ6 yUlJEm?)?Cxƿ?ż\*yWM=~p[=S~?{3͗wK͹W!@y]Q%8_?[ez#nwxу gpYgu]xW6w|d%;-7VK!pKL+zMf-Ӫ o2`i\\(_i\~jBYnO[gZ~|up'L{33#mv0zl-޳ϚDiW{.a ~nstKt}ꔷx8[ӻ?W2Y6>WmЎ>ќ<ʚ~/ 3r_/ mfߎT~9DUr_i_oþZB~kuN#>9O䴳OiiDl 1ςn(]fşsAnMtmOPn 3jJe]t7|6v,5vD7g`~%پwhlv9ۧ5d_0߹s~/4XOCߧ4v%6ԘOTko2ݬp>(mf?|pW6 ׻.]?o'?1i2N}ξm/ʾPg` n:7ˠϻi~b՘S}@O@Zem-Fj܇8$ޒ\EEtv2c{3کG?)DۉØ՞n nɫ992$#\8 OO\< F]E!ui<_v>vgP?Zj }'ۗ4^쫭YXgC̓ڈ6|>F<ݽ|F= / {nry{xpOÈwK'bO {5{]*5:hYW~O9 ;$hc'wI۰OXgNpKmL=BQ0?1ߩ\X䉱`^ ѣɅpL\[?pQ_wGE+Y|W Gm*֔{ b!!̧oG46?9V4hoo0vSL;'ih6r$O.?}v4[mc4aܵŕ/nf{;VXLfJOu> G|.GJ+e92 ,G*AOw){Jk<m96[)pOͻX{|\5m=|:!Z(3|"Yǚfql!Z?pN 5 [ Hv?s[A+i;{Ft5@u[& =8=V%*$[fm);>qD3=t=kXen|8h顾e{W8=VK9HDWQ^1L~!Gehq{D΃D["4B'7n+G%K<6/d):vֻ7W="SRz?kC:m!/k%Fn$# ?p/5VӸVR)pUh5_=W[lLF"GJ`NRIr{0^={;=4>6!F&ٰDc8!?TG.|s$V䋹J#*3PqY"[eD{" ɯ i;n!bZYisX7-?9.㌯Hj#[;h>}Fr:s|A&9 kw1}_p^xR ҡs{oMdy: 7g W*M3pw:,"l"ZVz~-Į~c>gGE9{[`wGp_<^=+վm݌'q\C7|pmZZ[Cg2&^}sGW5we|7|>"ܾחlg(f]mќ/j}:L:?yƏQ(sh_ۂ ~ْnu d,sS?2j]ZdIu4@hdׄ{<_Mq.k^,+=&|Jc=$*_)Mh̙Ӡ . "'6hq-_i~v47C#O2뭲j,`0&~\zǂx I9O"~h s|3"#gX|]ߠ~~>7y|B MU_czUA*˟q юm|лKfp^6 ](aCΈ>.O:?*g!aUk5ވgd ށ{@k{[C?6]>Z`-mm%]A/IЍa i.G~ٷ8"\k35E,`rWwѷY\w}Fl_X{/, -g4Rk}Ⱦpf|ZF}jhoOh_Vt:a> ~Bnxg|_6Vǯb񕥮L|vΫuB=3uJmN;cM̾Ey2l +͸-gh[~fd pgP`4[3BNo`4; v+{ oT;m{r$+ˑ?76_>$ˑA]o#o%49$N*{|l{<͋-E~ƚ`76_|w(-lUy { 27E~i\?߽]\W63;1h/0=Sh}[n_F[c osALrnj_ 4C+# fxJ 0zsr({ /_nٷ96_Z|_7MtE&+{9מgIFkmXp{E?ngp8?0Q;}9H^ ٣66a=6uY=eXz0!huD{qoR]vMϟ9 `?9/΀D׉,߬NGau|ܰ9 /v{N&Ίx3# ]>_(Xxg|z s}a[ ðóZY`hY1G8N B@k- 'sօԇ"iwKl3Bgnz߮ۻ1#|zu~[r~.thEG %kJNEJ ꙎpfӵoW/1=f֝.}\WN=ڻ8ې)ɮ1su|/Ue&܋> +wAXko32e}l>mh%,0EZХ7sV7UN@&GEbMO-#qLO:s&Y_mm9BqV޷BzNW=<퇘sf ZV)Y}5\c.|,A%t`xE N{e׃! ~[}ZeHJ  @ۙ0Yo/b=<y c˂$Ic/]=Ɉ93}RxgK¢i6G/J~N0~?o ;@x yOuPܓHO9Lt}H8b+t?Mꏞw5h>[˃X7{e )Ѿ-ΑyB⿌"t>x(_?~ޡ|,4 y{U~>etϗb~3g+NN!^7 :s[zEҘpsEU(v %jo+Mu  ;ˌWY2BE"%s!U濆#|Ma]!M;Fv/&-}Ofxi|",g \95]t7./_1fY+.~kfFTF "Tӿ{|@5_&آ, IX?WdBv3_pi 70fFx}3MSlQǹ3F3.q8{Qm6q,Ӵccr7q郋.?-ST\}Ϛ|vӬqhΔqi_Ag͸W'Y|Kq\T!w>O"}: pˋָ\ߌa2.mk #vl\.7RK{z3-g>*xV'q곆Pkf\>qٶhX?-ʸ?m,gƥN;q郋8^ .qtek\ehKG)s4=ȌKz[Wc̸rrsk;ʌK\啣R).^a{l>̧TSn`}ʵdr4٧vzvOٝkS~aSFHpEFg+xŧ<3穝OuX$drvu!|$?,h)G>]2S &rst٧Oe򣠧=GK}}E+2:OٻhO-2TSV>W}ǒ?)7;ٻ>̧{SVޭS{- G)r,\e  3_`>eęY=;@~)럊q+럥>?//O>qW/3^cK{S/.L^?螾lk5ɢy3`S?[Q FN.u{rd GF92ˑ Y,쩟Y*> w'*{<ڝ_ໄlk[rV= |lF(9OJ`sa |)y)1[yoǾϗ3ܿ})m_UZ>ùώrY}h߮#b$_b5a&/賜٢R[^CN8 e=Xj`.kHϢ}/ODk%͙ 6g*PwxZ;|6}]nod=\_oKAc>XH*9X=~ Ћ'@倫r!wY9vM*WiOU?`O*kϲx p-u%cq~}/sqwr,?&qw,ipOǤcr^PY7?n/I}A5ZL?A5C|Q&JG2aGeije} $5+%W*3uɊ,O|•BOB+!Dbj3+!η60H̾Ցk8_<ȸأOqW"Կ1_|>Mo^ |1",hjqE^ȱE/|dSDr:eY<2.6t%ME#r\5A|Sx 9r~e-iD?SVO[?$EKwjq\YE]ҏh3Y{N v4}b mܧsL\\$ k$̹"҇٤QD,؃'gQGc^OlWpfEPj{hNv*n>(̙4XK,a橘ru1|xb,FGBlw[]yʣ?=}:Bз0|ll/}:.th8,x}?(72'iPfc=Ɯ}z?{(]=΂=`:=bXgm=/X{H7pIJb#lԟFg3_r|~ߡːq:?{8L݂4E=J#@fzd\92/ނ18ȸ{G; L`AcWzq lWKj ݛ8'ʸB;R\v ^=wu SN}9ZUQ[cڀ7uVyy{oy{ =ObR= wiώ.-\86~܅vný0Z1%P3Mp_a?p, 1oW܅$WؽV2 #;zpgt'ȕrUh[-emKӈH-Ma-V82t)DQotޣ̥'+qzk}~hE=#Ht0G*ʯ=(xϴ.G< kݭ;\Kyfb=ȑG:z!!uec#iY@6t΀G}P-8x,  &l l5jgز9~3GZn̯j+_-$%l$3;K>cAITCrC3E:KF2i,Ԑ5}g_~ͰK 7}jؓ: ?82=QPGqac)C:bhKL:np%na/ Éy\}yi:v'{t=BQo1ld~sd7}ׯ#][ @=]xuE23%rAWYwL#3S{o;k";Mu%CFn\{Ӟ= 2田pY,m9QXCgM"׻ۛb)L2:7~DKydчG\.6R^F<??CsWcnI,3Ut)!јg7 1؛hCdF;g?_i꽑ٽ\9Qɞo 04oqubu;΍8Os%Δa9g2~/Ns7WйmDYVׂ5`|nϳQſIsʽ3]+2D>d ;Crw5)/%2haiZ:Qqp~)i4ˏ-l`򋩜_J5w2~/>3xעeyFI4_:݈1U <#=O *olxm9oftfwPk5'VO-?]c^+uD.mcfOxWyNFa{c>ZaNpO]^'pk!3Mq:OUkOr~?T=4}{ tn_oMf:_o( l-y2Af:_oP?oۼοBWlz0/N'99t\8HDWQ!-|>ߵ6af;T滷^Wh!2eQ|Ww |7R׉W7sYnw? vv ^n^5]f .]G绡Ӻw]ߡ4]&6>6KܧB{Jus mO`."O6tzT6ſm'S r7eӽ={V)FWtW4š3=zx >sM7EnlWǪ6.);rz\]p0Fb=Bȩ(5{h?T*Ö!-qUlkCOqvcLG#pG1lӆ~3ׯ:~T8]9ⶅKjr$3}B?"PRX*C{ߙS-DR#;*j9{kn^WL}9̿:w(Ƹ-`ZNS2J*3ezM܂?9Bw~@\ neg}zm2m i6Yx~Oy+ W?/S~|;\=/K]>⼽绛_o&ZRTAEٶp zϽ}r-V#̟fC롛owEyeG^''NN't3g?#?uĜ:W $ڕa_ 0'x Yr;ͩL"G+\ȷk:ȩMqC<7݄=ZY;+t\I2_u;cDŽ>mtJDw{ynmӰCWFM Ab1`G$u$?J1W;x^-Q'E1(Vy0x؂@Bdo9{h?Kf܈Oyv/o{;tqV5_C`-IOf5K;Ѩ9'ryaPs3fgZ|/KH17{#aqqGis6xYE6{^[:Q>~ל>L5? v՜e{rwsJ9豢s޼_xS9*c97p%֜wWYWsUt?Ba;B_B^sn~\f5QGd\2kW ozaydyXp%sm`~l1lg ;zOۇBȧ/49Ϡ-x:Şki=U69qyTx W}K3E Q?9 w‡4|UٞŞX]ҞzÞ|>u?u }{\UU<J'-md҂=ZX\ k ' F' LJKJJK LJKR'--tK'--( ^bSkz0qԜc< MLۢ/ߗ"^f zcubմbʝegDc>Cy~j1GD (?F`3[SxV4j<Ō5]t&o]όMV W)*Z\]}|O4H-4`v13vUBU:}#ǎy*b: d_tWwm)vR0| gRU{F2gX_GCط3Ti/?s TMn)(hd{) OevT< { ZL~ݔSm~"ɣžS:6beϭo1f~xjYW>cVo1[ir~CoZz; jY6ZނE-ڇ{/ehƌӽ]gX{2V=*1giO,;kTlc543xv_mɨo41Ny!%*]O׉Wf?.t/$kmg1ɋ<#=ǫi;B}>u3Kst_#VE NG9r'٘Buwr?[g+;dp,/2pIo]~eϣqlΫ %"NeHY;;\0A ,?`.# <_e2B+uо#1]p2G/\# ƶ#3ʂyƗ\.̘9bdd`汣}*$1~X/-Bz gPBUEGyR =pyR~d|Γ"8OYEY51Ϫ苄ZM#ĸr?Vz6Nb*P\n8eLF*35}L&eO'ɛwldrgIG/\&.,29$LNw2'2m,#]&e29DGerd]&ǘtϷ $2O=O}&=LN(6>dP.~:L$a+leq.G \&WtLZhWrbnbnYo?NTl6l7#\ۍBkwfSWf;؍l;=[Ә͖PCgh;.|oT+:OclX(Hd~Bw0 xvt?B7鉞O2~)t~hm}Ľ# т1x2ߔ4;V B?|V|V^O\}62ׅ4^V1ب_wS1e靟O9|b%2XGb76(}@ d~ţ~'\7'v<A'I(Y>qx-?zvFKmN77إȶO\}aYJ>18qR|MmZwB>ygo#ƿ t|!y 08|'ޗֹ6 Xݸf] wzX?;y矉Lp.vMG`쳩}*U_{}9KiyzN˯eZ>\N6o~PD7'[*[ãd?(}i]܈vhΥ=iyJWLIcMQ%+syNa,5h9ptZUb'ϩZv_v̮uI(:j!VY.bk(=?~N=c!ݱFw Z=Eg!̧Ku:Rb̹35',?CcC^ɫg,߲.Mh&b>.M .?q&Ӟlk0Y l_3@[3hwM(@GX7Y'9}wSbuUre"\Zy^׍R5+)1!ط>ltٗm6;.)cKg$E8&3#{&_ytHr-On݄+]u&\5 ]w6nՠòo>}]w6amẼ^+VpQ#wT.&\A0;+uyEy$UmLw ,;|o;AޭDOị6Bd g7AShz3̚HR6-PƯ쟓8Sf8DG2ONO*Sv4 (M95@ )/vqs2Y~oNFW+tӄ+ 7 W/?ڲ?qTFOs:v=OiLvv:x&3 pm?Wj9:C:vkiwȥn:] 䏃tmi p]:]?'P?vF~`)\ A=q<m"ƶ07?J߃'qqVΕph[`K[6;S=)G L P+Z{O;M?x#~,tBYN#u,$daK]Lggq^czon!`S_WVkpo}JJ:{=۲/}ov| .dW)+cudgY7bƟ:-V&ux/6`k&?G6wPH׌Xe l_`K\ gCCQ'eN~/4wz3OT_4ޯ:L%Q8 _XfmygsYtvuև<%?[e\>++W3uu6sfqkC aRr64DeJ&cﴑ|; \⳼c ( o1ʻc})}E}Bk_xQ __pVW+ؔ.듔rb|I+v+w o(tew5b:w!O+7Γqo16unB]Wn̒ue=\{M4Fוu>)?+&2ohd]1^W6޽'vy2Gپ}:>-ޞ8Tx<`̳ud3Jg?ZOnbt<|/e^I5"Xys i#>N|\gsrW->-J|3/67tϛ[Bڦ#y*ܥ7犡m+"ퟷV u֥?OA^7#8{ޯ[@/f.ooyUC긼U 4u}C|ϖI:>d|n+%FUχme:Y9ב"O=oFU6qOYޡ~by {:O/Ovp|^W-Oc?=>.&[\a+'ks֯aw- ;0|E\"9Y/O['7 ϭ; e'?U ;.3|CtM}C/k"]kIl;$\<_wJwB/la+m|9McCL2tqXӁ&/ca}W[cMr{Qު?`ca,?ձIXf}ǎ'kk({X?$}+\|ڜwZ8[q[5ؿؿղkOTfqF_٫ u>+:( 뷑W uo|A[=_PWl"'l/#uP׿P! :EO BR  m$8c3űp1%f!}S."pQcYzeˇ:n_(tmE»ve9sY ~]712x6?z86JXo,7鐃t(u7Cu(7bl+Ey.uxi_ww.-E!}eb%(mA8B9#<%#g1%~!mu!1uXz4ܮ +XBo|:1ֳ~1d^x.j_m=_޵zF-f3|ACy0{Mqf_\{EU_8&۪(_zl?:m!1fwxl Gweu|*O`{|'N>O8>,N.& kt|Vn{M9>Y@i𙽓|E>_cAךd|s|-"fE&8q >gp|noK-q `zf<0V!Fd?њutO_s+t^ݜp+)`= tx~G&Ƣنwp*ta:nyh++>ۂ>U.,+J7!%0;_y>>^}2SZe,ZO81X|-xh ^YNpoh`kq7t]ucp+d< oo#~0A&9YC(kBeN^{Zƫ^]^{.Rk'[/޵⋅[oꑐONϿV.Wx6l"/2NzD/s0= UxGkF3mΣԿ׊<`ֿXUyaSZ N`Onr+M-늾M[fK{CqevtޓѺ{J答 뼲2{69\kI]_ ۀͿ./{)l}3/? 8/ mrO'ـȳiE\^2Ϋgo.%Ƽ-ɑy[6X4ILOފNkNTpݯ4f{¼=2*,{xf񺬖ʵƗ+-&xkʻ>MRfBw5. b\sd vjv?o!36_%J.!U5+Ԯ 4@c;;&m/x"|[1 nϊ\pџsrᇋrSYοRo7gtSӲ\Se2-{"6^PlυGm= \b~.?G*-uZ>Ym-rvL^sTNE[eZ~&2N Z;i釋LUZ贜ݿsi:- gh_É1f?cxNBrfEZn 5j2EK:;ғJ"-mϏ?lzsFs#3b'6f4$f K~l3z|41f="kNߣWg6QB>/3|WΫOol3Y.m`j]үQnҙxG v)=օυ|]/al3(TwKA݀%S/ɧDΧ*QP> Kk%<2A # _jR_oazW.߇w. /- ';H>ZrM39SS̻BkfstVsLk3É%wM8m ?L{jB)LWQyLX߲|#i}{t oC{(ߞqºbT_dzr&|̆'nO=EdYDzqrV`dq||$|{ڇ3~6uB%j MxlG[Axr%~N8u 1U&\b'.BRnUG\й¹DLb<_sRc|H1K㦺}bA`[\L[)\Wb` ?t0 cOTr1_a}$P??lLbZe{Z>2/]eׅĘf3/r/4c:-e+2tZ"-7 g;#2!-`O˿ix/]F#oNgЍB:-Mzi釋PXT-UhKӲN2-CZxN˹2-?_ߦ҄K{#\Ti`sڢOEKˉ|vN\,"]:-V΂Z!&\7"qצ.ҲV}^rNܤΥef=-:Xc1H|sDbirυCuZpFPw;X.}svh59:'x@qn+~B\ckL9 5-r\㳩r\㳉r\x5&kKiX7d~H%17sٯQv\c\91q1k)5uXKPJ=t%15['qr\#)O7~aט03ڣ&x\m9>R!15L q[5,5LB\(t~MoP~[qUr\^cw0;%al]tDq HؽIkp\Fn\k>k8ڎk5j\~ۚ}\㞾ܷq6:{W GʝrG9+0nqHT$Ӳ\S?&\߱:-pe;uS;;Թ=-'oiyV_;2@Y~s&\Wm:-p/ orCj.w7֞gO;?I1>dgc \cpK'E)JBAg.BBjo/MYγ16<~(%{ߣ@EKb#[7?F'(_"*&ҒG_l*ov$ۍw/io19#vɴPSc!efA˽ w\D\-rOjef\-iڡi~N1Wq3jՖsiWqX kW<:ta#q7H A႟9HgWexpPGof1E+K3nDk}ڐ¬pkmh_ŵڒ}'-i~>^$|X[^;5̯ fkm> gw=@`mֆ=.dcSp7*oof|D/dUG!w?Mtj1l":.˃W3nZ9R ̽WE W 8l) ]#Ƒ{lN,熔(_طX \uf<)=ӥN}J y}h_~`GSoxw4MAI_~B2(>B$9Čcwb縮Ql]p&ߤ=@4eĹb⯠-1qz΀aU,Ni<|'bK]~Ne)Ev1+O=;7Pe,XlvL8/i*6q>| mls[Ϭ~{zQpm=;PyMyw[ލbhobvc"WeޫYNgİ2')?G|#4 w͟B 9?~B60׹w1[쌝oIiWWNat|?-?HSw_k]1i#vRElMĸ.dܞrab3?E(O _;H&wc\Ħw\\/o."Ĉ»Al@ "0bgТ\\F?{r<.L`˅ Wi\\ ǩ"<~M:W.  v u<Sږ "P b`\$gr1TхfF]8SqMK!p"\BvrQDQL.vf #=tG݇1t.w*wBoA.>BaĎɅwc&E~0C. /ǎ„+,}0'Rhv9K7|W'l7˴LlF*_3r-ֆ=T,^M-NbOKMW*wMW5]QޟO6_Jt!ދ_.2eZ_LJ, _cuW#k5BƴNFOQ6_+gAhb`O _6_sO\% !lrufN+1 ĸ&7^y&ޭ BvF~uyMQ/^1ߦOFWfD7_Kc'|D|X@[<$#Xa Bb!ms^bܯ{*jӣ;=}G{2Qؓ;zT=cgg.̳uƭy'yfx7 i9U``E` &4Lsݢ:^_rRf8/#̿f꨾huʩ~&y|w8w~?ׁ:~csۀ [ "p߹Iw&8n)1~Y.G;'wپ[:Squ_f?kT{{qU':xv]dϏ?F[1@ZM̏08\S`e([rW 9vF}9?^ksآ:AբFWWboVU7+KlG]S kQMHK]׵ wV*Z5[ٙTn }A*'1 !Λ,syPMM=|, pA!9 f~G[~~4>Exߙ(o>7/W. D! v`G;U￲`?}~vx y/":a"`Nok^V=RS);Vx^{k6rc _G  =x|i&[?.3-0c<~.Sr\;u){XgY(ۍ4nep]XYkMGeSfT˿yʞ\6oJNhwbv_ZDy;{I;o07 W̑y7J.ĿoYnYdeJ ϐ6O$% Ǝju3VAWn3kuKkuc% Cf aK/c5]昱~d3qtͶ<[MZ q< Pz)NqE.m b\nSꇋw(h1O$hЭf c#:֑b3<^#Y6 @ kG0%39=0o:Z7_c|Katb =?T}ƌAK*۩Gu)s%`}Y`ހo', ~AP;}kC;Ym9Ol/]Z&SLIDKOgGY'=qSzau~D` `N*ԏl} r,]~9~!Rh!b|.q޶C(krsѭnDs鹸ԒIW# d;m: e3*ό}՚uQ!UXK>4_[uF,4q_/ ?(2&Z4Q#@;,zw `{Y{><`.KW{k\9a ƿ.4`:X!_ l$koX!rX7.ɲZl=g6`c\[9q6¸\J_Әs᣽?6c`MT~f_3f> 7Ɣ{اgE^k}fݙY{Q8`Fj@LhG :`ɩjon޻N曝m=U?oy[pl5'} [M})ڔgcgcL1) zD)#|Mٰgx[ϔ.j٩#լ˧G-Ϧtgg iU^ߖÿ2x\ޜmmNQ8Hw[zx[[(w6k7Uo&1<~z> ETQ Ft M"F|a2Y2Vgt(wW[Bbp )qR$ F+^`bb9G18(|d?_Q "D`J=!D|f.v1vnS߁$?n;w oS_@bP'YUs d=[G Mg/h!ubg&\gN6_pkOa2 y~'IE9m#g= 9 둿˳e$ o6c)$(Z-nSwLw)no]a{9_&nKOefWGЄ; pq`].erSф=T~;Ѿ#ؿרBްunlמ?b^s̏Tw:L;J@Gs̏E:W9#GMw;Drn !y?Kq];@:gp?Fg#_1%l> [z?sOao=q10EosfѽC{~JL=Qx#F/>"҃~cd>[>m}Կލ97Dʺ"xIfY&O*@_v_n/ߎ;hy/QfqtD xLqcx1j+rwMzuǙ:}}*q0gp9;L_N|CrA1\OZ{ _8 % /B^erή܏6s}3㺑΃C יwűi|e @y{#{Eܑf|>#,iɢ=ߣyF]9v39(\AurE?6s2Yp_SW8Oh)3F?W/on|=u!DuH>5IǵkkJː76cYOo>3IME[N}gx߶U:Ql?z*fkIGwGG7;Ƴ#+ym7Oy+&ktچyv:L|w|H[#yv$b^ӺWγtN߭T.֙3r˄uu#^ۈ#$UN2?+%{ˤ{+oq'k?7 .saۦ?en0qq:~,G|M F|_(6g *0(IOC}<>W ϋ9-̤R]<"a'*6W27138jẏv}&P? .4zi5V;#H8!} V.}?:TVk1D[i[eZ9;VssSՔIG"q`d ۴SfMACa!~3} !v plco[T߹^qS2*Gf,}'qtYIdOҹfq/ieדڧB'?]z}?=q OhG_F=Y@nlɣi 9W33 lAD;8S,7vg:x`Sޢt2m]h;d[8ml mmV!V*'ٖhwߡ-^ge,g}Z㶰 - ?!-,wi6ˁ +~mz+n9e6 ʴYBR/vz6q!};l4Yüs]V=Dxw{1ژefÓb"7s\F!]#Md{wk<#Tkm-9Col0nklm߃??#n`ۍS>Yrng=(@pYޫ&\aCn *\ԉ pGɲ{!wgw]<_&˴|p6q^2-g4 pEZN4( <{ص#wqhǭ/ȴ8~X{]fчHŏϊr~G/RCJkoT?Փ|jj=78 #%7!igۄRU+UE'NOVpf/̔sbX=KW?{i6L^DKmEXJRۈP4 3~f.?u!)5f{X38AW aR1ܞ/]0Si_Lę 3˾sn4NpEj͟5sIoB_'d;h]4ul6VwM73Zo ^Z;lWԏ?8qkUc~9h;;q{ޑ4". `z}n3я7}yǭ?ͼQB87 }axobO8$3/ o[V@tUWj!lY;뙞>N}?į a}Tct+66;<|㉣ nZz0\}Ł+3ITst|G`U_!eW1q]eB^,ƚ^Y8~toP6~qܰ5a<=n.GשK90 k=1n$qoܷUy5S[D?I{CA{ơ҄oo'6o귯o' 1sC4|yO=wΔ<8Xwo]Uy8FfO&2xB>OI/< G$Ȗ6Щ,Dx{̾u&|7|ߒFϹo6OQȕٯ9a W '6~:NNV/ko2Ik)^fmkzvQbnC|~6})M#`4^?qEXf-9$&;f.07l+4g 쐐+䈥=#6R(/kŚ#q АY5m:sB=6]7?M#4t 绡fQѴ}7˶o_c,4G">? x+DHŸo&?xVmٌ,Kh fb~ DJssg{w6xC8bcБY_}e9)+f>Ň-wSleLe>5j@_̓׌|g˄O5}-Wx_ gx=Aq? шw q`o40_F_gʼnob2(Mw7{BQ~r~h[Iw ڇ5j ﰺ_+_G;L=ܦy]n8L}f/MسkXnTwwGbOnN~\]?I2MP]!1 ;]x^xw'*֬zfRny8Pj3?uTmܶdψ4H:kSWjWFZP5A l ~zKϕj[Ma_&,`y9 z%Jߎ|{?ej-R#GYV?/lfqҪLk9󞿦4Pχ ؞o3{|k ŝ9kڡ%k|Ε:x]ۈx4 Ot:j`0<[Ve?_A0AS_75G6;|oBuNjС{7"\y+&cc!+&鑕Ȱ5 X?jo?OR̻w"[ ?5mۿzz'A}m eO )AYN3>Xg>ߦu> N?@孊]]KAADoYT``].X]丸s?x_W@% w0:gFkg@C`Q_ `Ad}젵Ld{}`=W`+Je}P#ƛWǛOEY| fGdN|i?&\!ޜ8N !h7*pyM$7>xFeqG'P_:>8s[kֿyĞ?ܥ筝2nƦc_O첩}k̟UĽڦc.Q,m-!* 1cS}%|Gq,yk'1SzlU1H<;3p3JqĽ " &[b$ߦܭߩLbh,%gY/Jp뽃z:ʜ:'XLÔ-Y˝YltP5PC|q)̝ٸLyA|;S-K=]s<J%rw Qu8b4)gӟ*1).ufN5Ӄ`WJXṙa㉻Rü $״tl`_O2[F7 6uii_Ú=fw}"n}.⾫7._ws%ζ(&ߴBe#NoOllO*ta#3jKk?Y(:O?27 E= "b#7!"$#w*FO/dA Bϔ )2 ?u3Ńpb^n=Ep33?x%)=)L -l>Uzm?q-k阿Vq̞t~_qMu%2?N ]:?L?:C?\ A??]xi#GPq\C}x4;V,}>>;]lܴ+4[+ǿDžGV[S,G jPs C]t +Gc9]1NZ9v>.Կ}NaKCX\׉kiM5ʹOjݗVXGiU<֒#X{B2kubWPG8i.|ǽWbz}y5HifF+ l~tV r?WtG9 Ygfw >5[cK1m=/ _==0knwx-}8Ju)wxC\[wؽ&޶{k7%fϒ ܳws^+/O荹go{U荹g[ֱxȋ+;6j2EW|um`]oY) o u/5- .wnPD1Z.qrm ҲӲ{AZ8s+b3*w?]~%>_&_ha{Ia[ݟWGn._p/J %}j馻ĺԱ-lyQ,--,lMjj$*;9g<~?(s̙33gΜZmns+pWkO9l_Y8P\&Ԏy<"7w|V<Җd3Z#Sm|T8?$V' {ޑԩ}Ԣ`\su2`_"7GS E k@ k>=M &Ds2z_7"!o\ _$?AkNÈש{/S52^^G<4?x^?#Zg&+x-. WE?ٓ~j2^MZh#^MZckJ H`?Wx &rk]Ep={YlI uB~ha<9}|~h#_\fy4vѿ=c"ؖ$OkK4iYcw=}Fku;7o #/F>pf_f4Ksv5C;Yf%617#\هwfp;F`w6 [)boe1gvC&mv >ɿ.>j mvADfe}f%6;j!s)\d6`qͿlٿ6gz_rTfnfdmixTd/ qaf-UfkfϞxi=^P/I"͖kuG6;Ov.j  m~{;lU%6.}kvfza & ̙082}6va E6`ϯ6[+luZl:vfkceoپVlvzxlaC]VV_⽆*m `V'N[6j5~OLɆa? ?I ?{ivz9^F;}y s@_bcm%^B"J@N_^E;vDcp~%-ǭ-b?svwh]0OxԐ 2㵟F]w ^T9 ;#W F= n qgv_?MF;yFvKbWzw?j)?%vDMg&M+ ڴ$Y?M:?%vXM{ yZشnB.di&"maѦ=!5lfe mg2 i|Ŭ>ࢭtmSb}>SF_vݦ9|L66 ϯm6Vi=F+4ulѦJ6M;f~yMhk:s&fW߄^6u .}FބvQa1`Fz׼s[]ۅ!U=Eژ%<9# eoD}%6u<=AZ`\gN *W}e[Oݕ)+֪u|qټff 575on]Ytf Maz@YKx\Ks>>rh<:N`n܌7ml%p;CV!\朮ϳu8M;֠ IE8Cͳ &!6!t^d, Zg .@f^[ON|7'~}XOd9{-?ߺ,ƹ`n"ݍp#vF Ϸ CzqG8Paܳb&5n]1ٿAڳ)>Q߳Z#Հw=`S} *xUOhU ]NWpNyw'xe6$pV:9mj?;Oy?1~SP5K ,|*ޔjnsǁnptHhJ cD~h4yZah Z|g|`f;#J- ;2[w e3z:ČlCqgKN'5vMOlkO-xv>/|G3h^Wjx OV}h3lLT; l+,> hs'l~f~q~86uȖ>neM\$oy RsPFeNa,՞5VpV߅74NAz@V<.Ƃ*߅7lə1F<"Όu\5̸;m[.cWD_BsOn_K(vM H1UFʿJ |N$OێyaD@)CE{ Do[+?>?Hy˒v6O)cD!zX@C AStty4=x޶;U?DosvۢTv]gO]#tȀ:KM/001͝W1\ۜKiVury ?5Mjw71K:rb*k+m~- v3dž6Ecgd2v-ıMdx;=XUɂIFhS>&==OX&Z ~x`6dO:L4II$IWq6RFGUL]\G77Ryaw|h֑9"sIcWH%ygQwMc*ٺ^kE{6|6%X9'+a!mϳgP_OB3iL.ګ3{ d2ҿ<) .u"⟮ eRdh֐"IE0$}WSɿ6(]4O@(]R?ګ5Dgs>@zTMl;tG/ؕĶkcybDN'];.cѶcu>uJ%IB۞g_iu؃ċo'}O=1j-I4? ??^^~8?isxO0[۶o )PWb'Fܩm7_/Wc+& ]0OhRGmt]smO&p#uO8׎yH3|25h+L8Ѷ ^I=--QmfcR!>lLԶ ^ANoۗgv@CztO4Z?]?DgvZ?γZ r r_ Gʿzo|wm"䬁J-@17_=÷q|w!o >K,Sg%;7g)x&J=84s+2/v|_)}'x̫g6X[/N"Y—c۬-en6kc3}0C6kc{t1V8u}GŸ^_W75zNp/6/hר{4Ϝn&Ko^'_}Em,=fuw/L`ɒIC3G\}Cuī1^FcOˆ؈(/v>;2|z={'q98c+co0D8hrx^딺"Ԧ|Rys9O)7iFޔOܶsk8f8< }ƿ7Zs$6UZ-z:yڞ ,}oKAֶW1ga;ɋNy&cR+K햏]8 Tg.jPsG! ډ:.(SEGdơ"];nI^ .?Mz\s tYt œwk[".+ќ:|獃{Ζed&+ɝCxg[\؎y'c$ŅH;m)"__s%}z1s&z<.D2yc7ym$4 #L6l#R Ǽqz!0O})lt=:m^.sw3ڼx {Py[H_]ؼU1L3wCt'g=Ո~wl7?q׈KϲCLA]:ikYf؅;-mUrW_#S1(ތ  6㟒,OkL-?^AX/&+royRcҾp!x'F|IlkpΉ4s1ԋ<~!9|A*en?RY`ۼ{W[1Ю?&-f+U;a~挧oK$gbv|\*Q,l Y܎yH m:ˑ'hr m+$1-Q[mEyvC ;Sx\xEClSE}&OcѧUna|,y$_|D 'q_|D-ؗܭGjCNF:y21{GH6ȶW@&o #Yɲ,dydsO^IK y * )0|~/3'b߶L߃$.r.ȳI4megXs-af#usܒ9 c .˺)gٸT`bbI̾D1Y?cpK;A1w e%Rm ? o7y-&Wz3ܺMs'v_]5=F- s_&!yqrrq\o\[jזOOk .9Wr "ԿHX|Zͽϯ\bBY.Fi'9olq9FڽHS{ /b_۔8?5ݓ"fqm'3fHz@>4,*\.x;3Eg>vES* 9rqs.2MǍlsƌ5]F羚qbB.|\k-1M.t,s;%]8Կe .]n\\! Ʌ2b \ O3:,KpN7˅ E};s8a \gwvP8S eW.n"qY./3nQXEo{D.lNɼb"k _tpIp[8s Kp6wY.\Z~ksxY.}I^9/IzƀlGZFZιfZe3됙ys|3-U@`?pi郋#rSeI:1ؚcGih#-f0_i9zWR*\.n$i.r&XL7]/-7[z3-i?syL6n4r(+~9՛iɤm$6hgЊKK>%Ӌw并'1I-סd1$xc.Me>(@28ؘټ{S>T*WQ;q:]ыQ(m t9t/|w(}w6Kοc\U=֌|q+co{$è͜ׯ g]a[ Ĵ=$ )' ' @? sS&޿[O혇Ŀ^]ڽ I sSwVx7 >yH%!*XUWN>RߓLj^~F>2_wmz4[spY:h9dc W׸bd}CX9V>׹IOl=n+7n8b-WOѱZOvS,r}}b#)"/| ^@D=;ڠ)U:"wqv"jhy,s2 bRpcW1Ru܁݃x͟ha[5:c` _\:+Y-j{V#yvxP^X.orq~11[PWG0|#^ۛŘ^ e9~F~ ʔ{eoX}r7nܗ Ϝ=ʧXOdd>e7F Q2_?9 V}m-<ߞC-<.|Ǖ5;߇/OK/;#;cI^s1BG 2!>0h7N?V#,^7Q?Oeun?o t{Ծ4n tzC1O;Q͵Be=]%P?nC1}vlq|qq>(hN/se\ۤ2n>68j:i#+'=`,#:(Ys|\5rMGbMZw̩XHmrw;?2;z'c:vT`COxAAʅ$}.c ]e$O]B7\p~x3uqkI>#6argXpULx_P:&i-nf߲W05r']fP8޺cY.|pQ.2H[6I4kG߾/q单fZ^]aۍ?L˿L'?q[ʹT4iN8ӎ痖J5-GfiyUkW2ջ̴vH˿DZ̴Tᒘڱ7LK\_glT^{~iHebeH5\3-i89rq HCfPߛ~\\-&p綡K-W_t4lir+s^~LkÌ|Ŀi%ʩw>HG#۠tY%WKZ322HӘ"3-J&F6R%qfZ"-&7ԷAL3-#M:F+iSfZ^dA9L?i9 o1Ri~딙>H ni6m痖WlfZ^"قCP3--x֚i%~|\t>HˇH6hi_s~ig5-O4Ӳg2%̴ti IfZpl$h.A/ڠsekZ^L=|}4sjyFZN$oi %-=ʹEZlfZ^|x}AZ9afc3gAd]65tN|f}>Xx>6q>e\~o7G`[XX{I7xYvKoc?N>|/0Wi~~|>sa{;!T]UcKt\o~2o)~r{|ȰG[n]nk]}ދܸp#W!GOĜGXˌ@?ݭ[.|W*}!EiQ'yIaH"Ggf0(ƦQys ҵ苪 i5$Rld;qD^'C}G*Ӈ^_lR?̼Is&yZ[I_9GwZ)>92@NrcXrۘcŞlva@'{{P}wt`eʪJq4{|k3/e^.i, ºJxm_,&sKnuh_*\U y!}:5J߿ڦXnk>*]0'ìMd!M͹\\DZ'}JQ7RvLFɤ!76Կ<{m;ڴB]_`i]7J)3Կ6TK4Bb  DG5(oL {UN4ۙ+u'oUK] zkxs!7yп] y~6U@!ϏlLL 1ٱ"G9&xԥX OY? O5RbQnbh]1<);X:W[? [f.zK;89B*'Hgp'KOƑgO-] O:3 0'IwQ?)ӝܻGY'IwHI"S'=)!KD#Tav$y? gh\^c/32Ɗ|IZ X=]suH\;YR^ )z^_ ]690?^?tjS;Ư ┙_ ]*cI_J_1F~5 nW&3.H$R2UWpEF~WX+'B˯[tgY?`6s4뇞Ro~{5) ğPz/0o3⟿9lvrqBke֢m !W/ÿK-?#/1ݢ9h Wigğ_?gmAx"Q]zg ='o[б/kLzo`J^z"9m͏kL#9*7?Hו[-w0Ǚ]?o7Sd cYowFοW_"tyjnH+z}=Z͒$XIh^a:΀~=AsoK28#ϕ2P/xZUxm085cnz.6W 뚻)ghc.j\׭g"u:_ݫ`WSYjd J9C_ [G{tq#k&Oc_botӟ)-ο]-{D?Cb I?e/wp11$=LS,u@,j/]=kGWKE//79E/99q6zu1w/A̯F;" Q$r3~m7_43|x!F #x/ee7_~sO0kͯ{yg=E$VS-ΒCKL߄~]Ӣ9R='oH7XO+?/1뻓C뙙ŔtjI۞qz%[n/ I ?To"ku; C}#/_?w?KI_,?/8u -y:X$3@-?XDG3O:2l?~ӫRl?}MFL7ۏFqXUFGpΌ a3>F~Wʲ瘆k繞 C&syXm9<n=DzH[Se=lx=|4,]mN?#96˜p-2'b;kV=$^~'zN:c@}gNg:i2G{Qw !lOÏ,yNc1zYu{}fm{baz=1;"zB DYG}maNHonek;__cD,^ib5dW1Ǘ]w,2_#G`ǥߟGk5swes_r?̌̈?G).>ֱw?YV~?걊/%[pSjho7 ~Z7}N:pi./ 4sL$}3>kUiW]eݤp|itfJ\E*#R2/Igr BjwAo/j %1gf'5pJTox&no^W|`>' \^7:+\o_ٻ"D.p<p1zF-=MB.%#\FSpz_l&g:S4 ;(s̕wK.d)11틐5s)Glb S/J9bW/"$yGDRn࢜]׿?IK,E9%yHDDR Dd(gWD< 9nǪkXWޡU d!m?Z׷{Xa.p_"$>1K?Op 7I|GwSOM_/)mgGľjm_i?wS)b,r .'΢秙FLECRD*3۟V2A*g]F$gʧ3?g|ޗO4>c~Ձ|k?W1>vUMqm)w.p|N/tJV왝硷 %Wmmެl;*]7ty]6\Z{^;iG)~`?/16Yv>Y0~ɾMvZOvѿ'G2eF4s4qncoZ_Mb_76I[ipV<exm q}0oqb~Xj=H0_\ wr|q{e]' @E.*6KӒh2ua|ܲƦi=C?>oPn^i\}#zмW}{, O?HC-I{ cycc!jkߐ5j|wҏ{Ay]_'\,Sm-xo)3Rwa87e~?|wS)_K5G{0?حďsX mEAǴ_ں [0W0y.߿j1bUiX%:V3'x?U,]JqlǸ? pFwS}U}xDU7> yU.Wn`8ϧKD9[ sLAo Ӯanc̤'c^Se7#h!7!1)ŵ-{nx]ۙD2rj(8n_wR׾{s`syB4 mc5 xgq/WkT(嵑n1C훼l[U >|U͍Epf_f&Su| ߍ QW&ڒa9A#%x/θ=g<dP ({ { %?gl= 9M4&Okq~ڀcm@rѹۀkp6 \[ۀLܼ_;xTm@?. pD`P'RwWT2ymvTXۀ;tOoPtPg`w޿ xwد+6b6k6:}6`!6>Li[.v[tet>@ȕ#c˪ =^Lyн39qo7x#ذA8>V-$: ҧxG]kRU0c\P{~g/ST`M,m|1:t5G*Ԝ֍[KbǑ9DKu/vod;~5ˉ{]LXoޣ;${׿[d-YwqCq-1Ƽw$~05', Y}Vh|ཿ6ǍkytFzma?!ƽj 潟clVӓw!pޏo#`[@1@oA %tsh2.!_lg67mK=vF_u~X^̔,FE9MYVKk4ij8]1^ɔ?yS$EoK1ڀESNߧ#HoESN1دj $_??OjgЇ),FRo8oZdvi3C;ۈfJRoh_p/ T6`5>~ڈ>97a;iϯ L0*PϏ X^em|6 nmm2e&~yRm6`yy$.>n6`9,\`?r,?<'J6`9⫴#6`X_>ڀ$-ο Fc6x 迏O=~]h/&0DGZۀفm@yblۀLycd۲WO3ۀUFp=GۖwA``%{vsJmiZ{]y}1{ 6Fpm\ֿ 8SkGi2,sJ9wـ? lXۀsgo غ:n>S 6@Ͽd<ڂhCJ%5/i}(Ǐ]w넌;KC] 0ǖɺoϥgʫ{ tswzK2ܷIIW1x~\Vs[[ƺj0eO,1Ň{M^?r lP=o+DY,ϽLor0=U 7Q `m6݌:d^ $pg!YNy!❹(Fd@OXr8>ڙcD8?p; l@42nޝ'VwMo62\|]UW}cR7EFc|o{n0WJ2un`ʚ[__6RKoa?9ҌJ)-9{L¿E|ؚެ k0ĸ~qLyŢiM]?9wZ,t \:{7p"7G}sk=biŗ-5oήqՏ5K/\x`zLv,4{rc. vW8oY_3j8 h$Γ> 4݃9ʆ~EUދA?Ts_ZVc :-':J;H+mcB,Sgڻg'mYHs4z4ϊ/7p pcA`*k㾐4"C=x!j>ߦI=\QA9[uqJ$ e -wgZuLyX`5P?0[ ѻtu}e:!;asl$^a {+3/q !/ x}y(/79m%/o4 K7L,/5^o[Yh Ki?O; <ݯK6 0 vwv!/JK [=Ư(62/]g'yi#vURh*=V<&+,^-A">0{].RZѦ'AWa}p~+a_ _p{2xp1vBݓ0ǿwvsa 2P~v/f݌ۥ )?j-?W 2Onw|rN'EIȀZߒr,g f9~YmvPSY" v]~i4IY$(9E0k9`Y>s^sZsl^#i5F(S1Kwi~o5x y969-|iy5U-|9D#;`Vx*cq)xyȏpfqȏ3?T"2W ?Jm ϳ?,=#kA_0.V`/{< m4Ca-=4{naC_oUw 54|Eުb*yOa<<[)>ErD|o 9W\˔a?U<:T^ޞF6yeO<_˹N>ֿVU zÔY?c셫|@?t~e{Fb!bjW ~M$jfoflfm_X=_./=*館뼮1y']f {c -42dL'Ǭ ou-o2͖dA%yyl-;'v~oGߣ;x4=f~7׃B̖b/(閫dxM/h6!VpA}&to悯ڏ W}߆A}}Rb1{ ']S6˥u%S2Hw;ƢRN?/amֶ7F :Q*OwLj!pycAeuufX[A^xIx˃Y|g;3Z, /(M&r՚uB^.;/?A7>srKovyyKOkKoվs=б|OïU__ c3al 𱍧`<,ä<tan7Ny{yܬ:!0OOwHil>l>l+* yZ?Nl@^)G5^Q оU{n&/5n64657= 4Y9lꌏ{y3=<ae=hÔG3郞uNr!K}ɋDq*nd(??$D}79VؙﺺJU ;5)׶c9|[\6[r{6d$y&zWnyȿXNK)~_k;l6/fkzk/u9t-M5y+?i}2{Pطo6 ,6B~P}lWc= '; }v`cvkr*~vY|>>١fOO-F;m(cسfƖ ;B۾csﳉBd s̯Ǝ'vE@k-NlunAMGIk-&[F sK,\βZ9r%\5e#f>|f}л^83l]U7~ l>*W ¿6ǦƬr'Le u{ }H,)-i Ku\u3փÞKF}w&>lw-#l-0YMfysl݈s8OE&m)?qWP&h:;5vC3ߩ | W.KUjeR_QtΞwW([*LؒFos2}(̓6iz ϸw=N*[NW[N^4 -[^W<./#V{9{7EsG3[(8XMrifgÆG9 _:u}WaΔ&?$/^ Y04(do_Uk.ye.xpqn}޿^>g20>OPNm[i5}-niulVWaUвCwy昝eQ7Xiu=h;շk:jCzZOeFZY >HL鉶kn#m9%>GI);"9+ϛ [[蟟ݭ~v+^;UřYǂR؀wI>m2>n-0b=w;ޗٺb%au[])S/0>C]-Ǧ>㱽hwѧX>v>pe Li eJW{B6 fW֠n3G:) [6֖\5#AY%|*m[7܎ylw lgUJ&xX ݟmZ;a߂wK,%Sw5=Y؎yߧog~ $6 ͵{=cpI6놰bW C$cwϚ >z6`픧ǯ6[5FLj8|#9GįBkE*,I3MN:(_|vG~}Nו w JwVk*Kk~青m~HчN=>|Xt$xJpƫ;GE?="?F{5JĽ^gS֗9"QpHqPw q~3ǽj[,ٯ]!]u AEsCۺRlߺW7w=ߝ?"6wu`HX!bcWC?(}^ݱCBr%j|7zkZ }0;\;s[kǸv;QwGysF?Ǡn_lfZ|^o3~: y:I~Vi9 <^o{`l:$o= |-؉c[/_ Cÿɗ9z q=| 5>F}U0v4\ۜmsS4vy'w+*o^`WpW0yxg11F[w.ǩ{W홍5E|L[Wg~/gF}=s[H`=K9$zls[ӝzŒ;)LJQz"Q0:)zR2fSn+2'yq=\8}=]?;Hmai|)wsAz'\OKyyC[_σEL#݅dwqLV@EsuY&j_wԈUtoX˽.x?iZn.KCeۗ0e߲ĺ Mϝ~jq۪ ;{)c#?H4 ϽL5\ ^"lxT$|[|ȵYHY;Xe&%,3e&vQfk1LRo, Jk\1LYYfb ׊+|-e,3;xǧ2S1ij2@Ӥ\2,d&6ܟb fn=LY'ɽHZj̢sTfRi~]f,3{s;WcӰD( !3[̌iö&'f6Ϧ3%l[ZodGۺ{{v75SO˙>dN~晻W;3]G#㺮 KK y=_&"0 6(lᆅ bްĠtM7ݴAꦥN-M-X:u =׽ ??x(Os=sϹW9=cqLM5-= fu∻`T.ԿUkMFm}#=aFz̊cGZ[/l̜DreP.3wwV&f|L=KB칺`S迺{5=ה:r&r={&kkzQjݚY5q%*g9ϯkmȟRlwhr‒6_ٚ3˅ܥD/ڝ+ڱW_GLqi׾t#_ո9BW81N0'e (~ɩ?w>21󰎆2%ǾBΙwY I UwHCqN]++Xp,~eB,` 1UwV1:>Y5Uj>ARsZ-LWsr )}~XBkbr_SϠu̿2(ޕk^!IK)o%爴^,>SCk͌w6)B=;a=,Z6-^ȯfuRT>{ {HǓwi.;*Hn?|X8LB]gT.%)&0 ZE2嗾7WS!rSkVr|˓ZTze2m h*Iy3C}q]9_n%psxypzG1꺛7ǤFԮ]"!'cQR Ws&]`)ֺܱ_sYƯq8/??h4 Ae?s2:B6|!-?6 ';bP>>;C,g$:RǩE, iAqLLSEY(MsOc v_Dߋp/J7a r~*3URp1p1yici6W}{qO:iЄC&{\rw#K<Uo?amB~..3Wo_jyDkc4Фl>` n= ٠;qWrZ]9Wv޿[vkim=q3 dID_z_h9yv0sq8B7yN.ܲayF3s,cB/|_yxN.9Ȝj~wx`y.I!n3\dVBL#ݭ,Gcl<culKJ#lЮA!S<=܋Z=PsFs yiA#EY\dsk6,+s.-~LcOyZZ_WisS|+5FgnmҮwݰFKPy5Z+sx湲`-ύx.b"y=/BAKYέx ku9ϭHx~`y.!ԑF%HKͩq<#M)gBD}[{9sî0v1sqsY|)ulZJ7]ut6_ǽ8υZ+UcB()s mGlnvz K4 5{ȇs.w0> e2nWrׯuO+緻Mn^oNmF~SA#_{F$j'h"{&ԏُkkwucf#F#QOa.ح{܍޼/n/?x+OD̚C*ā:gp8\0Dc;T?H_~mK.bOcFu\eQ'~RSRG(ܡS=w8a' ~8F&!h0Gރ]u!3|c=|:j_c_>db/agZ)HC;B癤m9$\r쥣!VGI+x+F|AZx.Ѩ Zi ek٣F-FxU?7܃۠*A<˯&ZŌ*V^f=t}6}BAKrr%Ҩ5< &.~nU]ꂽfWY#ąMg#uuqgP7n+% LŌ8uw h2]l!n}3ʺOڻ,2Yw57ԭc4quܖ]G1F(74ih_d:8A LHC~z"agLﱫi k=rܤ+ls 7%u6}=U1l>k>_<ľIR\Ӈr/O◔JւN+748G9lWDkwosy,îlou(8oewVE..Gb:9- nYiXTjf0Vx x{m:ȧ,7)7c9fSJݯt8]{vR =zl!1ӳ=ʆ)S=ˆu͗/{> k:=^G F٠Me(F (] Y6e5jdãB Le}ᮅֲaBlO,\@F٠L!al^,{Ke@/"/ʆjekۍ΋\g|!x"Md(oL,i.Lif"ƖjeÔyZ 7jeJdpϲeC`Q6T] UcHqÂzlPƦ㴫Z (nK,l2(F6<,`*6ƫeä\k0>Z6Y6>8KALAe.֍4ʆβl-.BlFle5ʆ..Le#rg|!p%/4 ۯ,VSȆZ01S+ݲaUV6eCgPe.l}Ed1qŸ?$ٗe2 VܥpQ6<$=ˆøle #㴲!,yܦ8Rxld-dl߳lx58oM.?e;:pk.uV6R eC1)>ߢlŻr=ˆ^ϲ\6D6 Q1Z ^K"NQj'!Ϧr18K&?ݪm~ߗr"FnڎzB~EGޟ׮=UEbg,.[(;_Ysf`GEX/Qv O"{پ6*m~ߍXJ 2DPViN"Կ }@Kw93:=Ʊy'Yۈt.1hz"b)r#>1[?Gu}/tD7>WU>)Yoj=b,G)_L} O6,l qܠʉf-˙> gE_Ze 'YԾk8h8޷XoZxy{ |25D燛!A4,r֯`:s8n݆q|7 э|CF惸.k~5ySG\Y͂?w%#~sH{cu.~!g>]4Nup.%ǹؿ~}JZ8vqX?.F(nzʠ0ﴦ9ܕ%7b+3sO _G  -pQnݗ+Żo#Δ?!~G[>H>$}#YMaOyK}ܓߍ8P#uo3^.9cҔ:W'0e $ 0;n3>D;njo?l^dݳW2Yqfc>U r#h<' #%3.ڇ3Kwc&,u`O,=̕3{ۍ#G~3$T?=0QZcLѢ+1[m-@u5zg Mx#MoWyg#x/{$*o䮅[}=SMVADh{'q+q+&q+XJ?Y{¾ =¼Fva~QA05a~ RbظCq+aZZ-%r:oVS/CJXMu1" u15p-/Ӿw>Gka#Ph;ZE- *]A!g'In$M }P#=lO< Z+uy̦yxuakg\b[.Ħ# @~9k,3.5XI:s{A:(_#)2\gsۄoTRGH%9ʿ۪i3qE+[Hn 9{WN3x^u@O߀$kө3̟&g}^!c_qL8w`UNMNE`ujNwUMNww]wx;7G1w:"V~~QNO ֆT6;=ؔܕl`N6ܮ Hiiwȟ|!~|y~'j t pOL_9skN \n"6??N0!=Y켙0Ta]wley_te<cI7&jy쉥D>cl%?_`";ji-w#?uNW{<|"LkR )\0f?pYCqL;@s5 ā}}yӦEs9È)F;W56ڢTz'?g㲻Fy!Q(H|Fkgv%/uޡfu7Nrtu>#B>˂]mS|FgJz4Z_'] >@|F3{g%Lm:_?*/Q%;rX-o¿}tO]TqʽiC~c"ȺAt=C.w_Oc"щ!PaLF[<>vXc&y8Hzk}`:8Ixw9'̯sR}ޭ" -0 swh0:j;$@|ط#3 ^2ؿ:3Bϣ 8 |t>]mL. ؿ/8sCW@+9򌫖D "R@ (jP%wecKT[')o hWdOR{u@7]-mhg>~DLs龣wLZc}GBNL }'wEz4#q%yHv5X2&ؤp$h¦UDQ_ru/ӝuY{߆9iϺ sxUyϣ <*nI$-ZW4boU x^G-pq_i--uP9~q~Hg70 ˉ3zp3n^E$[W͠=c?סULx6j kI]-89s{Z*'ubߡ?i?_)~y)"`jmᾃ}|qhGQrOݝ MM??Yɟ5&e]B`P{c[>cY>{igˏh0S6Zx[`3ܼP+huyg?ZJNLVagٿF]nKjs$sn Ut4%~f:-~mgh:W`G[˦'ߣam9X"7b V5[&@? ,R CLZ+bwe(9Zl |8,;L >K GffkJR_#ZD'e3{HgtOI{Jw޲IK!<^ 吉=y/M3'tot2>{9g2FVtL ZR/[v?X|&k/%rC,ǿn1H1Ҟ.oN W$(_gzPRW*e~ _X̯Iꛣ4n0ioȶz\Wet[b)Z_׹xrl8i9 d9>ɖN.5q:n_rqr OدC6׿o?uT599}oD~\ ~u{0Ό~# ?W =qloGB_f.> hQ$B' HxFN ~8/N aa܁pzǑo?1OIs }QY 3Gרk$4߬w\{ܼcɠJ'v7ԁq4FcӚ ޻4 tw_ *-'Nzi)'CHrVEeql ,'ZJQNDDb#f䡽H>i[r"q6]fy'Is9u;\~7CqlC=[m+]L/H$7e(+ TeEHϲ⯪(+gkwzpQV5ba"o'iZVh TeaTa:YQĸR8f\`r$r!(ʅ= <˅(A.DXʅI$h("B^ vS-] ֡ӽ1"|iNQ h\KJїU#D,lgO+ ~2' ~e|YDxSa|I9?CUi4._.3?i;?Rys +1~^Jg0~\gOKs,"ܱ\n}^ֿ JS\ﵴeB7sb\[ {X*_ |CN|EՁʟ]q{u>3;I]@;|Wߩ2=ws]c];|SϜO!O1݅:.yлwb;ǘy'&r2p!21en0}?YZJf@YA䚽g08|>S<\忯Udj~~'8_Mg /omWs@fc|q8B>񀗵pQ?^k;oZ:esH?ezV6E7йڊq1_w;|^ȳ@W7@jqߨIə䢫o K|{Y~ {2ZDщJz8Wn3ByOkf z-lQ{ᶖ@e.9gи敫9Ao>-Dm|#oO0>b6GR>럴7Lyp,l''a팇Y?ˈ~S*3ϸ3\ (b;ea/}SBu{8ohe)!/$t@I4C|GwR`PxA13^CvE&rU׿*/yR {h,o[e^hx}:VWK~#ۢ{HƂ].?[!vkG\R/ks,"oCp=d6k6ҏ&ؿ}݆_k=$7 Q?U>sNA?n%*rUbXٚ^]>yd5mkrZyF&WnnM|M]_ɟ+mW6O1"8!?|.%0A.7\\ސn˕5\zkծsF2aQ7.υZP&;r\8ȕ&_? AnQ.+sn\'M0׏s\2A.TPbBkl:s\6#ýNS@,{żzPc+gOQ-?7*pi pZELiWV;!UіW)_?=#V)԰!^a}erz{0. +L?޺Q}Nu.U9,VMA XOOu8ο_"hvG}u |ќo5Q֠FUlzm6C+D^ht@ޝcM|F[%m#aL#= pzW8}'z->(]> +WiBYB_E ,Ҿg٦j}ܷ鳶ml}M8x5ƿ+{k6i3A*lߋ(M P~wUPY Ѿ#!Ỳh%ذU1Қ2WZxl>TJ5CY?S?ES ?%ゟ2)'r5#$Ym6ئ۴i{4/Q4m0 ㏚Jmxѥ K/NS%<'t-ܹnwݠy3.! xlӥ-]Am<ȋm^&aWO_}<@a-Z< 40x:`ӵxy^O7 ۨVr<x:H!{x Y70x:>`Z< DvUZ u}G-\xx jx:VOkxf`tl#6-"/c'XkBOk8㟯>[HkhtMpE) X*XBZ: :N-WG@F-?Z8WG uW竀#c\է{v4חjqSR* ?_\}MZ\ \}R G{]W~6[ Wο7 _!ՠa8iq5 7$ѝpQ\-Xa@1 WOǕC04-' %Ѻ^۫ŕlx~|g8Uq0\V_Vq|wWJH" n%Z\b WMPׯco{%7 40:pH[Z\I|\g-pp,ĿJ~wAZ\_\翍jK`T fjV-cR8lWWyKZ\\mꈽ:Uޭ|NEzfa@]or7:N\}\u7|iq20+1ľ&\ex_=W2\_G%l9եWW4 O%-v*<W! WB_?od+5"/ÕߕZտw ~s7`.c7q?<ɟ_ϻ._Ͽ7?_~1?8?ϻ M>M6m m!Suyo3G.wWQn_G}5oGm}>5}޷yͽb'[~)iP3ipE/w/ʥ֟,ɕ ?DTu"Sߏ=p<|2o~~0AGS+M}WN;m]4w? xa݇ød9wvwVw? ǶmֹIt^?[w.w~P/q#~]#~(C#=.jtUkuv1wy&r(Tߌ7.Z]St{xQޱتO[ nRwz_v ݫBkƎ=0Ŏ̎ٵOb袜[gf3`Q:w.4iZcv ;~23X9sNcqygk\Fbak~nv͛]׉p\oNpǸYhgzB=J֓PnL{Zo|n^G~ܔ|;Os6f? $?dO'%|:ü}p^8/#,[WcXf bk[kG>}̯J98/̑mQ敫b^7fdWyawq^l^yy=:b^H۴|ceݼrl^ؼfb6e^t^3 ~^R_s5[/V?v/qnѱE_/Kg^#h}ي] hmzϨx׏ q<{/{|>wr< 紷1y^ϋϿͧ'Bu瓟$ѺU&w 2C{Fm^ ݻn}awWy&u¹#%RڪXWD o%Wf9U7m&'}xOoҞ]o s3D͛3? >`W-):kN̡Sr` v}Q]ח`gRKҮVϢlS䦱|<p9.ip,h]}1W-=f_m: >N`g8s󷶩57Tk޷X_[tw_oyykŞỾ0-[ľp)H]ϑy tL&fn)iZpPMZg(bџzG{vb <o PytsyMAW_XƯ@?hE ?S({'b?}ݫ=GW,pg;FEETŏFao";wX?wK<Dԓ%U'`A|ZwN_rKZ)9 JJ&?P1DuC}bC;|[q~Mǂ*?f4.Jsq~.h5u~)G-"T ݎO9`C n 3qF}v'Srsp(ٵ Kd6'3LƸo*cnlbJ}.ERz]U%dyd۰NVxOC"ԛ Qo*M>aqk{WMMጋ@=0@{(ȳEܺL=p+44>Mdr֨=˕B9zod.t\)͙j.?g8<98z~WGu"Ԥys.˗wDL#sJ^ΛR)7f-ꂣ5 ﱖ(**3ٱxEr5YuD hp_)T5(>>V/V_;Bx(ʻ6Ixϯg5X&ƦNWB:u΅f |S93OˏqNO:=6 ')[z\Kba^Fz-GBgz'|G hV/gkk_VSMģG8g?Di8^ߥR x7^!v:'>ao!~4K |jD?~_ /?mFU8!HN+H{ <@*WA»ddwZwib#ܖ ]&zkVkc 'a,k"&^Df`\La4nY@+IxG8KZn=PUީ%r {pٜս\Z!?<.]>|ܽ8?rs.v&gc8xVP?xW]ؓ;:Ous5 ]mԿF' ;uzn&ρNC(Pc2= +PߍW0=[-P Uc/up ;]3jnQor+ ƃJE@n`4ّAxwJܮߩVʰe6zƒ9|} Te2{?ENPS?\8fY"گ> ٻl)?Ϛ> }Ug,|ӹglyI7Y@X+OGQ X+eˋJŌ5V#cjl^=}/ r_ |qY*٦ڃZ_' @gһ>Lj0OV2+'~=¥}c >쬿Le _%&}sQyCKpޅx% RxJ,#7"[&g8s5#'(1Pe?j0)?kHWJD!rz/D+w_gG|p u28O8w^4ZEX*{xzkG<Ŋqئy8!Cd+G?sp'g` U 4 :ׅA2'NoTAU!;AF<'6wBa?7+8.{aw qt(oah"ɵ\ ,[X kq>-m{.s-'0yIۮ͵jkQ͵wZ;r-js-\ gk`\qKY5«_bsAW*֞ |*Z^:D֐ pXE^XkPTA9ź80g5(bF.|0Ov9};jmGS0&8-MKbzH@yQ bK]jM}֥8볰6~g>qhlNێ0<>^"55kue+s4lHm9^ZzmR#^n9M2K+܍o ggakz9N2zYR"k60p#$AMN(Pw8QyZyQ?f"Gzӂ`:s" |i!:>L?,,<~E"y܄$È񂿟uQ"U<ҺTV*rʱmtNj,!AsbwbKwV($㳆ň;-p W V_qFY L>τDmW_3ੋ`,'5>,Q޲brb)ϛ!o^#=u,G5BxcЬR'|m]2^܆>/8~`Nwg/Nן {%~l!ȷ {Ypg <#ovFP8΄6z.~[~,NHz\-*{^:{Pr_={y~?XVzVh܍_:7p/ ߓR  4+~%N wJ&op3J,,Zk܌T|{EcdZTjڳtO*9? w>}?];~L _Ak z)+ $q_jeGcULZ?睯c!z!E}7X n:yI<{ wJ0)c^c}`Kƻa Q Ѕ1۷sR'SB_,4SBC,?JZ 0DV_M_xo+G6lnv']m/Yes 0X8 _v}Cu3TrH3hL\"r{Nl; |=ݵ{0/wÙ unV mp.2>BW=]7"l6oˌًE^"kN_ /.Ypo1~v9YO9g,k.%uǏgTq= z*Vgq=omzll=)W뙜s?LMdYa=XzR7ҭGU<{4ڭ4>U%מFm\*q[5yUcu1K,1K}űt_R+Fb3581e{WcwNR,Ni֍C\VkV >tBS?a (d21oVcC u5"?Szq+7jӌ:ĺ4`:Sjt~$GO 7O a.&?ߛQu-::LB: {gp9kۖ$2 p[!AW7^^u)/}8CQ/Ǎ;;9P`(pL= p+3~dtJq 8hNr y#&Ck7p^gGqK8.i,>kfC[Yxoy2ZSߓ"tr+eGvʳL_92}u2|+ N{g L,oㅙm<ɞf_rg9d5!9߸];8dZ3&ŰVu4| +K1֖YMoe ېpŠu)uLsg94g'8Bpr<6oc _7gw\b8BC ' t&YXiB;,=W'=a{w/h1n eLO4w9ㅠd|yڜ,ez*e4eW*ש*Mθ=p,% AٻJ/0jS{_]ieW~QGF+[SoKsRxᇂi馩snhhX uV [l]mq7ۃnlZiaa+P ;瞹9 }\=fΜ93o?f ʿK̀go܅pWÄy4t}cUwyփx0.~k2*F:=v?b-vQvLUQ+u3 l\ՉK]y3=_߳~A+&9m<;KzٯghZ%͋9e(ٻZ¶Zz!vq.zyy-8h_ y-%Ƽz|גZfW3֮U}krYZ:ݛ˭fexor{]DzI:oyoj Sp...oM$ۛlvzn`{aޛr? OHDw!cr{!ĚMfzhǢQDfyqb֮@&:&? g8=#i*3=LϾCFӱݓ#\d%gҙ,x'=D=[a?i0^@Cw~ta+EvW i~˙tlWí7eBL%I|N 2gs/B>Ogzc'ٛ$݅~`=1mhyg9_y @. 4}[?hh˭7[V da949T9+p؉zZE'?|*1fsCv!ާ&6b-,@UYbXz|fGNMUclڝSWLj+?yܻ뇜2#o|\*8d8Scaup]MEcR|r7硼ziF ?%ڿ(þp."u"AN1s:4#ؿS'T{"Qsv&[1 ijx0fV嵭|}ۦQ81JE5_$>K;'sWz6HKDm[t&_yg Wr 0F?iOvc8fvgh.<;ac:陿k8g>~F m9%f/щ{b4n'9atAl j^`cF> Uf>.E|X{P><Ԭ1D=f1(Zwi|-YuSݛYy*)|^KEG_]A먣M:1z|fA]lbAvV5zl;Xu.6r0.NMs\;>uеҹ.6tMRL|jh6`S # Q|} "hqIu1WvA2\D&onG: ߁LE/0֪G޿ug&gϐݯ B>O9QCD>c|_%i!z28U[.A kk?_.zCQmE0 ܈^"vgy xt|J{1Tj~s}/kc 4E~Edž~ک?g*ߏB $8"ֿDžwI7@i@9CUY[met\<QE=lj]bw- *tzl6r<3 A3{ `m (҃=@3O`.M-2&XobfQx:ŵ_W;ݙ]'yuV@-\be QsJد"|i"M2 _*#,4nX;&,'{<tK@Wj> !٥KqVft\; y/[:ľZi4Juxum!9L5;;V~~3ehotHF?A"tHϟx/6J/_0;a>aw%^ ŢdD`f}v09N=' >v#0p>"g-W +E`o}ؔqb2W^4a Ka% .sJn;Nww3!D97u<,D=<BpΗeZv[RF;ۦbGpFMjss[2T.s1 A&;suss><χ`"6-g{] . JT9sBxnwD>35?)5_k5bi59/虵1 ڞNoz̻Et.VxwGk5pЯ kN@_<{ָVN#Kתl³=Dk\J`k_ainqs{fBD9Sj\)waл'Z;L8/B?pPet^e@Jtk0/-R}BXC}@‚_Xlqeo;]]\ޓve6[y{S.r 뼟^FqLV3,+ǝde*#Y*ȳtg(RAsyvypg aN2Y9JWvմQpׅZ(0Qw<,)GgcZCi8G<6(oxAePq[AFWL_.`Rs GG$k(&jIYNr-f~A.x| |˟71_Ni 07,_.O%N:~P=_|߂88wZ/D;'{2tEf>8IۈZ|<6^bK(}Gjr}-mQ}]SӺPƭx2akԏjc;U&ֻ~s4<dp`B+źol-ӈc8]FoX{V6D]yǠ<]:zo+癤s88VcOBI.i+qКT~.ܩ -"}5&twǍtc$N~w0?R_ZѢU 밎leO]V^뀾mϿb]M׆\ׅX\iн|G~hK-`K<=&&sw[A{1_Q = "g)ݘ5&u6|p2\-ɮVoA ~botX ~3ߨw9~NgIZ!F8c@ۇv - H;_A8Kwaw@`VϗxTl1loHvvdsLg=ж?xmlBwrޑ5BV_u³I@4>{~egEd7 ]/_UR3/5u`3m?Q/ {e|_BC֮7%r:/tcU_-rSs_^:g:!\ur'eo痗v3~i8C҉_vkP?u|8$J/_ѯ+/B:Qsh} 6 _G y/t4g@iqFr:zV2:w/pk9gϋF 3ټoJA3,)zM0:=G }lSefc;kZ8}^D|~N9nI^A`W?Gt->KyN(?ۘhƂIe۹H:gUaȏBcC~gMwd-Gq{bOω]nKCX)|] Np:1כWwC* 7SLnxޕ\P#.]pyqsomE߸\|as] 虡ǒyK|@Y 5e0Q=,mk$ ]n`L)Q7.Zk*AX`L`8ȂCLЏQ?Wu^Iը׬Oa/BkS0W??͖ }< d e ??]EN`t?`QzG'v>I"}'{o>XdCVE~<3~ʯ&L֝4NS~|@x!ƛas+̧^@Xb'2]P=",cߝvQs]j%j]7yNuڽMMxKiJʇOSwґe3DzDz~ꬆo2߲][QcS+,#P23vDF<|ȗf\`ˑ|3_n5ũXkTJ|9̗k;;O:yr`//)/ߵstu9/1w/O _o__re|y[||6ȗ_5˙F(ȗ;|Ft!-f|YZ` f w/Vu޹z1w.|yU//cۍ;_|yuB!Ɨ;d˗{7_#___޺sV#_#|٩]a]`s<` uūE_2b'7J:>E;+c:܀NLOԂmtCsߝgf\#=v9 c1Z[5H4hc%Vŝ7;=Xzc,~ccGӈlwc͘V_}wh߄&_lXBy L;h9s4%֘0 @k۱lØGJioɈiO^Y{5ᡲwd0/;eye[6T- Nv]6V°f -@gkyy [9M2D+qˍ_vLs#P؏ "ZKaFE,G0OW za9y?cC}O{<;\!u΢n>ǽw7C̏dg~x¶_)!J~908O'&39^AL÷i0x'QT9m?ߛݻPK4z<3 ͈;i~-^MVgtfo2btXwM'uemIm"^ ֫uax^g:9~${1~i6EhC} _y5FA.\5p=-*{y+-ĔUXwsyt{Cd`~;[Jʿg :Ƶ YGc-{k3Z8N8_ձmWf\+M=Vh{:Q^ 6U4ݽrX+Fݶ4b[UMl[kwjh{Q3U4X+X+>jۤW,12]$巿,o&v+@mq 9ڬJNSַ׸[`q?mVP|j/ɮ߶߶?t?ϛ6b̝7:m5m8k#OHQ m(?#? y~o;fo}"Ɗkp AiwT#=?[Zӈxcz3}gau3F/s}R\C96>A(=?,Mmۀ?mt P5ʝB돵߲x(x [P1&.8>cCa=D~/hGoZKs?"jd c뀦C=6ʁ`r +MQ)Mr$lW_D#ςWI _(?pڪt\O&>s~p'Ȥf͔u\Vc(8נD}jy+Xw{\fHX%Ha2w_N<դ8ϝ+Ysy{-Q_<Ec-><'υӻ3}yvWHm8v`CmhDOz2FcRYjx_@ccJ-F,$'wp[kOu,fko3Csғk |/I'Ndߟa ۝M6+8܅~y!gC"b i}ќ yMeѢ_flDZ=&Wt'#IH>;򅙺8eÓ1f[?7sn"Wyj5˽e?jϳ:Hho-xNZ#֤{(߂mr Ԉ'? g^^oXO3+A~M-jfhLFw Rlȯc>1ԃ3]GFw'?ǟ$(]-cllrDwmt5~W)fVuv oLJ`5)f) BwcG!VH^ |o:gwåBx:ϥ UKøV=VS?n-QV2US>MV: ] DïpĻͮ}Bm 1 ]kxM۳\ǵw9+y|[Q7dM,/w}sgbxmH"myk(:H3G ~摂~/fFWD{(J:-I`_:-h&Mx ش&J~ZuZ61NKڿﱉuZ})_G8=OEw9ڿ~5܇x]<^ɵ=<|_C;1UD} ,چ~@'A }i68Op1//Neoe:՗Nee:ճ۴ztj[cXidDx+bz]I՝kGM˼1P٤b# 홰,ӽמfxofrpH><χ`CC92ֆE]aIRpٚ)\fE\iq|y|2kV/v~wAidV3. ]d3ө~(A^6z1 )}Whez&st|!0kǯ%Ι!7Nq6}Vk }/!{)k8h3h&v.~T?EzK^8(O0T'.#/u7,F_0:<} 8Ng:Ѿ+l;Wj{,),4S&? mBC\D)=(z 1Fi;JEwN-^wyVl<FTYF*" z]oxOv_O ?>tz)ЏbՏp(^(8 HeGZ+=zOFfn3tXaƳ"Z$6Lc-@eAyzxz-|qЮɣG"G~?|mKmCkߏOӸ7Qg iG$ǖȱ2vR5T7jt-twXTGǺX~.v7R$PNgíF^PX'$9F_Û)IZHs߹6~>;]]KM6٭F53~)O~D~ƞ8QsnGmc>pd%zcx:Wv$Q ot5~M=S+Sr<=]HcNE$nsmxbs8=vws;xZ]fxۥ1Iy ,$ ]$,?t%0oI~I[C&tx}`-g(KOa5ıxH+]Wb"e;M{85ɁDqf/" WL)`g( .L;Ɠۈ!.CŌsF:n\w\{0'g@|i??[L~f33~/~Ra/X>)}^zn1leytk( Mqa ۻ2bji~Jgm}~ǣ?(8Dy}zzb-Gt ezKt .O?bK-|7 zt0A?ѝ`fr-H_|4KmkNS=K-ŠP(- TF8KWc xyb*%,y34{u:"Zg1ODuzxQNZlCZLF۫`3ZNL㗱~m!yiD!4 tSkM4`O3x{ gC;9l!n?-F[.A~*/8<8w;7قعjzaa7@J.~o߷ۉR7o=i=I|7iL[%9S30lQoqz~(PSDp'PDFW{k}O;aa{R׻Y=+,k aO5_&jp۲5ʏBol-# hu`?ɏŇx:˔?q DI=̒kqL8e^4b1CkWG .߅7}cj6lhg~Wf#ڽgBy/?&J:9Dcat޵#I?Nsz\Ʌ؜>'`NkϓX@,^)}Hh]sK][ݽ9X)`hJsw!{P6{yVq \mֺ̽߫uzʷ2i,#?Y#ҹL2Ewq,ϼ[o׻$1\,1潤륁[ ?{QZ (u(`;ZX?5S$ٷ,߯Q`-ʨ `t ]G68f˒I<C9KX\|%غ )L8wC?O3\Z1_?vghpxo+!kA簛]DMh2 r?ylPGFYL#? gJx5̏J /2=s$%JK`擳'<3|FH#zr>J|>gh~ng0|CB&-6gzq>?q>aYMN |$!ȿx 3Iߣ\A}3Wayz7sq>\;f>RKߐ>ˏܹ9f40S\?H3*]am Pbawmb Syw4%"sEo&6%otz>Β#-]g †t@Sg}<tV6c쬊!f 'ˍ6C:`Ąm;GX?5 `6̄FVӚЏ~ m gmB=†~6--̆m$%Z#z Іq dPۆpچ)t5C6 * `ֱOeX֧0˰R? scG5@k 5lk9w2518? L9(el񿿈wm7L>X9(])vq>B߃iq+?S>D'Oom%i+K?Yq/$JT7'{z??E'wO'YxfD%?dj߯߂$#Z#kQu?> Uw[=M_܌> "/jK(u}f tqX1H`X@V2[Ey\<-L_9s,;wǕOC$tj,uHXݣYVif`U2bg3ynfƅzjKyƗMoM8MvO0,XUi_Ư;ƈ JccX[2mRK,gq^rE yFv$(:6 Ȑ{Pe!y%p ux7y:xil!+Qi2dF$f[Dd2$tGof[ky`OE_Eߥ߹ 1榼1e]=|9yT{|0ٛYL8Џń\aƶ .$ʌ<&TWjCo>"\y0&I?1(sz] 61w3&x1%{븥Sݹ|ǭ!C.xe7k{)X|f[ by[-Zh|p^ߑ z)^Zͻ32cP;3wYF9Nh̄Z^ ޻L:o;5(ʪ3&5_-6&PKج#|Ɇyb>Q;~Y? rQh?BqGXs4l#Hb8uf98 =S4s 7lٖilfC1)4S4 i6_{G4s<0ac"bMu\YeDi61LVi~5#2oj3n0liS4[Zmٵgӌ4 fw\HLa'>`4)7nJ?]v,dY13Žic Qoo$#͞hks 3Š4[1͖84xFiv:3ͼB=!dF;iɚfq5n YbلQfi*a9fZh<4LPfU=HAhizL3︐fs/? 6F. 4[򴞥cy\_1L# :3FZZ$~l=ٻG ~Fn1A9JcElN#bn?briND~yNq9'V[il6kzvNiœ9 W9"s s Sd0nٽ9 wh9rQ01R "Vƿ`srT`~unI3qNBlui*ah 72cJcKdEtoο0EBldcl|^gq8Dž nAly~%Y=9MB?B&i㷈-zCϙ>ox_X+P-]͡#{6hIcl8=K-v9ga~b;<Ҹ~B[4ƿw[tm SAӳ$St!=zI-vulѓg[Wa:N_?!hxcDZ?&N#usͶ-j,ӳE??eX$#/7Gl2lHG]?ǃ:=sB'(;#Nh(w-?⨫>urB[!n i<#h^UyN_oحk{<3u~ĘX+!?rq>Q6mEŸN#+Gl h/Zȳ#NϋQD\0#Q/G4B]^=N19c?1j^fG#]?ܺEE5,?"Tx!w?s8ƹs 3Fd ݞv=DXao q ,xpB>vƃBOך Zi\UD`慛$_6>yaFW݌Ǐ/4~0ߘ`cNqIž v(~9&UaRυ6%;oޏ#8yDoޏR,S\n5G]؏`h7ڼ~)࿌9~T1 YL9f~j\_7Hs312n=;Ro羒wB,%'YFK\;u c>ƹ]GԾ{yf~a絓] o 2p<>ΞHNh3#|3o2׃9Z-_ˊn`aIBb4O4p.'#60 cSm1LWIFn3iPJqFu^qFӫ9{r ^0L a?:!/OF?ԱA1? i<raz_μՋ"}tLHy_׽%iݑ0B>H|%W"ɼO", ̀\t'| #l <?&?ltg X|ޜ>뷘}>ۿ׵ÍsO_nCvNEԀ]Gt豝VXQ/fO٪32ճ>{}#>[{g?3C?`I_ dGL?d:=HFGvկ~쿛֙}>4=g1mxY i}Q?Agb^.lG3Sgv]wgk?.Ϟ &}y]hapVmi ~ .{ lnƃy)cylG j˺M۾gu{934|n^43}(a޻ghe?7/E2?۔ݛqGCҖjʵDTjB s/c ,ݿf2Ka1, Iǿb1,gŸ,'x|_d5㣶Hr-BaA9`Oz6e ]f뇭FZQyp#0TZvUGK7;2uMhN3T.jkukv5f]m(j-F]mX`O#?t5-bh=uzbmw{'r?w ?AWo-2~R݂gŔ/=]mvL֜d(-Bw]?[n\u3}jߵ2:esz~4#܅~7C7a%6jҼӤ)E1"Seו#͡eppk]-ո$g؁ߎ4ޯ/N˰`yC}ܯ4fzo ?&2x,0JIw|MD)ޯ;0ޯ~ݯJpuwr'ܯ_,7/ 'r_/}Ȝ؋z=[/0{@4Ynw=X~]](hp0xor&2!_sX0ӹ֞Q\k6ӨiQ<\ |w Af5";ڍ.Dq)4j8d[a2ݷ(42#?_#? O/ ~;~zׯ/`~}FOWA_bQ\گ.~̯qׯ>Zf6>Վ~vٯYmGN0uЯ?pWS5R_yb%^j=x>G맵| 3wg")q ^ ՓczVjǴ́@ s`?n_d’0 ^ y,=$zg5zB"L^nmFbmDxFy;kf"Z/t $޿ ٤GOgW|nFGd!a~Kv.BU82,c_vz%3th!?YTcKs|EBnLxgqOc)@ٍWL{%q{Fʄȓ"O>Ux2_G^x27j ɀbݹ_hY"<4TdK-{|;_d% !8҈xӝ`R4(qzmGD@.GZN鋚R;s]8H #qG#7{;ۅ ȵ;{F@?3ЏA?r_x ڵw{ ?}1JB,omOô +v~tVl2y0$<+s/Ͻ<8 7yzN={ypͼ s ;SO3w,=z'5LSj|x^癓(gXVwԘIL'_Z "P5"ZV~֙u֋uǯk!+LVؖ eE~'n"?Z~w5* ʌ&zțd7uyrjg=.rgb.\*?YvڝҹAqG@H8>Yu6;rfα$VV7s`8M^tu;(_t.ҽO{_͖wku@cNϸNk50(e>Hh$1L?M#1o,gQYYrTuId? %^mRzǦɠcF1<=xpϫky5Wʡ{M'Sdη@-U ܱXZv=(4(kŶMn&5[i7^χX<' Qj]jKtϯ˗!K\<2D1ʐ9#yY|6NI|'K蜜œzuqN3ϩVE9//#O.WR GۗaAQ@7n)9޾[[rT\%(C;g)B75Kj-7R-!9^/QF]j/>.v{h3>_!~G~ QGyVMWWby}'ݾfeÿeǧ02&;ƶ#j'6`ƥ,7{]c'`- *`ʼƍ[>~v}|1x_ >Q?NPk7eDxvo-AJ>BÝLoB?sp_8',VaG+6no~8t{>k{ǧP̍p/\&MJy.=nwxpFHRjLan%8sG {Dׄ{)gߌ3ˣ13rhn_KX#|#6u}`1~X"? 1=vCH|.bQVteB? ?8DpThwvg bq&u/So~ͼ)3l?~ěi  ?Of/ТA$ o&AksZ B!?` ^ۻPH]wi=ᝪmIb(>F3\l3to'sﺣx7{$alA2QǀZжv1Ez P礪ss*ǽN?Fm#JA~){|OoF;!s̉h'к[r"Ѣ_D Zd!?Ʉ,&~.q\FtN!smX"T|n-|Ӣy 0gV*ZdiiLXD_B^{VxcF0f'|؈p\+hrh>:m!~3,|:Ua hZ[lf?MJtm7 ޏ Π:6d>..j3Jo:y?WswZ<< c([ǻ;-H irDʴػL{c{%kr#TmOw1Q5ߥ+-(Ě!8{>aK΁ b CQ:U+Æ{;b;4"W+Tr5Nb[k]ǽe bj2u$WhyHBco/Bؖ/ilTB1Uu-.Zn֧C)Q~~< cQW{sw!h+q'u2R{[<޳ycy ]ʧ&S>h%$ʞoA^0; #o7V{K\A#wIO?،qty>.&g|JKlٮSTo|?}ۑF[b<F<6^cNlWٸ;G5&nصY#C8Jusqk[-ubG/A1CkWY hש,ݩ+ANO!A?Or?G~|R{؎i? @a&Pb<س|N~ǛyD) 2c;fAx3wޜL!\xi<(oZWHQ'YNO\n~,~ǧ:#a Qި2 )oо;dgzr;;cP><3~]D)<ȸ~v~Gq g>FSe]G}/x5~ |cbv[ܤ x1"m90Kcg\;scwK&?|$? }#\xL^);s;GH{OaP$şц=39Ϳ?>t%L Mi"Ŀ}t mG>6y3=x` =}La~=n򈶅D?y|4 *ٴ\?W,}jm&z|IAy$ޖɦ ~xo({m\&b(xgK]헎jV^=jN?x~8o[mhٓyrӷ 4׸_@M}N.跂;u`o)a{Aq;=#>]//{纩A?z'hŴzwH_컺H}9Y='<S'czOOuXgw@WZ/ٻmuZ9Y;u޾([D˼}͙ё(M?c7eLlpvkzH?Az|vU >L%us(qC5}85Cu-wܿyZ? _fV0ְ5jgx1-ؘƻw Gﶙ4[-ykmQFs(htvS@ثe\?t% ˷ivAu *'Wڞw4 JB.ztJ[lfůжبVk`5 mP\!wں52pױS}Ism!zzo syJkJ>_9)-P_ȡ +`mColG%5{{%y$!2O'X9#], ?n^YQ^,4j1x,?i k9w7k74Zm0i cR'2#OGyhs/0܋Ef{Èi  mW`}э=#mls\{Fi zFOF\Rso3tKQyutNzg6$yvc4\~sEF+m9︐j^T๏_ye Q<7=s<]{ÃB1ZXcB ulpw Xj%J$ڊ2% =>= { 9\uUkx4~e5Ź6N|swlq>W u>osnu8f2uNsn'6eNԔIW?20 YZ-) ϩ:79aNTo7?EZe_ߦߗJs쯘_+ͥ7#?%zȾMkz:'ޓ_1r%]\gzbͥt`^F[j|C\,w5OER_:7X[;XˍbȾ$Vʿ:C7k~y:D:[}~-!WvmK [:`N[^=|Z'}ܴ^iqy(Rr$G8DeLm~x/Ʋ'yNlWuJѷ6Ign`Hs}CYrNsyƾfq9]οGwB:_sMwP~KR]zK9{Tե9OեE]M^hRUտ9Хw 씣"ց~8.D҃7xۇ.}S%= t٢.]a9]=.}e/d_?qcAst';*{}:Ro@?o U~n.a?:ҳR]yr{-Knic?jsuxO]&aը*V&zk]or7zmSWyT6~#]N7].N_v]guu]u힙/]dvK-}Wk˭] yۅ{z=ֵkgڭ0GKk212ٟP׮N\9?Gkk+qQyۅ>`"@\/ X΋Z[+.&Iӂ0q.L,??CGvn_V|Hǥx LԾ c\D>Q>% y-;.gm&i}'r {K\|i.ϭqs#Mܾb+[.Hܯ>$S">?w!H]ٹg|o{ig{4p<Ow\{^2^w νX/O 3տ9Z v|` |Ka;,ax%0,ңx%x%Σ:j[b|=QA~˾KGr~^\w;ҹ򿀛$L$8\aGO=l bi9]4 Lco1=GGetnΟ|XG0(|?L+ w`cs/qqzY8K{ڤGs6°{Dyۇ#N"?pͧ"}?zg4Tu LF뷕d$O{8*~i{4pǥFw3=x_o?cA?<98c^c.)ޓAzDqՏgͭFwhWxZ9ਸor/^']_Rk@m/ǟ *1M$\[y_\;؈9svquhiY8֬ o=}\=ж'JjJ(V򴓸٧m!-S:-Βaks~?|s1gp#'RT<ਮ셱nz!ؿVpRKӊW.`o3ٹ{Z!c[ |`'۩bW;*Og\?σV@.7V4i#Kp6T(3DT<T-TȆ \=!Tm9iN51 eS -&ux#E.H] @/o!vv~~#+հ ս?[쓷ޓ\?)9}}OFTcS tkS |(4(ԈFҜ pw<>;oSA+,DI?!rxuSO@sծU>'x }Z'-E>~q??.ϩRȟjiOgFQޟ E;*$^7bO3Wÿͳ5+ˈXTnKI|;y\ \wۼ{+lE8m.O-]6osf7T>^2'tM*j=i |itn5Ug{8Milյ{SLP1`qVBm]+5L$x@&6$6ΊKG6vfoN۶D5t^ [wtw~x :AB?J r\dn#1`6ߎBUno- d~V&zV85S9xw2=wM>oɚqz^֑>vOAϠn7}{"zl@? 28Q@F Opo_n;1"?( EB6?3;$8{q6 IJ)U=J}:. SHߊt 8"p0~oP]1]vsEh-aV]!#PSS'J1a,W50^ӍOu3۝q}]9?Հ d~VrN)$O^3 NGP9cL"-|_8+Q߼Ϯ o$}Ξ{'~+PXZuLlL΍xpzU;fYt7%vPU|#xO 82 p7{逽$R+YK1Qw.L/x9p}z S`qˀ 0S<ķ 8e4sˀ \|Sw{Se4Q܂ciǫ\ez?ktT\Hᛉƪ2`L 8Ђ}9 eJ&ݪܮ sS}ˀ:f((2d[e'ܿ XS1ho2d%0qǧ2@;N|ѓcbƵۿ 0猶2@9upXcB4g:2ޢ z([,MVeyˀ1=0vzuL//ˀ5&& ߫2 .}%^ 2=&ˀ}Q|ˀ(,6 Ez}JNoEfK%{;va?ػZ`Ti4v{i  1q~*?K9 #9ɂoF#i缄{ZH}s"Fϖn;W_6OB+_OXe?C9{ۅn=oE9sӹQ6Xa_gL1h}+!ȞlקMpѻV;ab^dw\ɕF䣓ǽ |tA|.Uh\&_?NMFm3|WXs/BZv|ƻ- /8#3?]2-9`&N&XŜ%LsXm橲`VzU,GbQx, ->W/k0C>ϱ,xU" fb:!s(lƒ&>zOW;NWͭx'|\Rq}5;vN3S=dW;d$y}˜@Gicw" ?_K6m~Q>c=}ˡ.j4CCkp#y{?PCw?U?P?ra.'ˡBrh>w?9ȝGrpr Ў 1ַz>Ӈrr.>} >b{)<ӏrr.7^t,5&rhArH?>Pz(&rFQh->irhLs9râzt(jdrhG/Q zdo9M!gl9PdO4B!{(TC$Q}k.9 9?k9o.^Yo. ->)3BgwrhZQ5Pvr`9!gd 'C##V>zT9ɡF,o32&K|ˡLVʡ1բz?=G39H9J9жMȞ_C:/?>\Q8)-nhDZ* Cl0%ܷ\܇s_Q=.!g(>I7ˡOzC 后ȡ0JC$&rˡ5ը]Pַ!p(3\~A.h{yUӼ ;dz,] z!ފj=d8yvGG.owT0%>p?nwAw0~rp޿.!˻`{ێҮͻ*1½G\ޅ[CvJT\.5|+.HE t^ڋ\4-]<7Iޅņ.\ߓe]#z.Lpy;SFн?oy,pyjvmޅ2v];#au7gwm`ޅ :>9ͱtszPunr?'r@w[!9q=Dg[?c 5q&2vN ?ϱqM> o:±i_9E9p-42ess6cCXnGMcc}r;*mwG~LJ?s ?/c׃r)yX`MGEuq.ZK@!Hʱ.:c}?$pk>|?5*ny. cy'>xOGG!k_8S؁~GG~bPf@081c=x#?/qOin)R XTq%95C{ k1JcDXu\>wXW/ɱF봾 S)lnl`usC971Xe睽ı,1nCލ]/?ags?)|>s|w7~!ݩ>;`V%c:=޷Go7Π[eVz5Rr;~\p'︷q`_]_>ke.φ ]VS sI*b Ľڸٯ;b.^$w H5ۊ}BD^r9]u& ?<;AZܚI ujc^4yqk+΃ ٧q{c讶}^e%@{A=wg/ npT8L2s^?ϸfmUn~q1\ȁt~&CCuq~jۮE1>I0MmW{:wH{voLPL\˺>  !q{ }@()tMo b ə 6 ]]m؂FbLt_4}&{ɿlk}+H4ɩ7]utiucnz;Gw$n/W|;|(ע;Zwb[N|{_ηwCqL%gwV\(q2|sqĽz{v Si7s㟵K,s<,AT$ch9VߘsWA_Mɜ/Qph7Ucy}Abnfܰ *^-cS܍^=rveV1hR14~sC2yp=*Չ57f 1wkD]VŜw\?>=7!bFs]սsOsUnIT1'տ!{?9=^?H9&qo^+GunOyry٣vA9#aRD=7"bsQ#EE S1`l\}c'UI1ws/qy*ʻs0mW1׷VܫJl\a.=\ 9r3][HV1bEa~eӥyp*17co%bg\"q&poqs}v\Fsg< Z=aq*Hg뤚o\/A!CZ @6!K`_0~vdc2qc4e2/| T/3ez|Uzbq-FnK|Pq?臋b8>~*l]>H=R,y\GԮ|A/Dȗ\֬e^E|8"(_j|e.+TxF)#'{>|2Oe |)_&r,e"{ %IY{ӽ|Y9_fa˳2pֳ;l ?xLz+lzi7 _ׅq|e|eU~|}|W$M˼^&[v#xL>/*{-.4oAɗ|W{>{:Wi-29M?9LĚexs|Xel"_fi<9l2D̲e~dm?>2]\4ŏP?^ne"_2ee"6|h|˗bLPO|z9H 2`jd`!=ϗ{D2p҂ߛ8 Ft\p|WʑdOq F{|#7뇳n`/HLnj/3 /c?_oL7AsA|>E>I2KC9 3242C'|U+ǒr|%|/c2/ck2K˔6D6e˳2LJcOpo$??Q3hxh7=`djgMi_ۦAd_]s忸~D?Ddფ~V]/qʽ_p~^T/pE{ĝu$UU"u:A\~3~rqA{g^Ӎlk$2bD? |&يFΌk7kGKz!ɂiH;S<%ݜ7 _ #!ZbDgȘ0e9vL揳? R}Lma8wi"rh8[@|p8f#jמMuq_:P!ucʹ> oD¿zǕCL#N=lU3_xMR_ˠ2q33k[6g.+sHWy|8g|G|߃`z\9:5/#1vqsꕿw3#vfz\'%ڷ'WG:wGceKCگ&d}dJ)'Q1uݧ,Zց~8x?oLxcGsʀS?#~nZ##+f<3t߶9W<33kyܣPs;*;K'z==Ggn!g7k|f=G9߳kCV?c&N5˵fF;Ap*wKd2mȜxvWۗEg#q:+!G% [50r.$ci{Tii/ʂ֐o0eAe?,"b<I{o2_, ;ԐIXY,270$Ϲcơl-kF,o> `Pǝ#ߩ;څO q)D ~Ϧ{y9P/na%^sDڢ=Vk#+Z-Er[ΉE{YߚߎC$(ǑbvGڮ6.m/BţJ7N {އ;Ŀ d`Ol>SX!ۚT>Vak$GaT>0 lSHv8g:`GfvgF|>_=o@SRAOh$k&W'b`v?A`T?IVuP/Qk5ՁsФ@tx}H;`RT3r [uxǏ?V+ MN=/߯oSOsƉWl-8ʝ/}!-4QESi) kځ$g<[}S|ױ7M@6FqPhp3i߮ pBnuk 7@?td&Sݎx]˵K,mԎ(ς3g(`خN/6?+6ڭ3T/A_jፈIOǿB5j!?vL)1ܡ]|`ÀmG`)g6L)m9fy0T(iz [d :a(OJJmg뙮ıWOOɆ1x)0Uru3 ׁ~~H6 ;vb7yr6ci;v| ś`Y I6 aav@pkRp)A0Wqo?Xu 0|9'ѳhݴN xȝ@l(oKUV].O0jJU/[wﹿŲ&ð&㿝$H.w) ӶF6fa?Zmb~XϬ h#&OdcSd$UnJt卋d6mgĹ?iM~'>}{qs5yMz;ЈmT 4F]h;ɦ65swqH݇mo3'S/=)1s{8}'ݸiHfq or~O6>"s> m79c;VߖE  b9m&&nؐ-࿐8|3_Bh.Hȑq{wU#tv~7Ɓ/]> ׿7%8X/=; #+d =; &oNzl8Xm m {5Da9c%q$l7C'{6h >O"Fl"m.tAyt=U1PC.޳ 6& n;zNqz7vg~ǚ6xZAXb~<ށ1ptto1aA1{@zS | 6RW;㙁1p0n\O 'z`/ iKYϦ#FK>㨨ʤzH}G$~{Z)d@CI 8a }0Ni͙K8Xz̹\WLi ߱t.>X'r0'S6mpB[wv" RB]vp?;(n?[xmMbp菽wW FMHu@v۝]8no0b})Fl}s 62{cSE\[@6y+oj';1Е?+e/pSun[P.PhM@=dlo3~߫~#̍b=haS oo GZ5ܟJs}P!v{=/?G.[z;z 5qoB{;LJ︘(ӷ.>;dwH<:0n1qoߕ']9{^wW*A̾ 1Bk{g.wI7.>`.[ux=ٌj>f^tԶU;{&$w!OrLs|Kݔ9Szg;{{}f\N+޵\WqQW)s]1ڇM)uŻ mXUmr5pϽVs]1)_x~gaMa#7 drILWvvO+tś8 NpƂ^?bë+&> ]+3]{7bMXـ`wT]1:aM1`T[=D/WSxyāf/Ř33-Mll0o D_4,6b$֜Qܲݝz:ǡ{f8hQ ik{qqmޝaϛHǡ'N֮lezL~H[c,?_9G-cy[^c9:Kl'ͧ|z!B5UOM4A|G;ͧqx{LCLݾۗN"Q̎iLFn o·'|4gi䛡214ʼn{ fo.[\/xz. [HLʥ[^\?heȹi i ?aι[}ƫ*|>WxUho}j gj"vwzdb @Gr:/5C7tmTvlÅq.:lOr"m5{fI}pNo?BͿegKm;!CX]ޓw$h7X{3pzaaexh[^-G @>ΖV7~1?,R+{+1)K瓪'm:uv K`s运>ϡ;ɭ2 .ύ9>cjWeKٷ.>?2 UƤ~m=oσ?\D߂}G@/ v5bߍlc{+-u} ƶwImm@[5<7dVuC ɹM/Jk,ݎkխKJk^lՠA{.ZL8C-&vkktsQL.\|\4lj<)$\ɿsHnޠ& V^LlG4H /o3xyCY7|ɒ9._s7 uU?jeEu/|_q >{Y7}QW߯2֊Euf.Zh.vZ,oVs__Eͮv¡/j!M?k nK _[E-6Qg; !Gqhe`_T߄H33_wejNCF| |jK@ӧS3_sO3ȣ_Y [oή Lo8+ 7 Ss`>=  s+ȝ?sNq9[H۽YB6R^o,mIm<>Z/'?1:^ ƛm8ĘUp6&ijy-vrҘICIDKk&7Y;a%vg~+{c 6Y~C&̥6ao]x7ɗ{t>kk"ޏdޛ~ ?ӹ>RYI9= x=Epaȶl ެ>}P?kmz~<#89!w[=O }m|xQDki<@} ~?>?SD_9[<,,!E mL/:hɃsK|#{(g7`J1ilɵ%Q=ﻭjoEjfØĿ9wimܻm|Ix_w[Aԯe[㲬y(^WŠ0Й6;p -BI򿔀ncH'IϧF:a;qLk6=2!ߚЉU#'b_i9!=&mI{Ҟ':|tiN.Qu'L0k>]VDoZ |/6D)Q_`qV0Yf{)TZކ߁?_yAKgqJA.;m\nn7#K7s Kx6(jdCTur *hͿ;nM4VuA1p wr,"3/VMg`_1񻩽:EDZN3.8+ﵰq{vsZ#?^bc=,{ޤ }}7ۛg`w7RF5>|%u.CI#h[ Y.hp;#{\ޭj/ŧ_^䳎k^<4cj{>.^ytcvD Qid?Fr#Ūމ5I$$s<W*{5 6FB~PM3TBX7BՔa񰑫SB1RU<%uL#|1(&=涞lbxgH< Bp#'glni-ۑOxpK|&I3Dc 57W{IJOoedO2:[x!%݋~Μv#i),l=.ψ`mQ]$Kʰ,I#yg>\X)𖒑V y2y|fR`<㐗F3EZ`BtZW ƿ3꿧1d'1|"s&d\oϚ,s,up&d\o޿=,dhpin^Z``*SFs@n4uLGqQ#8bx'xq¸÷ z]^EHgE׃hfum=>ow9RjNǓ _R,_|Wyrڈ%k  `*5'=WMtm݅VwƉC?||-XoQ'6FcN7Nr>8haV`:D 5ZyIJbǴu>w;\m?\6ijiҲsIwP`C6o2s={6Op[P :K"vzq~څ,nӔjog{:袆ݘ4|x[mz2Kp2xB?@CKx#+ؐ\-r5ɱ-ڕ:yWbopOJ4Uf+nWbk'svJ4 MaziYZ.#Q񑢮] 18kP;vf;yk-ݝ5@ƯqeUC;w)w4wdu2Yqw~]GzG۶"˯ΐ)'wOwqw/3wn=y4]մڏ$r lL3C{TAMWUL>{ɭo\frÝ}Z|jת>}  xGj1.ebwqϹ|i^H{r8J.=k|zkD]ưM5F6ˏDh|F >͍+QZo9._eqq4um\0d_Ocw5g4S'br\g[i*&4"'W/o\V DLq DL/?iz1y_9&?_j>4k10"iŽ; i|Yܻ .S 5\햱N?0UlH=?-xL?Xl3VGw1[қ~b!cq sXyssȝxLs;*3O縶w;ytaN:Cǿw4nwvxynLI|& #mۏ s <oK-+FXvgN״K#>5rMQuuǑtum5mgmڏ.@K״.y>iMŃwϋפJ>28(f1>YSLxetay2_ ~ֈwn" }R8wiY+ޏ{5us~Ul>F26P!n 8ɋ\G'o}@dĚ.\`Jjk5m4W.Wc~%o ;iL|1VG"-U;h͠"-Op?;&rT8*rg8܏IC釋L:{Uީܞm4߳ xfMb{vlLYZq^lYw@ܞ# k?O=\{wTL?^mҞE;w#o{d>G{cxN={$UrC3|qX,+ZkCwS3 ?1ގ4}1ݾCgHKU1F.YUƳv?]4N?rh~$G(~&S_YHs{Ȗ=:yw[e_<ۏۜ~lM%y.9Bݏۜ~lD?:=Gqba])ݏːv^u?~J~I㡦`%/o$ },/a۔Ѿ˰9 hJ9/ZHM p݊j&YFKۖ -J&EOp$Zm ~څ5_տ|a'r1^|(i8Q( BZ7G=32 ǯy~o>ʈƽ D>+N.8ilaͥ?̤ #_B}'Xļ5xl.7דm9N|Uq_'- "wJuᖕ{Q秓u ޸t>j5fy]m kI<2_j?6p5bNPӔLd#|bH?.,qdCc_6svN.G^cǙ\e8?]+?$ytw}4iK:;\s=xc}b4=GtecuW1ع9S\HE8R5)ؽ'o5t_9\T"X"qnu[v1#`so)Qqn nXH)_:$3qQV ? K g  kH,0nb`XZXP%%p K sg> &|Rfs={~#]=/E<9rI6_p|q9*_\7[#[Jq>'S:܉/n|d,"hA*x*_\']LnG g|t8o^5_MQb$ .#k|"§P*_p_lMNQ )kYE>bD\Ś*nqa}HTXܻyH3k9_|rj⯭|1n%Y<⌳d\0^9A8)ܱ*_Rs+YRݿbxX/Pw5>U=]56E:_ 2BXIVO%k|$?7wT€z;.v_!'1._|qI/5{~4qƎWlqm]b'F/5kG9$Y3S勛$Y8n9IV  T]ڳ!wc+2eѻĽb'aNu/GKQ۽WK.!ܼ8ޭh)^8pf/-rK{w/˺{o)P2#7gAu/G{9 ?-TҀr>-P r^ZE*]e֘drU?V 00\V9C]ө9K}3ziJ#MN%N'sIHg[a=:0: vUT0gY oJ5Y9)}u[ l.4+U&,7)4*o? j0V}9(okFus?GzPFk-wC;3ݝټ+NԿI8.FC3k'ʰ U6A6I*+sJ"HpهpQ(⾞vGw.0Ddzyc5Q`3:đ&EDƈhu١qIaDKkcKP"dfg=ZN|Vݳ{g}x%Έ*]zF41f9jSyZxgG&vOW9Ӳ\Fi]q{{q?)nJ#o<qTVۂ6?azIuyV ρ7FuyK9O$XzBܷu# %mTd8~yb ς |4*j_X'N{d<Қ/Ch ܙ=Lg%gHǬSykqݢ3|4i{u=ţ+DG17Ɉ~lZKw~ཛྷ}3,#!*H5hhyKi2&mNv/8,WK>Hi"#~DuNKHNwL# Ƌ3XL4OQIܾ8 /P_mOC+ 0;o-.!{z%|xz>gxim&Bg6/?kv#bE^&=7_*u>38lHs;#GY<b 6;lgjwku?@??s2-1?v;;[|~^~~&@7"^׃[z1zއ*iiz.wi0ܥ:G=ޟQ]HؗW!m_CsiPw%e^[_8Uu;Ǿ1.?DSSۧR3Ϳ3}1Jw!W9vfG_.gt ;?}Ly]p~B(9}D{WqxJςV&>Pә4⃒(İ8<^1ǁv<*n8g剴^i? DMbBKcTcg="2F v]v@o ߕrVMpP,p lQ |ʠQ&vl=?Ǽ,w [[||nu튁gG;`Lە{6̼3b؝d!j2}ÀYk@K?f48];PGw?;d*MNxZ=ja1~Λ8y!Ns&5]Cj`\Gr@KiF?O ݜ k_O4glцt,ZwNDq?KlG$EwGQGd?<.h19v,zk?Qˏsa7|A~!ot^itD[S~T~E2O3syL]:?*JdwB:J$8\^=6u"l4'9 ? EG։Ok9?e3r&^<#EKvf+`_8ȟ*]u1;gY&Wi;Uyqi!ڌobbT&r1{> #hW YFgHS8/6C^kb3AyI7??^2(f?Y1ۯAy+#D?O!H*?Gu u&BGNG\&wp<4N'[ׁuw'^L5i:cC~~~^oG rwR{G˙fPQ}HB Ӷ&,j"遈o ?F]7Eˈvʢ h~+.F9wvqUZ݃{& ={.x Jϭ$}p}&* l$ާQ0gAmm ]\?ATU/i?{eNG-ʥ5;W(}M |f#L EM .#2pz91&#I ſ,OAWmO3Ҕ R PΈ=ܛ?V޵ނMюV Xeேnc2pXS*y~p<.PJry0<#N+rxJDϙ#ϣ(Q| 5%K^Nk%@&S9޳c2 Tx~G$|(LU)qk|Fs|~>|7'ڎt#sy~:2K =G2*ʢj*o_ DLxl"{a7 |q|o4Sψ16/O_еs?k Z$#Љg !0n+z|r3.>pzT?*fv޾h?=7ٮ?#֯,xfP%>o&vZ=ah-ۻDfLsF\x1p[: 7{!ߪ ~5!9{P_XIN#L!MLIO(0}`Z0|,FҶՔLFeo6(έ_ :N8kohtg/cll0|Xg}>->=<XƧk_A ?ORoT|@F&5A>9.{?YeRƗӲ\9=.5'Qjq!]hT3u{DaO& +Jx~6)AoR،ۻD^6KUD4svu|Oˤ{M3]^߀ꟃSѽmac>hzIݿzm$~oDd(Bto˳ c|$}̳x?{o{HǁSo1?2^|0{1cNϯxXʋo$^mG½v)D2юMG/ Tmgycy$mA69;^LFxozoOy$?нmw-kQޖs$m{%)DH%}R/Loզ,W/whvӻw7Bh12wy9wms:\u~mfHI]>;-?!斧n䖧,/C #OO5![/aeD;x,޳ g$2`0ݗ>|Uh7ַjq.ޣmr8oAǢߋ3tЪo3*+tz2LeALgg/|>_#y`q?yγx~%Ƀ,X?~ n Ep"y`ᛳZ~Htp'7I ^|G, '@|߹ʖҹ\WaN3~/{@o*r&1 :$.L"xQ>],?i<g>~3`^*w8sj=1YOfwX N;,c\ߞ^B?/5%ַأt?9}#L H 8N7aoOwdM/"g}ȼy_PbΧ5k (OPEsxgzMNCy#pfR՟m5|5jJ=5=3"g5<܊&OPglg~j^3p_a~: IԈ1֤s#,[ç50\3ٔ{YS;v&}n6}"߻{^^A%t/'E^g2|ƽ{R>?'r^z/Xxgo</}ŬT q ;i~[Y _z?u~Dטt K ?+~D9'Wc^F1m]Oy 6(#4sEK3 ym.`w63Gb^py] BP|4㛏O XǼ[nл1ps߭Uyvȃb%´ʦƃ>2Ehʃu%ǿyȃ|kٞvu-kM%l(:q!1NyP犴 F:3i.vD^N;Ȼ 7?dcl5ss|Gclk#N#3u{4;\]y_n>,e>W#l->]*9/׬c6@E[}A/_JR· wر]=Б=j6B6!U 檥ZUv9"ya3h.}n*;M=^;![Sb9+5ߤt՗0ɒ:tfF}T=ag$ oq 1m(b ?/2#;+ur-(>Gӯ8ju<5}__Qǥ39LC!$&ߞI4Ig4WljM!n1^: w0]oƔ; cKw5u9֫˪LfoD:7)ᬤ!}*-?[}Yj fx<(]9^_bwj4qz޿f#o[ܝ\O2;go>fbVU;J{֯ڥOjwMuK6MF< vRC;mӦY@z.r7uQHw^3FKT|>v &'ql8UTy n~W}W=\ :vQ:yg㾙n(/4+[>X_tQߋE+Grٱ/̻1PWލnI\ v3JoڮE:Fw-DցOv~~3ۋsM+'N7X8[ٿ{How0hoPyHh`' H& 'p'~AWg!nOT^~|CތP:I˓nu/ 濡BO.IdS2hkry֢\UjQX5ϐƼQ$kV)/ȵ9;>4 ,paOO@p#$Z$ܑT @C>%s pWy)ko[m~cZ57eUo󛼐*tV "wOm/ y}Jͭ"OO霿 {}?!)ZyŠ,Q =2,=2+f0RHvOBiU6|M'T5p`8_7n:%~D.47R}k=g|H;{>9j?r`*?G4њޱ GG}>lFm%*fL|QƇ_Xa3>>3BVW GXR3z5^nл|x|dD>^BUT'hM3}4EC. dp~*|h5Ƌ|t2*Xa#tYCmzM*;MC/\F| 䯕'Dk> n"fLju^$۝+5{: ^/5fAl/qԂ2#ƱءГ98vlҟ@;{aGq,cc5 vɗ?!H;qZC5!E+=z~*s+1Cv}hl)+u^^b0aR={|mԿgvyiNwd(ʘaD+G׎2u/FςM'ޠ2uH)SP)qYR<rocZ:50[J.ύnp {ׇZecwIPs ګk=S{7) ֏hJW' {D;ղ>j#_pg/|_9/\mg=TgݗwJ䫫(2P=?Ubv5^0k`4qg~Hۦύ)WX|w-]ca,#Jz.szdh].Èo0S2]YA?6 t_LŜv2ߟq.;.?_i*?L,p7 uW\ֱ[z7wqJwjUz-8IWU_mJEztvMDz-赬Dײ^uo]K{kjvH5 rySkE<*^ITz^(7 RRHguM'z?^^^uEWNNٝxxHXӫeޥEk<2>Z%)h/Y?_#?׾A{sG(bcBŧHD+Z##ǻrq|Y`0N%wy'B篒;v[0b5կ,3pulg9^]ȿp Zq*#VK!Tޜb;\'h/6g ר4ld/F1!KrKŽh/{JҾ?ߩPҀr< " {# PrI^/ͨ{A^v0Ş/2Uh_zmobe}IZ?…}=do_%{)EXp;:Y% ??z*4+~S|˺"Dnj/rysڋ>P{ϨM?[6r0Ogطˈ<Wmt~`] \9wwh w@/"07ngy nQ @/P[,05f@IY }̲0g}Lu's3/P={3x >G$shx v& txcʗ7rWu:jYGMm`9E[_ՄxgXP{u#:du\huO}֜l1~N{:CZs)nŃ(܄9خ1wDo0h;}t2x^UD{vw;QҌjR"uz,L8_4c7wGϕ`<ۍy(n f k~7NtP,*tў=>Cf۬'II~)93~i{ lQ.A:L6`b0x+M_TCu>{QKп8 ,]4,?b}}>_\/b#9R lYҵ8s9_ٻY2.j<:t\w#_o7f SRD[ wU9NjYCҺ!/$ؽ:s/X!Zҩܪq2xWƁs u'w:-g5wTs~]&]]6]NBZ鉊p!Z)NS?䋉KNkt\w&.!;=*ߘ7%コY?iwx j# Q<3-{VUo;\we[(sFSžO*,e/7ɦ)BO#v?،%fR|O' %oquOP߫R]l-!TL:ꔣ nQk:SYvs9,(O!緤6;OOO;OY>R96= uč0yz Q?Cw&85IŽ!־ۗ5WOԋwBD_T 忮8&|}j69ކ_WoxC7+<zȲc]Ϗ8,ǖ&}]cK`-/$t~"$ ٥޹w~ &r:tZ?~.\(s9x(翀VœWpd&A@]GgS_tTϫ=,'8+Yz:z@`u鹇$r ?e?~LVB >R#7vރ+,޵pmwFqqX+^'@NJYgAZDWvcB,|e‡xG3\s!7ߜ>Pȯ"23Wf͛C ҾCA>m7e8a:H>wTW21}bGf1[Oqg1}Sc>[wSMdz(oŽU>f}26|C?_~ޞB4~5;ʧW!Wz酳Cklyx~2!>O/E\cLL>~ϖ|kzVi/(i.oi0bs'gZؿOKo __u&_ɌJG;2/wkO.x>ό<="g-vj/?GǟLQ<{?MZ ]\ yOO?|n:ʲԮu]Gy4iҨ8@" (wdˈsFtxWn,b<\GA}tzѴ2x6_:nso)m }foe:ʣ>Ur퓹y/Re(u|z(0g {sƑ?Y}f^w_$O8QIF:[>S\q=bU?4:Hn3mr n7*p-{\2>c=w7Uvݿ)2mHOo#G})2s;u{uv4g(A%YUD=B"6@Ms\F pJ"5*]3J;Ls'z\slvjwz@{9$&/n/?,•/[(_}΢g ;!p+05yѦy]_p+׿pq[D*()\fw֫wiV1ܲK. b7wu܈!ɿJ?blAqfjobn!c9| `3t*/C_M%f/Z%>pKq)\wPiE23+g>MɻYӷ|2|^n;Cn =:Uq.s. f;(7VW{.6UX?LU}GSS|_>co!ZNxzB.z^ϘY7~\>f71>?zW;a_Oq2>/@?&Z63<\ܛ1}TFEsؾBN[<Qu⩱Wri 58G볻\7]o34h/9Iy$\<M)ܑGdpyÝ_'υ^~9s UF&8Q>\{~FKE5ܘrTKpMA?'?'{̞S,~u,Ij,.+SVurٽJWaYw\N eDWA.@~$qGs :rWqڵ#eƉ=+'-VJq*?T̀\¾Aso3C{-2< A=}E9ϑswWM Z{#?|dgnUpfiIޭwQJ{8MiE=RIc*yzez5\kaz\wӪ=p ;Ps3v+X?? QdF{/m:.5w\qƼp؋$a/Bxq&ۋ7{ ?~;Cn? 7\(kAЇwXjL4cXb>!zeֿd|QCļ jG5W1mY^BsuKcmpfn{1uv?k(oֿ.v`oߡv]r3/ߪY?s5d$!]?c/vwYcָ}gA4?=AOoeȑh){#[?&׏-!ґ=O>a">N"ڄy*>crz(|zY`MN>}" T|*SgN3GcFiTzܾH\Db6q<z?ݾX ;:|ouCmyg4/:64~f<|\屴zFD]Nqʖr^Bz8w?&_Sow@ߣ]CߘeHKϏʆ?P?Ϗ26E4 w3Qz ?o1&. ?g:ɣ?<\!o$TFƞҿq%*NGn䭺 =+P4"ly ƻ)Df5f\48phH)b4,靯4x|kT%D\_Aon.M?RodpAz|1C7dTmkFCl4zktͱ{a/^ٞkck|jᅦ~<;e2;\ ^r|~A?2KLY.?E ?iI'Fo/f.bq7֚3CLܠON2Ǻu\muyX`=Һú"غn!Pc]SuݶǺ΃u!/p3zZuq]sغn\ 2k*u+ugz ?KW=_F*; mY/'\/;e=qt.=cƅ$DK,-ed*TJ{=*Q[eP}vl6wg.m&3qqInϦY<[J]#=Bf< wd7M﫭}E~7ߕz-^Dt ^(>uHw{#ӛ{KgA|vOgnUGUNqy㓳Wr.#nAcM\^*oliH W=>:#9NgLY!_@&[%qsu7OGRl Z~uwI?P`}>wsz$1z<_3|YwJE|]G GST#kc׏r'5鈴%3SZ?>nM2N0z<3|vf"|)Dgm\f T} lG*n4A,1 >8sq? ["^YmlǨi*N7d8}RF44N\?&I bzSy! ʧ~ZpT8Ө'Ӭ1{S>Aԙx3ox#3uom@<_/>S78g ^a=SFwM8SҬ6\ffDm@G4#i" P݇aosůiA43b'6&=k`]2H`1 U:z t,@GHtL5%p~XQz7aD=ׇUz8G/?{pc3vMK>c/U]&뎩 h3?g={ص-gE {>Ri6Kq]ֵDvJ~ kJ<Ȓ]ӬFs7ٵ"ͮ,E7?)?#m]͊H}'=Y\fjU iIнE0? ?4.?)vvM~"4W",N4y  -Ë|l"kU]E_]$Ҭ&hç4K4{4i̮iDfSͮ9,*ͼ ;t}f$3M}4{}yޥٖfMRi!ڔ/!ZER9(*bDtMU"70F4fi^ltoG_YL5lv7wiwN^].-$?@3<. giDf-?@Owϊ>YOMY}^[dBৡ8Cy4ѮH|W7كǀ|4?J,4`&d'@jTxN>l'!_){WDCHfvB4 ~Y7NO7.%:VxilƢwvV7F?*UR]@>bA+[EشhW5 G&mwWl;]Fif1yJzs=>IճDBGt>6A=NqMh w@ǐ6:;v$g.)cg׹I=U*]<ŭro솔0;^tvWr73.6zMɪ^HyYDV q=NME4& 4sg4fG4C tStwgA/d[hMu$(gz;\HX$j=#%[gcoUkTLHPyxu3vEʃ#DAIU*q>i ?`Y@,c%;ad%_zݻeTfAz$=ƒYi\O7mOFy2>xr:l#ʉDZpY/5ʜ \wt otP>OMEn_]p g˪\^s< zp!MyxqŁmυm4n1ۃ,l?7LiiI_зL/y@WgF.랗u;D֜TzIȻ} O)ۗ~(9I4}Ot6+m$72d\*t/fY` r7=0tU:k?n _$C.2eMpRɪ{ýI8$3=:^~[+u=}ksOC}[3hOQe_To ; -4Sfa<ݓbwX'BcD:h^va]xX'ﺀ~~Kz=zzk칹s9e!"^[EU>t5v/È9=EEWRe".+-D"²P,,ZIy; o%07#XYy z*hX?FH89" ɢ!wӤ=㉕6kZĀ"Rjo v/բL|Ȝ6Y/C|vĩZ&ϦSd`_ANT|GdIԾ>Knpǝ(9)+peGNd\%=8Vn85N1:[ZgoO;,2j&秸_E2>Kw Oq.#f^_c&r嚿/-bzϔ/Q'`qRއգjm"?hf40&od+`6a&c}w L?xIRK(0q~@ߎLf?`ʗ/{cfo?v߫?UPz~l{pX;]~Qr3Bq3oxƣȉϜc) >™#`9JO!DN~d e{LϝamyKC"HB: @ [E] *O} 8ʃ-Ogp7/^ sȷB:ыsӉ֩:Q.Gꈣ?};0Eq( NdE%sю-w۷!wOIs8,K5)\3+FR _ 8xZ7{i!~Ujz6Z^' u[rf{iE{p<;S~R -n{R^6~]j<-F̓t :^"Z.טS88~r䃤1%PfyZ'S;wSJw\=#ӓ/ ”9dh{س֞Ӟ[|ru žiZqXB?/mB ̭žk՟#j ZI7Xˮ6O1q$դ'/_t~no-HSyUnu10+:\|V+ջ~QIo,L'Fg߸ =?I]cGM]szHQKnt^?us;~]oBv{( &͙T$˿0ɤʿf"Z= >݄ECA$QZ|ҖQԞ9|JL7 f?vlMGZZŵ`m~/6M" ?36نx.Cencs_NKXynŢ|3_dC(<Y{gy}T>m)7?fZhGK3F!_\ol3Ջ=Ө7Ȍ:OS ~IoD o+?\T7?Z6i )kϔVtؙo`T3U7s4!Zk3Pm0i=[lY*͛,b9f;u9w.|;tυހG5"3 ʉ E1辡}d{!ٶ~6zG_$>>slj\}]>ЌJn Np Q$lsŽ E`+Y0n$s&Ocx I3qvXy 0\@D 3%/K3|a6@|`.<߆>}Qg?`q/|39}B.ǣ~쿞>)f\-јWg6:_s:Ap_E? 8~-\}xAWEbX6_>ݗ}>"_Gnc([v}t}s1;W?Fu  6Vjo6C[]?TOmF fM}`rv~Qqn?Tn,yY;:^>C-Zö)Sϙ 80ɀz/ۂތO'Zk[W2@l3!2)O|~v~=a;~w>dzt= /6\?ʳ-U:VM:[%ם~u]G϶qMt*y*?fw󌣺]}ҳ[ =MyjTI.u6ZXh{gB1fBzޥGoz^Q7]1'wqP.uGat 3-\"ji_[]M<]og~3?/u^_u&u~IYK1TZ5" =Luv?iSʾNIE3#Eﺀ1.4Uimo~gM wޥbÒs`y\^?tZ?Kϛ|?oz ZWw* w<܅wÿ- ЪWCCD>28Qi,=yfnג_1qa4L&pFCESi,;!0OVDDïiq7?K>ȧhf>l3i|)-&q ax8|_ū>>}geO2hc`#O_ZէUV3Oi'5lFZ kŕCR vʃ_EY`6{-%oʗq\;鳫$?Kcd#TY&U|)GKng5kYf-ce8 , &#=1=yM/74{j~Ŝ}XP/?qd\F5Do?@mV~gyyj!/Mt)5ʯ\c<]Sjנs\2OoMuc˰}ҍ:fJ>5,c5ɹJ~3MB dޘ{ڼt=Lm^t|T=Wz=G3Uɲ8*~5LX]%}ӏ{Dfi:yY=Z0T&mn{ jL)zYO:I5@? wMgd*WI̻uq~=R2'/>X:c?{upǏ:k?/`~5R^V "P|/{:אzs;]Cv=2u? y18As\3A4EE: _ r)c7 iuʅ&z@/s9,PwA75Ki8A3'XOQ _Fz ac6z/ ? B o?ӓ'POHMZ)癞Փ0{97GK9j߮) s[">c?? 'LNF9'y[xl͛tUKOb#.Pl!e~w[x>m9}OGwz6ߵޅMn}ֻmm5]oZX\ԻX>=^>m6;kcWƯzw`w[xyB˕LQn8P6zHoYWzW#0Wֻ0+h_ӏkenk m_w[rx2M;']D`?_FX者]U~ջi_u_weԪ}˫xO;+P>}-}}2ީ@ݼPֻ>~cSCw2z?׻b'ߜtɬo`DzwW:ym6Yv u{壿П`pmw=g!w {__&spw?z]e ֻM y۔#.aˬ#.w6wz0z1XO:ܽzw?zMY>2;zE//z逿 eCggpP?Zֻm<gYj7|xcd0׻k*\5 y{G}+띓.w^TԻ8wJ}xݴ~&?Pzuw]@`)Lo.(yF|w_zn1Hֻm<&Ziow넻i\]@ wa[_zNޙXY;nRzn l?=lꝽ7ջPY>νcu Yjso#?z&3͔nxY&|JYw|\b_(orw%ޕWb`wzˋI27wXֆ׻!z~:zf/e{_{qk:dǽv&…rzW {9HYEZiaY[ձA/޽_"띓.w]ֻV׻V1QջR9DֻJ! z{M_sw @y7CzYV @ˀZY%ݧ9z5Uֻ1uw+y+zW] Yt;ϬuѻDw׻Ճn`mWs ޽#ĽNuuYq/w&y&zUgeqH^zNwTz礋o*]ֻb)WFeS1RֻUB@(>M_uK[w?/l^<ꪽ25sKSm@?kVCw9Sb[ńȓـ_ǦOZ1yD޽9ܶy [<5<Ï^2vls_}L6.SgBVMi̸t%P7γyۧ3ɼ1uWfvk%PygiryE9V2x8Ly>ըg M JwgvG-i soԕ}+YີQosr!~my*{gZ,{"˓qi @; 44f?=h"Ċ3;zcLfDG&ɤ~w׳Sf⿟Q!M^?IͩD\snlƺ:#jKC~_gEzwVW pN]vdMQO cxѽ^x@il!0~Z״ wvZvR "9yaןp*'l|dqT}El;q\qw%=zT܋Bng",X4)ckXH㜯E!US|~JANR#=O\殀+H[(Cf;P.ZF0d%RsxZ(=fٴ =HI z2|ă6U\#[:?N_3 /1ewߣ5! =A󀥥' N{8s =zD*5m^o qe" ;kZr'u^1:WV9v໋ͮXBOXk(M=7⛅ir@b Mzc"6W42P8N>|qrY#(N&GAV+DMʌpRq?]MYGP 8[f\|Yc˽hek9E|}uWw}c>_}HI /$LpԮz/^45Xm=~ngl}hC/Ϗ} `ˡC}8W+ eCr hEӍxsǝf\?{,71Q7Nnџc^uc>3 gEb.{*)]%[iO ľyH}5 ӕ?M/ Bt9"1t y,Ӂbh1O|_@o>"upt7&i}4Fcc o?ToK Kd}0/"9󿝇M[O?/Queoo GEoAtҿ>eКMӀB ߟAm;wV|~wR9d<'{9$O2}sAQA~? O)1ytw1=WO_=Odl yW03?Nп_Eޞtzw&u(ً$26 rKy㬣cgJ5s@ebˀ:͸\I?KiSIq_3zm_=g=W!.̉M)DϤbLYdHjG'Ҙ>rX?_;;mJ#mF ML D[^unZ_/LkZ/v3QΨ2srxsH5p_+ap.;=x̾:8lo6F`=Q&+x5ʡl,cs#i26w 87K-mcln9m\}n%6%671gM.x{)>bs_2ov6'6ɵ0m6朴%SS͍ȍ=܅͍v4{~ϟ؜hsݞ^+ܬ3] 9CdY Pw'M%del@f\bs;ߒ\qb"7͸v2K"dK繶66lsGls{|fi;xҵm ͊mI:(mot ܬmnfc;h?Sۜhsڻ=9&yi$neBgng?TpέWu1I7:*3Y/ %ᬻ^'P2n")n%V~G]V ne~9zP/`W #g5n#v[ˈgBtxھ#9YBwd}1翈E?b7Kn1)kDbM$P9kY#`' z"^*?@|5-Y`zkzjY@lL+w»sv"ׯr=u@vnxY;_|QlKx;ߌN|+۹6.cpf\bۘ33d;3ϵyY2v>b[hl^gfUalmfv1'igLtCLWscy;|멽?Ms']?a_\yF{;2}By;w+9zYΝ v[ӭv~VW05|C|vJ@7#1 ob__Z (lX/ ~:m@|v@ ~eFeU+c6ٛ?n <kcPooo oD2u˕L 29|##&sNLǜ+&c b8/Y¹Z rߋ(6Oc:go^I9ȏW:OVNu PLy!}AJe2>ޝ}!Yd׳%@}\y?Sg< <z`(Lu ^ob.`x^=u1<_G}x[ Ӆ߻!t/35HIA<hkF;L{X :)cw1Y,$|&[y>uRlO`z6W&~f=fTͲY߃ľeB1IX%w8ᤋ*&=G9Y+ўX\j#d2ɓL>dO)yNNNke6*HY^MJRQ3e̜H_^6B/_![Lk"f9cx>owafRib2fN8z|P'yW+6c愣3[O1s#$?|SXW2Og1F3?3?c=cY&!Od3]`,p;k_)}v |Cd̜"˙1sj3?ry@Nf.go?sC֫qZcbcb3IT'!cfB/'u\/eUԿzz1fw"P)*c${C P _ b&5]u3[6y2ys!2fޗPT/CE̼ڽGyM/clCU@ "^gO.`lK=\Z=Ó}׿ ֿa[Ƭ?{, (nf<2C@+I,Zdsw?yDPĜO?@Zf"yŐ?t-a̮3c=e5M`YfQl4S(lO)*q-ry(2//2sEd cOy!R-r^fweeuwjYf7OYٷ:Aل '2Kekefm2=Ѳ̜t2?EY&,27֯*WfG z<逼Ըa̜8^V9~p GzCaz \ Ի _ //3//]܏Jw='#u'8YXk#fYaşsGe֛@.`! <(wxtؠä9qg:5b׿3y6k!T1c.=;9@M$4G-j)/5@q_BOGHoyz,*2#x|l_ay̖!'qR#Ծk6"zQ@ucy=P?q\=9{Xh_٦ou⳵@m^Ysyblӷ }D^;ڦ_mƽئcym^w\M_Ʀ2]8c~u[yoeP+,YuPo2#aLeY!e?/,Xf-ev|YfN0/'D܁eĽ" e^S2n ]QY j8F#e?$'5{k<<=d^`kȓ(Oڻ{y˜y-' f3_c k-i8ƐS{3x#cuPo1'|x1aq+=̙H1 yZ xs_cc j<[zkfw*-'!bk]Bl855S~n^|y31u~`5_?%|/P}1nԛ  f1\P{Yܕez/p9~пcg~w/Gh|R!lo,?ܷPkđq'Ss\dD'\Ø\ ,98{{LnrybYLe8XyY/˹TuFi|e(7m6Re?^ͼ/>`o87Ig]Μ!qg_io]?{}]Re'2dE y 3fйw,p+/2˯e ,b/,3']DfoLk5n2 ^f2+jo`~Kf?̞?{u/du/v|lex Q2OQ"dxb_#>k$~5ȄYdYwf57@d]Ogw.C+ߝ)w Yj@8O<^R>ߓ<>3F_H񼮝Tu>Dny}7ZqQMt2n(7Vw%R_H"?L7>cԿf4PÅ{_f?Ur. noNԅ,c]u!l8Sj16?*Jm\q#e]UJg?Ɗbօ0)3]fH3z/ ao3cd?^{kMGi5m c=BuQD*VJ(r&#[\~6cg t$iSuw!=r 3;T'5^Q-bKlO:s{!Cs;Ϥ&P?BsL4ٶ,Bϑ@w#:QtBB}/dgFYSrFkXˬW 5̮e.Rua&YAHVfepi+2PYV5,}x0_E2Ok/'Rye椋,b7#5Xfˬ_^:co-Խ2۸b`rكe@gp9H8|9/wsG)7ܷ  2EN,va#I+8;A_&O“^Jƅ4x{s\bWaOTРf+qM⚄[(ۯ0VP_4Lӫwv98cE_UqJwgf:F6.# s\20n>^f}`Z2e@Ao7d6PY+3\cL]?ϧ8{%#o<?Od$?Gp0J\¹$"OFo{z9cGѻTf$u]$zYqc踯Wwq>$1oCf׻+p}||ֻ)IaCsoxPzyk1HCqE /eӁzAP!rSfp,m\FH7yzYo<^N`yZ6 e@_sxB1sL7RC_c\2SpȓY3n\?Nϗ7~n~w6vXtY^SvEzM!㲳ϴAZKMm&lut5Ul2<.;+ڠmKͻߨoQ}q=H7Ȃz۶W_ O yD0=s˟3-ߣ͸D7`z]Yc|8;2 <bwbwt~ɬ~՛'l 1?Ağ5ےQ7:FV[*5,UfW ljެ/1H66 ݁wۀ!qMZjm46!46ch'\ʧ~:o5>dd;^0TW5'0?PԷzs,7D?t çri:ݞǪ ٗA @="#e_g-e_s=ˤ8߲//}عH˘tܹ7vE6Zfܗ<\o\)ܹ~KV^ν:?hu~iKy:^ :ByΞ{YFu8X=wo;_eZt:k% 9ioDth1\ F{dZmx/ڂr\fR^e_7Yo"ֵK>Y]D^N]a]D`/jZp?^롮07t]@to5՜4Lx̜p@~"3ҡ׆96O-K mvu} Qn2sƥs0ԟB[9 2#$sf2/0)nEql76ˇ@*LJyTx*>^ 1ջA|qW)%pbTSoFٖwv }+;Α'gϳ;6jlg[硚Gǚ8-:ez!ߨo's餧yɇf;6N̟nww08v5-qB1qq5(SlC+qI.8 +{ &F3׶8t!ǡc]a<bǡ n"84qxcu!bCuCqo3dP @9_'8q/xkЄzn 8TP<6Cgd8@qhCJ1qB"/W_qKnCsNqνC"\ЅL8CyB&ơE ]!ڂq(/~C(y5߉qdP~ 8t]!|]18t5 M84(md{z2א? C8HrpdJ$q+P ]l@~(&52`3g3Ɵ>mdskuXĹ1l?yyRRBpş< y?xlWĤe<"c˴[.P[v@Q<>|~>o2-ޚc W [z'DƖs͔K>7)h`cijxlkRǖ3ev-F2.ǖcrvŖz1\+c˙<̎ߘ$۰p^G2R[Ɩ<^[Ը`KL.-,-9[0_[p-󌱥2[l%("ut%okl9Sc}m2DRlYbˑ [ r,-oFr&EƖ2@]p-g\a֬ c W [̵_ɥ_-׽~ޯ9o-O/8ޯ3~~]H*_r!(_s$ǖ}7"d]t3sgc]y-GxH?ޅt>!9د5ƚcyT~͑|k2JkĹ=ѵ_s$ǚص_ӿbB5X{/ƚ_39GCx9ĂiKH_?GJγ=Ok$k4{a{ׯ15̬~͏ߡ_sg9k-J?Ş^Tʅ_co{AR_.72o(5?M;JxJ=?ET6ɯ ,|_د#5֤t3ƚO~͏yI2ֈsAN]jqcѲ_B5QcT5byfl=ğ< 2@]pدq> '}yl*a?k~hth`?gv_c>[frp1LcKt-<|7Pl0Ɩ2[eq =N]쐱[FLr-#byl VrI`"az^`n:[ƖPb<[~](c5<< ("2`-֓2L-Ŗ[|`l?1Eorp2-Fu%6s[ >Vc W [[<ly"[%5L4e>>:>|7b8f l9S"Ker=P6|r q29fP[n3Υ<Զal7ϥgp夋`Х6riq4y8&rky|\s:BΥٗc㓀7Wq-߄l.;pcϓsi1QX:+0J45ci.>f_"Υ>?8_$J޸̥fK?siho}{ R\ wKCEݚKvkJ/]8nnnnn>o8diMb77vdcjc7xJ1Mc½_M*t?$vS+M^7t OaΤ~gQH6-vc n9&vӥyxtJ?nfǣG뀲[z}xnKyτ?y',$dK?' d0SU`93N< lxN {~ũ$ʷ=~t?'w{wr>\DcJŏO:\ jusMKdgZn%}&a%}+Kd]܄uXה;.>G| @[0& (ո߇ˌO?}I]?N>&jKD?Ldm$PGuy9?6M*59ZdsT?3^ۗ{gC!ͩϳ7PwoH rCӝcpc5ץm̘1#52&VMX;H׼T/w7YMHޥh>ing_fw:,7͸W3_GIټztw2Z5نvqpnƿO?:Bߚ{w@~߹8JCۮ۝Egzbe`=pv}4=Ez w%8PjxeVٔ?o /s;֥FfcVx`قDNId=ʣ>9Q]\cXEsՎV_XX#SN}߳o/ϋokww/@p)P&7±.2oO ]cf{ǜ۶\c?}=fuԖh [sہᨆ;Mwߡw_E0i |8zŖfij dln[GѓQp† |(_J_ }%j@_)O ꨂ {QjMc#!]/7B+_#y▝t'Fؗ¹V|0K_*7 fmҌu|,wqrjܖS#0oJUkW5t/lZ\7ffw"ٷ_ocH8[Ľ݂5/)zRT)ysӟ !~fQO.PO/x4Y#5]u͕U?fkб=uٲ'Fg]|2q]L}~]ϖf\E׹1u@u'9TZz.tcw3uҋGz1,p{4fy+YDZȾr\q#c\ucF>Ec;z,nO)cA14Q};N2~Ƹե3ѥ8k^j%u)blh:k"/[S~z5jP֏a* gBl{sܽ1'Xc9YuA"t$Wx{ :=F e8:gYW6+g"ٗlL >8fI`?"'_ڼ5Wro_S ]V?/X_`ڷm!U֘) :} )cSON3Gi]FK\5)Y5\;Jf0W窲t5C֤S rxt<}?vFK}gNLy$2$+yy+󺝯c\_NtD|v>SxjPpN7G$$*Wz Nmy`zpf%2} bJ7'*uCs&T$*QOn6g'K̢Sr93c^68ˡg?2{w%Yx|7~SsY'%aL&)G:$8 (V8RLkTQ]xƢaG|}wCac=&?ZˁN/O]˃W:U=ypqlg(n4AdP6ߴNrH|"p͸daYr$Nx+G>dvĢ4{Jl_8g&+Nߦp`$'[!tMִNN䤡E P>?e(y>LO!F3ґP67C hNN9UxW l!k1#~[Ar(1 u嫦۔z-iFcm C =z 0&_-I.aK #V 8Ehq+p! Uüスbv8s ӽwl({v{(>哮儱g*]76ϭs^yZ/ˮH֚:?nBt[my/8 ږw-h]X8:z> x9Ol`c-aHrW9i~WWd_.MƾݛKRnw-Lw~tpHy8G/zZy@O]/ofeXckS_^},!7ʾs&ȯ ݻ__m,jrN^f7veE56^f'iS[di22J ?q\d?[fYq&YpVمA;̤2#2Uێ;aѹ͏8%ϳYBtSds^F7UzvC,#w@MNߢ pm(n ^350-a0OkvwhJuԡM@y59ﻠ/Om&wO:o!C}o+s{s>XFCO>α7!E?F8kf=/ ?@Rt59ϛE.䜠;K$o  %ԓ?_~|n?P^,f(N0)LT<wiqu57"D~6*/^^~cR쓛Crl^yT_f4e#-lpWX~ Z /;O)#M~9wس : ;_Uy] I.k%.ޢgϲPCD9rS-! !gp7XjsS_?e0n`O#arE<>ksA~?FȞQ9;4GuG|83J|5=jgEcп;sO]\mw1gq;^֐34((9sE?1>9%v.^~#,4~ދUrmοYe'bymQ5mz1zcg :by Zm2m+ڟ2E[ '3̢D_@}8OD{ueL0@Ɯaٹ9DŽz|iP|L\wR_Rꀲ׼ݗץFoKڸ1̸3܌Kq<3h8GZqt0F\|GAh\WKaQKQK2(Sy+o}Y;f\2O?0uˣp=UQ:(:i\W=ulۗ9O  q'9Jm9iQ>)"|2|JA|F{j2pMq/\F}W"GC?{$|uk<䟏ˇ_= ?+AiW80Hg^Fen#\(dǜ0pz'NWz9 !oL+^^i{g?T8B7Ob#UZMcz!* @Xs.7w¿7cse#Boᾮgտ;tJzcw=HN}^=('y7:n] "/V^é^MĿ=PS/y}K䎈 mq8>ҼgsF[0K)PLE6#x'kigd/^c??PNf? w@wck˞? -E_&: bzEqΛ@,TN|lx&]0VlU' wz9ٚEjND3hv~# uZ;bo~ߣڒ}hGb}ަaksB/OM}{W}t;ݻ}ˤޅb|]}ޖvz(օO'f__iJfL{Pv5ݍ4X{տi$kWfZck5sr;/fɴ]D> Si/iwQ u!k鱁 `+if^&GLͫ} ,oz =ǜRO谟ʛ1sgʼьlIl5!,2q{x}FqXyUr'H) m2q=T1?,,{Gv Rsw̭6'[TqԿqMߐ.erKq껖Sgtѷ(s60Hr0|ꯦSԞbrK}_W1rKt+&$S ; )[Hn99O[G:pNe4OjyJWb0WT%^ƞEyݹoIxciwH譍[^[ǰ0{(w2lRsF#3 匟~6%{jsLZsO9F{#'|eBi_׎]hGS`> j lZ<1}&[7ܻuy^6|zz|g=5`.f: }] :?U= I!ҒBSqD|qk_ P;yy9VN홛o3-Z Ʒ$WqIx^1Z݃U3XXg%@GY[l 7ŸHfbŌ.Zɿ8;;(AMp1{WNk:ٿ9ڨIxL&dNIIDYiPOpJ˯SPJA#_!BC.%GBߎ'9 @| ǏY< >7x {Z߼1u2تLߛ߃- jZet> cəJbOƟN&c{g1>9S/Ns' 4w8wr$ΑϢ</%6g\3lW1y9{>H7 \@!wj}긤"OAb1yF[ɪKzh+_Em\܇3ga5y`S^v=|b*IkV VsL#"[s:WRo׹Us,vݘfIk+y>]ԅ $;{~p8G܏ފ=}: 3ݮs8s׵].-Q^"),fb*UUgedҕ2ot"e'BFu?" w.#9l&]XZٻj ~-\`}k{P~{^g;j{[JLt9}*-Z;tWWWV푗y>eFg=o0kvBʣ﫵HÁx "ت@Z5v[+bMO(rߕ#ƛߏ챦<1'd;v+]&.LaN𸮲>%ִ?=I̸bMH_k}8fNѝynb){#֚>b~tY_>*N@)lӛֱe8L[P{|H_֖mAAg(+_aGRCHQmA>Bu*I׏g{Xo+t,A袯=Ͳ1|(}GW<Pv/ؙ;uTbadwyyKv==5cSNX Uܾ3^%1:wxTR=XatA)UAsF6a(^s>帜YW҆rLrބ' uC3X*CF\|}Ѹҷp;C¹zf;/j_&:,;/oӶ<˼v^,Pyy[vysTr??̷r$k[^vqL΂oǰ[; Iv^t9/7"]Woe.r1O:/ 켼my١ބv^޴_7XL kK?}t9/kݬ?)]K:/ iU}3x\;/GQy+IÚuRyoIߵ#݉@wEy9"my.ݙ2z ac5\ʅ$p;/M.2@y?&v^ٰ)[fbAv^ޙrLtyi{|o]d[c 6w*_{ _o1X'û?w7=+Sݻ|Gշn}}y\_ !ξ,o>ܧ?E?׷2C?5J}F;4>7n5ҞLuܮŝ$^+pY5]RĈRyT/p{cs$qz|i8h^>U\Y|dh 9/yv<V,8ֶ9vCdJ0|9 `mK_.T̊,I ,ymmZ`?esa8 T]e 2ɖ2ۘ|&ɬ1S136S,:x2Jy&9:2ΉC5|wqdw fy]E¢<,څD17JÓz?܍}wO \kݡA>>K ?=o_g1C~2zL{n|$;_(n.=l,g g uT7\>;d/j=C?dM$t;]E>"w6|3j%f?|JBGk= f1zf q?IC@WtO%yLs?p5?Vz+~$tGQqNb/)owUNB4g .z y[e 99OzGqI<΄Sf{=_VݜaW',IoWWEJޕc[ `||~Ƨi㙤v? OUA\. (bוx?e13::5{t&+/>[xyo GZ"Z? X_뛱[of\1>ޅtMBiG#FXWgM`ӽkՂo4W{I|83^X u'{^!ugz'z_9@]ߋxuwK+щ xFkЬc1K֦?NzٽuSdo$U+&ߨ)ab sL`=7Wf޷W?h7}yXiR.ǛwJ^Fz׉ImۯS%xN~8p$s9[-wүTns tE-[׉Zա_g%׉M:qVQݰvܢ:1sGcfq]uVտ߱mul9oos^WՉ@9?\ei?8e̔V}Cs_8E9vq2^Sw.1wU ]z2.=|W_5m?,u]fUm'Nc<.i5/jUf}a.u l I!2Rl`Jp Lr_{m(3Ç~}{Fqo=rƫʭ#6&]o@uB^+߯ /s?BXi" .{Ii۞ߝ ~V?[OuU c1LisTY=J?iVRc`|~=>[`{b&3oVAiP^p tiNGHF/ڿ~L!upo7{}YJK?R .QuiArw":.t=~ F~X#v 7<Ȼo)MpI%gf5b.>AtPs&S5̥y.m?^$K,_ZzsT'm-2'XDfx6ś9EkE<:Ԅ%_XfxI1<uY_D͇x]tv]tQg'Go"sSaK{Zswf0W\o\;YLDףo9CZ;ڂ0F6–-~{+[.|ψO!~T\y,-\pz)~/DQ,_ڻ > ]\Z>?!mknEh\ykpFTX@e '=6y^ @ؾc"p5ByVT=z8Pfjyk.KIGIprnr{q2Tsc8~SlaÞb,&8T871#u`bxKpoTw|Gep | IN5"1X1tߎ~;)cp/_k6792|;q~gko9&755TJkE\\7~Βh(Dr>7"52Ps9v~@bZ),p%dh+jq\?عEq×[yλ?wRy2Dn`ʻ{ IR;Lw+\l].r_YŜ[.xko7{M]aXoHJoƲ^a?sTּ{\x=U{%|Ir\t,s`jd.GK]I= SXLF _oZ#D*2;;b~ c}QG_;Y05|~$>FGM?/|٦/sp"s}cM 4+q !T{Ďߠ1_Vkj̝z>/ly/ђ/X`/K1\yvOz4ş0Xe0z S1.=ύq~>qw%\Ny 9 A/ +Rn9ƩYYRmbY=k;+,WY xp~.jo|߸{3`ÐkD݄wdl].ㅨ㞳Lfta9ǹUu_YsUʐ+XZĢ䚑\c]e/f5dǜEW_[>&Ks7};=Q ӈ\3YyX#$|靃@'=nퟰ{NpMW/W_5w|*6Yfm'm{kKwf> xڗ" CX_Ŏ6 Ϡps;wƑsY+ڹ;s?as}3pƭ'(HJzaC&{89|ПJmfTseEg/'<~zX?;b1pl׈h5̸j3ܹL14'/GzuH.n7 2D9ѿ [ƿ#MIZ|z=lM7PQG{;ks/|$yk9x='{]kJ8QϤ{ w=7Tc;L4ۙH.\(k51o_Sb|׮*9[ܒ:fok _?蝑,毈Α:zFԑtᅙ$?pڦE州NyV}Ŷ˽z#ս}f[煙1ߝ-b&=;{{̌q^|`Qq:w1yΚA|ۅCE57BgOvgf{SE !>R7z+8,-t5A982pn-'Xz'K}߇ˈuon91l(Q"qQrA\=Cq;’\A|oϹfg~s\71( P>L@/ 0T0j@n<_| f3/N@"ǰͼo'u.r].ׅL2Y,/[ /,'s1N{Iβ^Ǫ()Rw^e1 ~7,Q`5ϏS,Rϟoo:j|Ǫ(Ltu5e!YB\}6|]|}dmabhΈ{Nxy}/GT;»nߙ' 3o=-)֮_:o]M53|8s˹9qYurh4$_̑3?-O >͜Y?t52Ny0Z7ԵS2[aOq5|gxĮbl ??njM9X_=dt1f>Н-`lmՇyi̲]˹,!;/f\.ܷK.`;β2@yy3lnZˍkyI22II,|;/Syyh&]8M2@y9Ŀǿ[ն|?2pEXs=*/o$߽Wyi%eYLr;/t7#C1myYם򲴌ń9vհPn :3U xU^ 5sv+J?9;8]L=u>GI%F(b;/f&z8ޤr)r#ӛT Yhr#Pw}3gOw%+qڡ'J?q t4\It(;/wsy T^>=ogkH۟,_/#^,oKDo;d^Rz{oU=e0a(Y'>3RY__۫u{;Ϫ!bLf\:E[b=OԎ?*9.^ANi{a( };i{Z/c8Rc֣pd=e;eqx5f{\sFY-&n">~jf=qj v k??V OsIUk:NSOl55u5'ObMl$>+"K}S'GzEO? p75@ΖDǐ>Enr`'sQ̽1FQBa7,a_tj<<:8m.y؀@>~/yļwasVe1akû|fD^mSo98^(U-z}sI|KeƉ]lfI8է;'M2SBlfO}BUHso5D>co5 9sk)ߟQLXO:]Wݚ>%Z3Ş:W?HzX8 ӊH?/'|:yKyşk=ֶVX#~ϢYTζ#u~^UMؤ FVf9NzIog̑OC#m/X+$ҚAfJc.5+'#‰za%#qӅ6_8`ׅں1MvߜߘfM-Z$f`3HϜnׅ ]myG H]_mׅKU~=|Ѯ =U~3:EԅKSN\vu!f\k=U] "XX~iʬ̯q7Qu d5N5~m׸tYc^~I]~}{e^HF)uZ z\2;' 3+u=:3P=8ϡ3,P,frUH9D8>_zk1nhM"ęo Gp;I7b{q$sm[;X2F18pP>v}_j/!z32IA|Glz^ZGcɟq/Q7"pB~"^cb)[rk 38OÿOaVoRܯ_&YQ<aC+ϼ}|/L1E~ #uo1w}ԏnϬ01{Xž{h(N^ t^o* >nb^_L7U }tE['o\k?-Sד[ 鯲I+k˺$Xurq&mo}GX=?B{۲.\/vj{!v狕F=W/rXO{F0czot==y=n$_Č*j^/_ :s?mYAxks2?괚Hg-<\<ݴZͦq-ϲR>y0 ݍa\={(aّ*߰8 0"vwwqA[ԞBCw62O#$9Z|{q^e"C3z/f0+'{ B+#z}1Hp,>X:yWGf eSI_kV3K /,#tE/_3Hk\nWI;kx4/7\R[? [&!̟[yf #vׯgNi۹eR,܎njv;UU/QJGՃy>]ۺ/E|jߋ;zczSm_-'EZ3IugƎM^S{Q;S.?)tGfg{#@k zʹO ї}ʿzXg|QA} x]mlۂkl5i'kAIk۽1+yo|g$^uݷ=ξ7lAwr .썰Â3c>Ž}>ǿH }'miW@OJdqh%XרHʯVk1vMOg5c?϶nԙ i_sew}8Ϣ?{6aO[;1;?js!γ-mS:\qFSQb,8wM7:--}N9[|4H]-e}Y8 8:;<#@?Pv_ZGgsxty#v8@9]]@~u2F7ջmƓRO;?l.DYyLk*;5uzs`^lJTvDflk׋/Z.#ھKI=`^^DCz^0#ЋMmYcz1}ԋzqw71c(^[vE8뀤 f .x4/|Uk׋{Uޥ.L_@_ ߑN!挧`|ٮ5[xc23߿lag}c'U/n_h=EHcWӋmH*">֞vذI \I/ /b]ZQJ!xUmDOf kk{ڢ#lIseEfxQԚmP|$:w>3w q}Xu\{h4tıvL8ַju9Khۄ*= oRc)%yzZ#ߍ8o\sV’J cw3^6|7UL1&.6*fT iuyJsƸČKuL{/RFm\MOиtJz^]Qړ^?9$ԡDСa`7yXy9-^RO $O"3v͆d=ò- n ߎ+; oy8E'u$?[ TU_SMɄpA30ϋ=\u/_jC\vxd]`.Ub \7gYCӽ16F!vY` ktzq]G tW N"Йsˀ_)l]1wf4su5 ޏ&Ā 4/Ƿ},zʌqm~<ҹk'ֹ9vο?y;󋑅{,f#GIX1 lT;TaǎM$4#% M?IsM>xdwқ.|bJdW!WGySF_bC~3/2D{սv؏OgUbgP D~bvJn;u֊ fHΥ/"Mw#px[{DuX2zuQ "V_SČM7]1VD_u%MA,kjC.Z] Rt>+=0 L`9ǽBY+t{5JYcmfXؿ::罪jX/.Г:Q/ӿied~8jyFs̉4Ĵ纕nϠ1c%|+I9ѧ,앙x_}MP}U1vNZqkWR;5|+bk:( ޫKno#|M͓w}ItϏK̄Až>S˂<_s;[  ֳ~5K^Cwza{PHu0Sk`lsvN#$׏2\}pwx֛c87SL^\ob~ Da78~n3^ tt%i<{:9-8_2`$s  w5x%) gWΛx-C |ogodvl4GsUOZ%\f QgYW݁8(J>ك./lKؖL8˲ W6`eɦm:TIt(|1ǭ/N+2M~ iiH;9L#te32.شynB#5qJ~wvIfqx+pC)XϙD#eEր3@wKǿ#ȳ /g}dt=LEd#O$Ow]#Ż$m22Vsߎ?bCw|9#9S= ]:vom)o#?މ(!k߷gk_{Y3n=~>w'#~yv;(u;_c ^^.Ɍ=̳7Z1> @؁ti`Rd+=pm{1fMqPۿˌW?څ_Ja52b[v; m~E"U_Ko_WCcq^ݲ=9[9b-IP) z)i%1|isv狝.PW3y)yty53 Kڭe̖("3!G]#%F{Arh3b3O>=#< >֟^{YҪ_|رlcY`2̳t:|ǚw7Ø4\u\\a-Ğ{6]"Ìr"4Y(/d">HA4m_#!aD.||F*}e/ -#0Pfz 泳ȳ;vQ訯FkNګL_+rT=z1KŗjwF1!'0%/7V Cx_zySXz¢+ŗR mQ5wzqOd|;֋\\/LGp"wwi<\h{nIz,csYkrI׊U-IRaV >,m}RW߫\1^ 4Rڗ@/ \a;ULd<MyU'Iw={O|*>@By-X,9!aѿ1A;Wy~t/f<HepOW~aW!cX?gyu_||h}#k9DX|C{0AQJw</ao?G7$浦)ɺ5/w'Gy;3K컨dk(|4zy57QbQXHn}ˬup#S;{S<[|M 2|#|E0ONϑ1,rM@_`R5^< FCF{11}WTCcd)5% Ϻ `0'ݷm_/d6G%-ga\u*T|kr_r_".@7.]k%oY/f_T/xK&`~8)aɳ(mkxw1=lQh^'!/'fxM> +%rTFWxG7'!ݞ3^wŒˊ6JaΜf?0\;=#ڜզr5*hyYYcƛ-^4g2<=σ64|3-0[>Zx/ϱbu?Z|?*/Q[5޾+ Bu+~^P3db~ZuÝsYxfuh^G־&!/~tG΋7"C <}?}e?!+s5Ϥ{G~axQ`&}Fgo=cv}Utꦣ_h:y++F%b]^oǬo./Uڕ458ؓ7nb~ҝ)1w?j u}n𾞖0uJ@aϭF}_q5wu&7^/Y5N`ƌ2bK-X˓+D5"[qIaO8̿ӟY y|`8'OؿH -dspYjW{j4gU5o;y}% K.W!ϝe.DYļrsD|6?4kwgE2:x#ljߖ:?r3}byh.s$=?Ѯ6iB}I+VASlpӏm̃\Ih/lTÓk@FM4 \-|?-yh۽b -$ΩEU24-K.m\fWs5wW$?n _ tQ;Wa?̵dU{1M0u3w3Kw)cL?ˑ~ԟ Y~ρ;f<~gg'u2¿+^k( iYec]ʮqu\y>*fĀaq!ɛ5SO'ƧQ.xn";:'Ƨ$C`Bo؃BfF+9%Vy7~W̻- (ܟ, {:S ZgXoC<||΂s3f}6.ۃt.#ta~Ι]9kyrj?_hBֿPilf13_CfmGh.~3攷l$ߍ1axtg' z81N(vrM1z9vL$f2co_}neO'OaA| >푩&6՜ &s[q"e}]Dg"6=9 >&v2 ~2' x%| -21_nj|w=>y[#ys?`> 1.] f;)٪|!>fIVfS.m>=?|.[Z(av؞L3YO_'f$Ӭ$9~ŌɚĚݤd-zj&w5N|+xw_O": XC4>.ߘzw'6#+1{j3Ff_P γY"nv~lcMMΥI]B;Rę-ojŤ[*69MۛdǓ4teNZfܵ']ܫo%t W,l7 #lqs:2?Y>bTa^]|^X²1d 3֑lbL$/sJiLfZ\ս5~ґ u䱵vFՑ\.ˇ:L_o.ё˘6]*>}Lp%td_oŵ)BG6v 9TP~tꈻsh&\BGdD[@wƔ*y⺣p/?<4^'icقSgN:F{70Ϛ2a}Os(|w/PA^ W)Vlekwm7VO~dhh[6 -;᫱m#þ2.;2̌;e8QF2^;uخfCC5{@"|vWw`0>raʳI uό[oK?>cUQzC\x1{qMŸ,o3־5={f8u: ݟ9ޫe>I֟^kGwsэdjyYtHGnY?IX`ețZs8#ߨĆ~K$[;Sw ESo5ggѿ 9A+j:j`n\P,#UìJ=#mrQ̸^^,&H׃e>ߛ<#΅uTFnG*q|4?gaS{EdSxO_[t ud>[e2_o>z?{$۹W|7kUn*w#wz+p U'|MNlh|"o/W槽@??2Jޝ̵r\ߣ^7 B ݏ/bTwC?a>>wW0!~&O%MWp.%]I}~X^!_aWx)T}bm{9 wVb/]áCƏV=4࿌ ~o.Jʇ5ފXSm ٤;g`?t{h6ɱb x@<׍)<'wXI;ruunWf\KcMFseZc>C~QӻfiIzwc=X}ࢆV= sEɢFRec]e׸:O?&@UiRg:oR,Pe9_hRǍbgY$i,JI8&RUWl&^LOU`0ρfKȆO&xfbݝELv;y'ێrmH 09s쫮,ֹz QngC|Dg t=C;C俒36u!?4sfN=5ʓ>xKPuʧZSj=uU^{+xp{O{ikx{{N 9ku'|paU@]ݧH/IEW8D{+z!9ZكPgqƳ MVxvpyJ^ǘi?ߟ88V'T;&^ }YYy8d*f~/8spFswofTdſf>@{v0>G?Ú\'L%t"yvql Qo51rNf]eƍ5BbFܔкR/y~ ?9WW܆9P1z?r+94=aPu@{ n^*ho<0h\@ -.G@{3à!hs ͒vZ˖?Ә[{pg{3.1 Pa@\̙ ~ @O(}<çMhMޕpU7&i*jS&iB&LaAzpi:Ҷe qM&7'z];y^/ BdRv`W;)NW?B=e IY~Oo)sW۞ 'ݙ0tL^LXېU}; <.vl?ޱ?Lh>DLxn3F}?LNg3EAh>D}g۫τ BτI3gBVg$vL]FgB4GzjXL.Rc.oϿ~\Y|;c,,d"@wLgI0㹨[qT{U1"s$/s!l܉ h9,*T2Zs A)x]]F&]Rf>3R.R2#bKx+: Mi9${2&dԧ dD0C~.W `̼>SȺRU.Iں$f籉?`Th̐݃cw*(fȘ?~c4f0{?NX $LOɌpX=7<]Ԋܿ[8eH@I4P2tNޥSwp~61~?>?*+g9W/Kg#{6u-i?[%M\`p9~]Rbs6kMlop}6qM'R=)F﫣ykrRq3%No.oxB7ҍqBL;{˷oj-5l%0_&˷ŎUR_q#[B6G\hm;Q:)Lb{:g Qxj. zjLU/$Jf?zWi b` ]"/dAUꉖ(R'#'{g?WWdtJ.O{0J'So2=W$A|=V,sW Ǐ ug_kR;&h^* lsU3{!h_+|M ٴ&w,3פ֤RkR[Mp\«פC~yy!ӣ1OoyzEw#Ԕ4Ii6tl ;֞Z5"zU?kUe)vPwg맮KVG~zڿ^xxPEy 4zVG}׸Q |%lf/67(<_jf/VNgP-Ay LCNZh_1ڪEљmfc B ym)Z>rj ~^?to`0 6JxyOnkz(3>DyO'[=eyD|WQ>Mlv9lJ0;\焏P{@;xPhb${P^zx*3i,P<^!r/KF-Gc!ED>Xcj)6( |,8IpȞeҮhOuQٳm:`Ȟ'"{!9G3OǓx:{@^h-ٖ.{OGYfb/7XCYgrw5f4Bq 0:Z< Yf _d)$]BWDZ.vR::[|,&=¾YIք)F{ljDjO wD]AA;QW=2qӇ؀]^2X{^+#9p\kXWj!v f-uW8o8 !Lb/Q/Gm(hȇ2{OƼAsI;?A(;/alTI9@Jh|Hc2n/GnZM W4K%q=YyeeRLb|ReqwYj^ j^c+q=p?a*q OTBD5ͨu ۀN=[ưbidyapM,w_*/R}iP~4zs4~0|^?o?q5HZ{Vd y=iy _vB^y!0_KzA\B퇕|u;Pu߯22 BVRҍyu.[.)?i6?L6~KW6lms_0_M _#>c1ǩ{Jq*xr%hS=N rvc[eiA8f%P&S[6P.2{\1/7lۮֱJt`flmp%sGs)uJ/KK>?)k h (}gAqLQ.SG`E[.8&>υX,>'v('_&uiwu^ P :]a eYn?;׋Nۀ)P' (b#d}R#}ߨ깝OP܌}kx-qSD9ǡo hHB K⿽Ʃ/wjUMnyd\rFNM}!.3uĶF"_r}6XjD>T =>"LX` %>/xC;7bԯYwj "GèMH)iZ#`y|V+ܞ7XT1jݞWp.2-簂|/^X5L_\Iy_=5K^yyہsUUObYe:).2|G}aF$ǓB]W.[se9:ʄ8bjt6b[79c:?mV7yxXk/+4{5O#l?|?I>ZN=P?/#; h ڱtՏS{s<`)&-Btrv=sʟ:gY>X '0O~?Ո?;0=rV|3ʟ%53k̟xfOϙ.ә/Wko(OA}O;P]+t xsyʟqZ"SÂyU'gaTblz3ރB=ރ[h͙! |G~(n~Ѹ]G6"@>4?F\@iU+k=T\f<{?Y;2|E=(~9cS"bϟOAﱟǖ}eBi;=v'|"b?_A?\^`>)n07|r82|˂Ӂr { H탩L1%C^%S^ny-Eu1|2Ǝ cʘO m@C@9^!WĿ K26˱B5AܜHԱ?ط@t~4N>e{g{@o،ahB[x(_u!V91~WQdq~(˩/2$ڙJGϡ>7t NxElL(c>diZ'K.У&|zj G81iO@>l4m3X =>M1'ϧC OtW!X =>1{;ϧ8WƄ΋?=ΡZë)}Cmydm~NxE0. _~^M Zë;` m,yK1?".08RE~&/\kZ&!>n'(`I~Pg<ﻘGb rZwbOnN;o.c?trp|l`qu,̓'?ߋ?:KXmz/_L`8F3rhoZHJth,d't LUvkxhDF`F{_z4`x`χWzǝ4u5Ǒz(?̋ČuxL;V J{07F=x?b#{C%1 (vo]M+]/ׯ-߈kKԘ5tLsKP[pFeAׁMjtkeF՞(f<߭ ~>EwgѲ߯7Y{ yp~}z?? ~^?a%j8Q `8Ǐ{O;{Z_8`Xz=|3_2|H2>Q5|^f|+W>\G;{LR,33N2y>}b23GKӾ̹*3M$2Yf|"2s--2a_15lUL r!uZtЍ9/5lucWt7TL+98=øoa[8Tk)mZ *y:[񼽂98.R}FgXѸ/rY̮0NTsM=O`5nC5ӆwlʟ#sĆX~@ٵ+9Glu yl0WzhIq~xsĆXz59b`NTuwDNpwANw#?iAu2٣C'Zgm Ir3chm|-_ \>[p `eר*}H[]'umJXfg6~mڴk Tw촐5'ge'taמE>{$>{l6{hcQoICyF Z6ƘuXza paLXh=i@:aA=UEgBI3_пa x/{Cޣ֟~@0}X Gϵ,xgc鹄* tO7]s٦=GvQDNն19Kb<zpMP>swHpDIˇNX,<~>RacoǍg`olHvښT9>8VeE? k/Q.7ɽP/ʬ9}>HYt-1W.C;ҝ.cF_:zRqK[>ml=3_j-HgŗlRi׬øOng'Oue9x eg^o|b0`lGll5 Ow¡U֞ `΁iORss"~mlĿo_T6myF!zJ2~j>8 Y>CKK|ebW{dٱ%_Hv^U?S ln 1[ e4xaCXN{)t -j+Ps6"s7>[ >v]?e=rY,'[Vl=/I#םDId[)ˉ. ݙ('PNA9dHa䤐rSΖ}@ٲY]r99 0rS9g|pkz[vE]ofrwؐS7{QzoOz\}ڨ?A0NzoLAqE@yD{RGk Xߋ}op߻h>XB{*Δ&jy|$=,=;x!( C'b_-'ܿ]tXs\/SܛrneN˩|lwQ7Rh4^]5M>֞[ܿU{;ܟe߾.^rnϟHq,5ucg^Ai&b~Ų_QJM|(gѹ]%*]/3 -;]"'g߽//~L1q"/ʮ/rlԉ3f_/_S`?yÓR}9iHdp7 (SedrNbOWrbrd a#+'ڃexP6drR?y~ҧrn=<9yi|4U)nJu,'ߕ^ZYNT NC?w6]I,(('XNCN^LrR%(k׷C?\&^bb֓Q-x>f:Oۋ0ObzF> fq_A*-GZ7u#k5 ڿ\-c>0[:O/vF5.`wVb[o9<=B~܇d$*y6+e=Gv15Y8PuސN.wv #-"*KZ (:_{ˢ9Ud9} kc隽_Э@yUV/r9Y JY9N|_ s3=ٵ=mx;? +o| a5O,MD0=|=]#[5sK((dXh0TA^V^_kɱÓ9BӼu3eyy?S'syYUQV'NI&ҹUƧ[jza9<UJa k6ĐĂM&bx|ZG]7SYem? y=TzLtӜ%||=q!Kͳ]PC|Ͽ@R ԀFulA:H$W;Bwh@˦w1.eG~R/2m5x`8 cSc[D#VT8΂&ה1i|#*'x=G3>ҍpBq&c=C_Naeyi(Cxcv7\lm(ߧA{7ƑN`>'3H Pt%oxU>2 g\jIz0FfϷ]N3Bi4wzuDZ걌^?-HNsPOMpl{?W=0^>V2Xſ (`*%i_0gԞOiJ;އF2-tVfn+PV?#?f?$Oˍ"rZ_.6hO\vm+PV?#?b6?&yN;B!&idrșS|Nbb/%z_%+ʊ2/yy4GJНΖyiKxy|W.r_)#'yY)؃*EZ.2/U+1kN@2/t /[(owTEF'y^:WW[/+2/ eGpWw!2/UUY楝.&mɼY^΍ۇ^Nü\zU@)Թ{g^Nü\JꟺtaouIL_u ^ Vt/ɟx0`>nk<6e)x1_vqP|d%üC{4ym5s)sA9?g@Y'Ϲ|ΜV<W&nUj.4^2lk׾aGd?k^S*fGR43g b7GadWyލ'_&ؼ} ?0yE? <]{+bM7_ +:5|jY.^}vo^? 3T?e?g|˼^V g/ޙ#2/ٽ yY^ >;e㟇 O=x^'OZ?{9 <kf:WG3!/_a3۠˲z/gyU?2gm KByU?2g+S$?e-ER0&wV  y;r}^nyHyOY!&"r?gw'WO#ָ?e^0gV>/Ktx^AHJ?3\Es%}\dv1~'Cꨙ*N`$9ןsI~up0wX!o_KWO_H9^| ;2 ۨs̽Jվ Fke,ץPm&#Q4|&m{զU//Y}L֝"^kPpje,Fuȶ80?BqS7_㦶.871Mx9Ͽ-niw[Pb_.뷘l[7ݟqg-57/|f?#Sd*-Ce.=Hx;%MKen8(s֮-2d,s eq\?e,s*]$sn.rmVsEٻk-5GHύ@b{%?572r\fYs~yr~`?e7EP¶r ӏI_&F&n07"D|k7t+ &FF⠏`6,Y <Y 123c,I}ǻ y7L]l)ϻuɼKyWؿȼS|}HL杝.]S)=ûw#n@iyʽ<(>zd?ϯR7CaS)N99s!snʽ9^gvgݷ cmVrlbV6b??dlTrK+ֿg=?fXeoԯ(w{2 gbAj!]$r{_Zo&m,E>P$ZN"!5"ƐMwtK;SH?@yHR;OݟoJ[7AvJ&?uuwd"ulN{?rT&:ͽD7`n3I.gIB' ]rZlM2˜5OtӜ%n+ZZB7t: ]o't=1_1٤tB;WO"Q.Ds$XxE.ֱ6P,;ϫβ3YP'g٣Ժ]4ed2m; sl,+z^LW٠8~Bڳ*FK]<[n#y{ȳy6_[b5Iuc'Dԯ IOCXv Grb&U",G֣/b\#Iz&q='Ζt8Def'tYԿH"/vGd2~OYƜ?4u40oQG)FRO!_: QH_ y3'1?@d mH>z:iq;0u(13r%=[-\rr\b֏2  Dg'gk鳞lV1|/9[ vcҢIv3I{m\ì%2^6[m-!?wzBoۦBzs]ЃY?'ŧ] Mn v|{03W#ծf"xӢ7|#\'<}O 5@_t0'CقhC=L[7~ %x/7ryB~ 1؏'O_D}fP?m$}0me^<{R⯵Z$f`&)R/ϧ3:)/ݧj):)wCٚ[S|S }i[`>~MJ@L>Ż, Û>>~[(ߓΜD9)~qAz1}[Qw{y|^?ɱOqu/)ey"hYOQܧ8TSS v}q/ ApVy8HXzAȏm-<SBp9/;}s8>H?=0xUFeb#ײX&& =30?қ`BB uBߥ1_w/MmFkWrS ]_0xs!,Et G9Kӿ=ݻsNc">87(Wj9-2K xTo@,?U۴-``zg)Yi)liŅ Pl:5/{Їa!~`JvjuyrPbS|njM={t|(Gn0bw9>F11p?`BoTݟ1ށ{ ۀwmxgQdD<=S oׅ>$QG µmL̬ɭF_\i grU}eUF\esH;,dbLC"m}Oh;*ࠇl,UmY >4[6c[9chxڲ+mYvb-˔mYeP!yy~ 'Ԗ]Y۲H7 ]gg?O-3wBy9So&/Ol**re9?ĿNa[oS[vB][4xekCx[0u/ơ9ݲnֱYS 6Y4ULb`cuku/Yۨ\Yelke_~',.ct}]Rs;AYW6+;hH6t&:6+-E+R8,u^zۏ,:%26 r~Թ !6klmQ&)Lh6,fxū+,Gf@JCL彈>AG' kL}GpMQc۴P6zƁmhۦ;;xteobGlO6Q6KljLglh0M|t{c۴qmz9z8pls]yp'~',-e6խ<κ>Ѽ,wf63fkvl:\۬2\Y%@1]?)[eelVI10 nv-KV&E#,C?o9m2W?'8+6pRw뿼gblgMgkf{;Y,fr?MB7 gU8bkE(٬f8kg(q'  k =ǶI3lӵ%<κMF o^w:Y8 ʲ.z'm86ItuB6g*J/g]mӪ%Y,eu,Q6OqV |sC֥8bm>ۦ"3o|euM.R2zp6kE5Y7M6kculkuyg]j֭>Gw6Kج_GX mTf%f~ަɥuE`)z穙ϐq:/fQe^gkfqˀ;d%˽ OlYoΒm:X<qd:8vYVgkڲ x ;eEmزxe۲-[qzg]LYknul^[s8l-[v9ZL:d}0+qޖ-˂tutf>8[%6}[61*<Lgϸ=LJgLYgmYGo Y>瀩lh8Y^WaPcf8K[sfruz7S8fte tc\tս:[۬ٳdL9:o).2Rجqg]9RȉSg-i3Ff__^_',uދYg>J6^㬗xɁ,kڦEd~mSv}ۤ;Y~m:ۦYױmZw8wmʏsC?3}o)pygNm+P;]O"e}Dz=duAq+渞s|Y>/^}*6Xۦ78kT}֬,z9,fY:Y'Y%2jvA[=|delVuQƦ1Olz.6uCYVM.㬞㖢sX/8KcQ5~sups?Y!vlucZ!,uGɼ=],Gf}9Y/8,g{u5cmYO'-lzrc[b-;$nm.۲)-{Y+g8>Z1i8kfǶpҥo2mYns;N8/wFPy q7-5B:vD?xo,2ڿ_ߖBE*s#Tg8-go˞ms<\ =4E٬)κʌmVlcKeMYښk6녱15_ÙߞR26t͵,3?J6geqVg}׆MZ(x[ۦ3mgmg]Mdgڝv80}e+>=ֱmzqֱv8`:~Bg2aLkcmӳPvD18Ug'wBY{[tm1Z Lz]6a8Xmj5)k6obdu>:wxh8g[)Zmqm!ج !2:&)ʆW:[sj0TY6+?_?Rԏ:V۬铇dLggjrgLZkd΋YτR5jsׅ1%ĿG;d%DO _5JlyhG*],Gf8㬧|yQYp3kkˎ,E9ؖe2U/9e8oˎmYV^u2duTg>28e/tfзeqg_~>YsH+M2j3uԦ`KLHCWp$?HmwMqSplfsNwY/58H-|ol~.b9TYzl9Y;]۬392jzg?]b j36+cZn m֑ݼͺ`H6+9YGXf7bpBYKq9Rȉoc?&6K\3ſoYeΛ=g>J6I<Κyxɵ׆MGj!O19MO&U8Mxfmgg͟%#q CY.y^ T=Q3ϫCoob\^z=? !T#{x\{gHںkj=0]\ѹ]%гXҌӋ'Wnx0j]l[o ^ĺNn>n2c-E6ypN&¾za1nLD.nn_qBvfیpHfKQKS;q=lSgu}*$l׬c,]k'0ʼpray¯YV`[70t _Yc-5^xnߓ%=Baf욁[קs2Y)t}드L]%&~}?;U^nCNvB-iw>F=gn9Jh 0hGz#5 @y[Tz|Qůci̷cB^:y=H ]',E<^0RSKzqy=\wCX@;ģww麰33H?Ļ*5F~ ϽTK-n+wc_`F`=J i}Bވg 2_4bV!Ɏ!$XI:ñG"yE2߇^?p:8i޴h}Y=eiQ[~zLǴ8's=I\7"3򓽥>s`yLE,DGJ"=QOT$t^Fke?3>clX%$?Wh},3Ա~H퐮 ]7N+# µ$Ԝ2|c 0]7aC$~L*v? Wݒao)Z[[I+;PmbuwyL ;ݨ2`ڳ}s$m ۨ^4 cTAgt*=Կ'CF7#myUGIT @M{>qCYx}ƤIMƬ^!=N sӷ6}% o T":Ce0R_Ԏ]cʩ'c`kY:I?ҩl~ʵ\'zm^]p|{d&翣7.oRkTSj1wz37qpn&rۭܳV5ǫ鷜pSkڪ/<6H; wZ 3k~>SԻt KN俍ZzT`U'zuH͐s~j"@e}T/#[:S<;y{Zu ߫ߚߟ մDDi}sy`jú`({ H^}ޫWw򨃲`AUYOd=ie/yY42~}/5 ?Oɨcoza }z9!V ;C~<-<l/OL mu7;sK?\wA/f&ϫ'|ڄxs^ޝ^YW$yMy~z^]qk+̑uD*~>ȫ4]+'t4}B:ԯW;KSO.f~Q˃xno,Ǥ>Td!{ifvv"Rq@YdWpc9%At.:&)?Bf-|un.?G}ϯw$h2LR\ȇ u'R#T:9yu9nyIy@v}_@~1^}OB5}χ+k܏}T$Qvm/}AgNJ|}xw\U[Ӈ}?Μ}7_yږyf[Ûocv= ϯ9x{Ma)(2z / =_ն??dk[{HMFz|$CgΖ'ݒAṘRdjFeaπVg&_x]~>iiwJKJjIH0‚B(-,1(E@DĤ4@s{f沠e93cΜsF;1!rvsEVlay oǼ qh7s6Z ]{(Rd~w ;]7J7Н\d i2o~'ߵ(p;[Ŧ4Vva}".v;[MNϸ .|Z[:kgyE?Q]Hw{e9swu~nJϵ[6j<Usֱ<߆i'#X;kmXZe}]ouFd'l_(ۻY741[Wn]׍38o d 'JD]_.d'2*d;[bJҞuӷ#igaZź,oc[1o^". UąB%ȼZą.rJp\seq fxk+[qQ6i4o|k_[\kE:K]|cᇝe^~>a}ϥ}5,Dk}Xbk8ygJrnKyLǯBEud/Rr5&kc,FėKS$E\r&p>X0HDEz //'jNo=g _1ث5Kܓa>d(ރ;>">9aؐZ4SiNՉ Cg7 ?H0&!(^k#]jKVFgWX! ޒ>}v7aQv>I1Dz}QlӰm_뷹$b}n{?>=?DNd^-^Ǐ6؎3'>{U ٿ vgQٕ'Y1_Ky;sٕ'ntN_!GS3T!,#yLQ7pQ@otnKu}\׻{FRT(G\E#5|p@Ww +Ey纃=:ou֖_;\}\lq@d^'ooF ]Q.vnn_\AD:wnd [D\Tlfe7Q'G|pqjtk4~}@+"E~6&rhm;u~>`l8ʏ '^`y"NyC s+6'869]/|,#ku=ߠd>Qv G8Yy[5?<гcLPp\>.=#bi7Qȼluio^otP_+;#N(}zEѥ\ 6xV+Y]㟲".gew?[grw?w9,}\l:,Cox4Xś,o".~av-E}J$@pF"7^*KYٍ]".be3 L_Jkˡ`` hml^ֱk8wؿx&?66X?u8|P,|5N .s࿚!6X?9ź>ڎD]_t*_-^o>#Bo#2/>%꺝.@>zn[p:5*z:Vv>8Ys[ŝw:z錓j*zq'cBE"?cY~j~~~C0MDכ7_|7OR ˳D':A_j!a]__ KY^Pd."*wdzQLwvTYȴ]'`ALFd~OIaCcϺk7! 'X޼aE\߃ۧD\(t1.^+Cą.Łn'3́~BV ^S/ϫ\g??|xam!(?ς|VNyO_Y_w.<| 1k<`y/*8?#S@?7C;Z'S0ud~^'St?\r<)?@f_?|W(N26k8Yyn+@g?b7Qk iΧpY02OY|k}u8V&s.Vx1ނ,o G".^x qЕc]VLKą.Wm5_b4;ɵXxj"r<X(e{^_X 1كc]֖ xv?;Bt%\ϗ`_|~v<9bw;Eo|I42y^a]e:woHrF3y#Y^/6V+~L[ x6Jo;]_g%}Z>最4_tf#g|?Jߢx[CybG*C湙"?\A+gzBqeusEy"/-ey_x~\MvN!_rφ^YeuT1Au. q.꺝.@S?=5DןZ]qRI뙧Y gu?E3)?@1}FwNp$HLqOTd~Hp%ϧǖ_z? ᢮gay?LBNe]3]ds}]_'ӱ, 9cfy%/ӍuN*_=UDןZ]Og%E]3'։ -?>u Nꖋ#E]O xd#J,?D_Zzzӝ9eKqF,E\r¹lDt_1]ȨC\ U^=?Og16 Rǐ`3/d,Pb01SDr^OxClFbw#u}QW)2lu,颮+t+ӝ"꺝.͠]hz"ouaN"N2Yٽ |>} ӷr0.^vwoœe"._܀".zW  ]ך12vA'"Inuw;gMqq_ +%|?yLο^_|kKesDI+iX~!}GE~RNyDn7!^gήx(z/t1Q#v;/g0&)\d%7G\F=?ܖMLjfd/*|%Z6E^W]\'['NT9o,_$$z[3s3D?P!lEw;Y*Lkam] }skfݭaqdE8_L_V7wtqǽIܱ"9'j cy>sWAo6Cq0wT9_&"}2#X/,,f"=%.&ody]T_ 84t.UO/K'2͢eRH0{.ѿ}O<,o?!sL\-L9'B ⎃] ;]`sZCpLD\uµq|w)1얝x|g\`}w"e,oM|?Xqݟxs?ҥ(0}42$r +5\< ºFd?`➥q v֖WMW &_{Kۿ>ll0 ^>*OWbN)"ϓ?Dvؠ49]}'D]fy? '¼ ]|&QtQ~(D*ku}<4wee"__K@?@1}{l0ڲؙw5)NoMqW q>`aLSą.bpS . .Z\YQI".&԰ۋ;}E\$ae? L pv9| ".9ތotP\|SE\R\vd:1"Ƶ c=IY} D\ʮ?p?^D\l9b8[M> B 7!D\R\ꟓpSKp1UwnP\\DbBVv{y|8Vv/4~o;RxI~@90}xٿ"`0M[t]I,-⿯pE l=Y*OC4d?ӗs{w[4\5I̮M+'ʷ|4T"󸝢ĝ4K+W{0 Ӽ;I^y#yq^N=-l1&KymmU¼Œk$x_<-D!Ŭ<+T3ȳB[INN!nv^A&χ 8y&DHC{XYب,R4YV} d"`_]jMaUo0 n}:mJ 6#gƏi\c}R%%_)myxe*el Sd 7D˵upD$s 9S wŷ}x;^,i2kKZ_ۛGmlC[k ߃%*t"t` }`%k[ڊ'-3N?g=}s@&x~߉:h(2o|Ora/#Ƹ@ߠ ?p?Zu<$0j4ktd@0rw ]58.>Pu;]˻/t}2O >=g?x)Qׯkaea2';έ'n[]yڶ ?ʿwnp dqVuꟃ秀C?r6k=hk,'*Lg=~!]ڜ0?nߓN~=]vgcLj,w-Y@zFijzj'W݃гaل:#g)9# ̿6hy0YCfFd0fcg?(?dm{{=ws>g`-?Wf?򸙻 Eo 4Y\qgг?ۦ@d#g#(]7@!]'I⹭Fnhzrgou٧59C.metqp9`7sۙD>B$>YeCmotm?G[CdPda~/ZH29sw_i+BxY? ͥ"9_.Bn;]GA8+ t@O-]"OXXퟤoXhGҕktW?k& n0nc cs 1͛NY$Cqћ lwco0PG> ֶp\}2w!Sr |}RS`T&Za\Z~Kw -M2L="4\1&s{I(Q3{m.2wM0b'unK;Mg/c}wxOqdpCbcWy9[IȚ&k!{k2(?ܸKF!v &5ڬٟ\/ۗZt q+5:Eh#@ǶRrҍt7] GOXO^0ϤoOq23{1\_{}#`o_(t9_z =]zF_+uۥMJ[)-5f[k؊Nd|?^I?ß#.kw@ʸdX.6[g~X7duO54 ,Q?U JNS&S.x/uT.S~ٟ>~t/bDj/OZԴ"ظ!B^Cu#RaO5^E:d?U?iQKߟO=S38~SKd}zmO/)'ɓIYш̃N!,Jџ*t?]VN>1ЍѽYzǵd,Op&ʲ</jA7zygqsN3 ]uR_nר4]7O˅ǃQrZd N-??5C0wQb S O%VT??{|I1nVꛑQ;"{rPhwk9,^2!1t;d=2G_ykyx.G>GGɹ,'(>*9@Ҋ%zw%Qr&酵Hj:KEI"Xb͕߹Q~'[ ̕LǸI"4J5S%A{Dd#"e4g,VS~?ήA kZ{*U%S9nԏ piw^LLg?FXs?oF+ 2Owdhyd,N?Liij5i:7t8k#/Q=\nֶR⬷ {烱wCt)dsm HGgs0 ުB"gYr;O.s, #gu`ކ<@nЄF+}Bd+CxOo^чBd?DYraNs!wMsi,Fc:RYF|{,zo8X `l^e9`Q ]a(K;]* {9?BJٝ:<ʌ#qۻ3ٸDNiqۙb¶$M'[sX\\88?gtqFb?ӥp?"Kh]Gܤ9qz W>T)W~[N h?8ֹFC?^@>FxhEam-f~Lf7<՟_TYҏ-<S$3;??!Uɢα 䜏}P:VLxHER[u,o79{A1 1dK1ԡѽ0'>V#Oc[\ǿf a*͚o?9[r]*1`n(]?iqLӥ~y lwNs==gv@'jk͜K;FMs:Z_ U}!^QOsF S_.ٓ0]W;]A|khks?mDYged$e77 ;7JB)OL7@.]}R'iʲ5J_]Wnt@"W;/Putﱎa,o#3j7#`H2RIkf[چ;mq#3?_k38OE:6qg^iͿi(?gHC~»p_@r) y.G{BƮTzeޢi-&n+ho[!"y6'1 I3m7wG:  C(ߘV}@}) 3~+~l8֡mFrܼo@d g@n,D{i߽?3 D?J_nit =DHQ]pBjn9? '#铲ޱwI&#q7KxI`ϹĿטpt4ǿ+1}| Y}x(񬍹ҼL+z{^:9 3+$P`?^Cz!4YW~6S?yYT7jE~gnҟaBg<~ V;=zG/lߣWic6}|G d@~4t?꽗 u:#xظK=#ilXcd:neg0Kh͟W=zU{QEcd={Q1 w.Ts,bzb;{d9"A |;|2yjkVK$hKK;322sKLV.ґz/6҉Fj5/Cx[#x#?aIh͎+k9Sz_`S΢1vWk]){GWpHx}e +x G^v޿kw̢ǡ/ƕ}~n_r×wE}oOF{rɐ{)"TUKcxMfM=tUt@X8>VͫJww:F>=Smd8|__,~_NsZG]'Z>w&[` yosW w`sw~qԶ{}I+aƣrv*8W 12I.Օnɾ^MqM{뤭(Vrj(M;XY?o>IBԢhQvTwuo=˝\T Qz.yYg[kFg[q1,ץSg[=O+ovU>9Tk]v5.[=ۢ"N/`Ϻ䚎~Y;=KzZq&]9$+h}rī2 x]AhPr3W4;_*@R9=#qOqAdviqV@5qZRϛ^Ac dc7<٘hO6 %;?0fPb+_@bדe_oi98`mtԿ|H?c0YFǕ˶:KmR3zkkXCFsb9Z6eMf3z*sz-.*{}6zEwٝgKܳ1ʾ)S>{֎Fkn?wfк(eODm1F?:Stii/cŰ6O7ۘ?<@lbG\w@/֙[ϔ~f~-f>w03)bD[Ul_0Wmޛ޽}!֎HvZΖ1'WpAq)~vx{X LwKr̃vyNai?,I2v|`J|J3(fj59mZaF S"[+PKՒ}y}zȅH2 2!饣b’~kX" bD=ӥ2F~ׇ\ȋ qWۜ͝-$ig ƾ- 2I/  8zP-,&qG.+=c6K.ɿZʳz\yIE3-:oO-/PW1AF=r-i,V`y(}ynƴ"{3ke6$s '`z:έ`?فx)=P>H7~#^Å ndQ?#hXH{ $Un5^kBCx?S ].]_{,_IΏϺr<858lL|!!? H`CyY}Ϸ<dZ@f _N Ob,E8I+$kwW /O%qvW"}mP/[. F/OBro.cp<|NwZvslyYuοq{ο"2йϯ9XH?F^6 9e7`Fc!w19XƝ|kc+?@Ϣ=jOOI+gpT^!3IK3A l? Y.ov{G麁Q:Oy2~/ȄOU8x7j#9LP܊K}1 S<]ho0%?%EaOum]\SÊM"`q8(rkrï"`_ՓE_ڞqs%98\0Q~ _Pe"<~C;]/"M_qmɵf-ԺBX]J7.a&Uќl謵2b6zib5~e_D7GQgݠ2 Ȕn޿lsױՎ_{;XwS)}<ߊ>ᇤy@iU~v* YJ_]Tgoѿ/7q9I'q{>K\/z¬WV^/L\8;PƮWSUTWZYze]] WzmM+ ( O_NoCit)diË\3WkM<$?!?KE~2kX~wa~|E~;OA]~[hd֐h+hSގkep6?/)l ]ǿj ֭j_AwP/u4A9:JMXjg?0Yէ:^ {ZTAdj*G cHm ެwgZ[ r0*ѶR۲ԿM:=/ӳ](9=x9乃H{N/ܵ,Sװ<}le"?/e3p}=؅=>ncNlc 6II%"Ngl mbt)ulcN$zքfϧ=P`ֵ' Sb}xhc{E{6v[kc6?lll~hcg f6VY#`cBCyᢍxnhk0ձ[eHssD׈5{5;YѬ*X{QXӌȔ؇1Fm{6-o6-A>ocyy9X{K p]zO"$=_Z[/Y| ;Wz,M?70[jJ lnIO2/\-YD5_ڒO.գAY>G9!7ueeu ccR= d~k%"u>.LsF>SDkZ$7x_] _23E\(tAΨy.Qu5d؇ȞcsJ>h~l6P/|wJʳz#Ӹ %9pNyi%c[Mgz,^hohWzyqZ@kO^ ց(n+AT^?  PT\sKi, (x%H/+A3}X/Zt'.ߕ >@^P=7Tzgpa(jd  6WOt\/͸p|ׄćz _//|h1 ccr4J q}IƂNFңÝSs}9Ͽοv%X~5e*7̿'׭?bbא.r0yVou|ݮ} G~T:NGrz0Iwg9Lf-l/)#nmt}Х]P85x^?׫H}I]F#ݕݨZ-T Y=<ӅOy ?}ӏLtޜC۳t0C{:owc[: KVLη?g~q{QHBXοSojުװxqE{_St~I~1R3p+֠#c%Ō +c$51uH^?ƼsE $οGP f!]jG}'Ō՘;So(+o0`[ V%jf-VT~݈SRzEQaZLLOyŠaz$^!zal5/{\t }?Y)= ߍ?K::Xi?e:}Y&EYXY BQ_Mea. RYǩ|kpPHggRLgsWcs{sc3|0(r?}fve-rw$+BM)rg_Nt DR)A Iѻ؃<6.W~]Ǟw}? '~6nߐqe_I:zocl=V?$TqI?bbX?>-a쾥B=_ٷTtXG-3R_*?[۷HCeLY{]J]o4f-ZcN5I^t~&[E )ZݜN)/]/˸TQC,O)R dY?MeiKe-~Vkcܻzqc1n7+][S\i*Ƹ ] RzEQ IKc-hS'rO-?oD`zÿ-N2ٛIH%]e$!WwtM,#9?ѽmI.,}YMiKvx"Q}DY*t,GRP(K*KId7F\<ŧwUMKXy}Ich|z@V^6PWEPSX%$>{9,P;Eo a1X7?^;XDM;E,u6Fass,2EYf܎c(ˈ,ߛ-R d=eiKe9\+;,D5z$sMAR`(W.8h;J.e8ğj6J*7t0F{:xЏ0Ƅ1Z#Rø+Zu| +gBȹ :oK,^AlssEDbPElM&ʿ&IWf=<wGWbDqsr+Q ?rn4w{՚p$t1wVu?CȣRfh{WRjs[?HtХ{ Pv;iuWvMү\+~GyF-n ` aŽc! #,z!@Q,?A ]-H s@5OĂBWթt'c95?o  [  ?'}BbiKZRbA->aibXZZZZjbPZZRZRjRZZZ [Qht$i4&kgh,r>ZBv%X cA Gb"h2Gca@[E3wX`8?Q) ,"7MFPqikF+r&3nfEhڦj6`DA?r×b acO&(?+p%kGjܙpr}H7;@<7˽y.`acw WXհgkOiXkpD㽡(4, ?G B1e b,<ݳ{ 9A#~+ӈrvJêhzP# /H&k%΋BϘ%apFR-z-Ve!o?P_;AaMCxl^6,WlfRmwP< 4>D.we,7D.e8>Bi6[VufQTیFpca$5lv>b6;يZ"~s!ijl,}%|?>f}m^تJ5=ьی΃l;nm64EO_? Mj^_[w9u;yǃgA>^B?yM>[T?z!ab]^=ei][ s.߿m~ 㿷dp [^e%Mjq_ k^ ^/L,xߦP߱mƚ%zMT6A{rImrB wc&D߃-1b?X671{ ?ZS(9מX^˃uyU" .'X\`>?ɼ.{0_D^W0?%=_2ޗ j}IZx=5_s%ݙ^KKM[}*rޗ8_r/v %Ek_J\ tK xc,_6/8Ht֟Y;@-yQ1/,EZmVy/`IJn(,B$!yx/Aš:%(C'1u>чsah,w"+`/+`dC!Ow UqI4:OU|8t_tV+Vy 긱k+N%5#X&Oi}Ҁ4cQSxk%ͫ/jD.%ynൌ=ФZ$wYlŹ|l 1{cAthBc eC%-J zE9+O4>^?H/g?FN,_?D.i&1{z}G%}#JUvH{֏"Hs+ZVQt9&Hl _yyor .7}wK.;2K<~x=y?!13gWoJhM*M'F^[OR~GnvW)3=#+dp\w H4}x߇ K5;Bw_&MwNL;7 ,x/˼tXo./u9 >a.o_g7vKty;xc?@]z}]v.ˢ:.cE_ez1K:l2U.^ދB)ľ4p?=OeHnv}A4(tZ]릭H',D!g}ߵ @VUkZ.&ka_%j6\Xν5z"Hn|tR~NĿv>8ԇzb2.[Aן>~λ D^4aƦ^F)ޱ,ۧ3Ux-3)Z)o٥N씂BC}NmQu{;ZEFDϩgMo-.K}H Z츈Hgο[$/#$m[ί+Or~2RsMXrN 93<?o󳷷'B+Ty^=+5O{v"+0_?..UV]FP6k6 '?9{s _Ma$!o.!-S_s|D3<_%ka /5O>Cu_'J槽]߮7[qz4[_'K_Jv#w׉n?߼]M/!:ߚG_ w X5]DA{]D5ΣsɫH:''#7WW7Y;g~uWvtω 蘘:'Jsںmsjq vD!D>tNTNDI%tN);Hω|ns"|N D#½SH rǰO< 1uNtcp-"9``?_&'k9Q#v[DRȘ+5fs"lN4ޜ_+Ή f9˜ &'D귓9?O*=ω>Qakz }LH÷[ZT?(S˿ P3O2VG &b| %z^.96U.96\:ȱ{ ;k~'Gol?9w5un>yutn>;Eçҹ_-|nN%a7Ɂ3 ]u{L/ӹUZnC$d\/__\n87ks\bF:7~uN >|nz}n*>7Wr)j>7WAl}f'z?;Y_W:7n1CO#z`s/5Q[:7[i+=cܘ+m,{sN87=.ss7\9+^[,Fn~0X=`O71oބ?`HngxzB=<%{Gpc`{fH#>U% [N2 =\n-H^}ٳ|<{yyt`{wl< w(wv +n`C߻"y`;!?|;{!f{sw>Y('dU ?3kT2?O w2M3_ϝNafɝqUUUx*>}>$g#[7kxRD}O Yǘ0ߵ;o縈d{Yn|fN.wFA;]-iN?'_3cF}nFfjsɬCm`}\ ޫƘ˯+H buf [t%W;Qm3!'OfItɾT61*>N6*1C >:u{Iw ށxyyӆj<}FJ\LC!MLL6b=:S}dF15Mz쯕 [}2y/SVo2F[f'8z̰m`*\ {gR{FWbT9Uߗڤjܶ gIXoISưju8Fmj=f)sTK+Q$ZnQ4~hrrs73ZT-Pdos2H%Vol/7߲܁MMDpOٹ2gV<~$$q=mIJt\՟J!4pO' S7ꝽK云$g NBg =HLwrx^_㌚7)goO[g8z>glo]S5pzQoISާ>1}$$M,}+czZq*"k6ԖiZ_%Vr\ $7¸Wr?c}\:7|U.1Gb9|w%k t 2{11k阏1h.c`q~*o{ܼ 5y_S(69pƯpvtX󒽒=K?'1Xy -[a'[?S|y81☯B:.__Cݣb$\/}|W傘v__sψcS8tu˜ /j1#+8L7bG2"1jm1_i75u[1R?gc#1?F 62o5|ybm˞%uf$,qqFzD>O<ncj.r;ϓ\cGcCFls蘟+t̏.﷊c73~$W}f:Oی'y_nfێZmàFby^ȞR?hyZ-^k's`ww󥨡_eqq|z̯m|WbYH~{ ]c1P,7ý~.8( Fqc'8ň m1F/N]i1_>k--Ci~s)z+-1hq̏#i/ç"yb>o\MV-z"yooX#[1 7KK t/,OPmgM"rAr1)?vv1ݳgu9A.m9H~gt.(oT]^NDg _׹ѥs={Mk>:{!Zz%g?-`^˷V#y^D-@n c"v, rnrg<{螽mV;i[o-o _7`_KvupC3ABM\?l] >KJf\_`kOhq0T%@ކm:[؎ڨ>d23ۮFV`ojV?TN1)pc~p'C|0~q:.aG*_?l]~ГTa(ߜ/'A_?rA04ӽ~OO_ ap?FPnۡ0CE3𡬮HL:no|>C}=}4Y ~KBfCap~~"ʨ>%}ҫ␼t>)@VX$Yy81 | LD|̯fj_i$U 8>;咵K[?Ժq^Ѻ%ɼ.WҺxץ*r6$/>)߸Ѝ.âޭ6 r_?|4^_JJd=vQ?7&z"=|Ӻz~3F\?,X ~q]al|5=^~u|CD5_^?qf~qOpxzV?|l /_eoVW$&Ճ/8o.b]?,HXZ$C 6q~X`!,~x~A XÞ tg ?s$L3 Af!U[c6*$?dgϤ?`zuٯ5IWx8Aˏq7' oC]U#f{6Ex-ҽWkG=H=_K17;٬!͚7YsmjfG6{oEIy/˰~fY]If67(ޛlYo6U䙂3a f6k tmi=զlf36{7k]Jo='͞goBm@F_KuaTqYW{{L!RR Oo 2Oz`' 'n Rz~O[|}L&K/W.TX,w,W@?K7ÓxXii?>F{Ϝ T;PN<>,JKI_MEtAyy~ ο9/%_W/s2e_tSqLoU/RyKǗ q|9[io2ѻ9&_[jaͦmu$;NGj*C'h$WyZ/E w>LEOo'k%%I\ |*+xN<Oj5?f:>Y`߷z9.h75 \I^[$qD=f\n:]y\8\_3:_qE]),Z2gSn.ż.U@` y]:]&ѥ._pqWT_eкץ*Xn*K\Uϒ_=Ό?i]ua6ct\y%Uꀿ/XWl~Hޘ߽|&1;Xg)Q9,%,^(ɵX2 "*<1XCԃ[zmi) @R'brCd:c2ᴎM@sx]0; ]LctAwnD=?Ϣ~]q;??f #kCK3W/?/el3? ?cʏ_+bIe,0~fߌ _$S3!gl5?Y 0?[O/G".?c1dnW?)HC1b0Lf_ ?b!)4?I;7b%oKUHJ/?]O` .?=3oS<_E/Y/:? 1CDw0?]/4C;@.>Qc 7'4 z; ]3څ?R|0~0? ?"ۅ⟌?Ocb~BX?F/$ƿϩ25'+1" T_ oe6s_"ىo/*3Ɵ'* 5G]O0χOaV/ [p!A c ]o'Jpv?ٻYA Tevd Kʴw;6rvUp/j]#~K;hô;h;h,M{/3G1s|Zy|{A4E-cy;f1 ^?1:bV7r^1=&Vtui|j=<>c#?g15AQoonwD9>ry|D2x7Gy<>T{7 zsA9<>nLn5|<<>c# ?SMq1>>K7Z]|L3}<>8MߟAM}x;f&(?C b$'ך%(#Ga#9LJslex?&HZ`yb|ldovwx9>U䄻"Ƴdr—*\Xn\TJi|,[i|\[><>nNj'>Fcd1>> 7m]|L0=%<>`M;"9cp<>T;a'(ct \KI4>hH8#LJsl ;Iit1>7}=ڻxt9>wG 505 <>ϣc$c"p5+h|,K:Gu<>96M2>[~m7m.>&&DtOĦo yBގ1f&G4>\'K1wG|Eh(!>kx|Wpc&84g4|sh|f@4s|d -#G*<,1?a)Y#?3k&k q? 96gqX qn8M_xe;?Er3 -?l A,W8|c?2 M8FQ GȋS4|\:TeDZqpc:?4?$ĺ?b]؛>21~9>n0g+?nf?25 b$Ndkc 1?c&?c#t7x^riJ"?2ǦHZ$3ӀC eMXp%xw Qn3G$?W >q96dž?? 7}e# q-c`872G? '`1XO# QA1 11{S*G G< G  x capSq9!"G#QqqLA q=#U dOd,W\G//0(? ߀H1?jxsi{֛#ID3Ǻ $_)? G4|܆ x[G42?f1Lh-?c ?n1?B(7G b/cc"9J gɀ-?0ڃX +9Y!1@ g 7.7Mܵ7XWLM#?>܀HacIID0G Q )?"?&#A7G cq=/ )?1G$GkQ$ ~ QS.ǣHc 1?z/?c#?n4?B>??^doZes|a ^$ a 1G_ \%?a8##\8FD7G%Oa.AwXeUk|?GeU\K?G( n u?^9foZe#9>;ɲqݑXp%E&Gt#$?$G?F?>"$7[+?2NJ)H1 ?G_X!c)A}II}G_ǃc}}]/7U^0!xÍIa0o]CPp#wyzG}o|!I@p 7ln:`&}:nXГ=҅^x\F֙=Hki(|^cMo71㕙 LW/*\]ƾ l1w/oLt9XCoUy.+!9~?z{ytߪIX.%oUX!V DWoUp7q'wuk[BP'@J.,{U1agn"gj$qqE =rc%g*WLrM\dۮ.ztVu~'?;6<̕ܦ)^\7~$g}tnQ=FLr/xM33/sbӭ#"=O2XSz C^a|FD0\`>}'b?|@|1鿚8գ a̧ ϧ=OR6]WN$ ˘%yT ~cj,D֭#Y.ajGuJJ]G-Zn#uڻbuޏ;6ul"/qS\$̻d|/HR5|kv[ԌKv Dnp}p U WZTzw%z58{r٣S.׷*Ttj)%Z&Jb`ݦz/=jɌ d%Zs,U]'?ǒ)?I2?Y+@YKJۨ e={} Nvrf=jp.4"Ш_;&r]2 1ۈax(8V{c,{7Z-mJ׵;򔾒i8YeQA,e ߵy+}Iu^|;86Jc;\k9y99b?IeoReo03-v#_bg)SYxڛ?߅.MtEjֻ@A_A&AcefD A]q7"ت~r u;Aw/?x`Z$_Tg"ן@¿g>d;:|g&jS2>kqO&6E2 Gkn%Zr;iߪWdU\LJZ_AEA>udcsz^nHʬr-_+ ?auPF(\`ԹSeZ˰K-h 7_ݡZ-yHzĵ Q~1/H~іbooK7R_*9w&K.o{6%oPE({݌XI8n~SO TLMlߵIwZdH!+w;B&c[GZʔ1O{`?7do?[8G_bKt Σ ^d +"l٨Li^ !*,>Źs=]Gsu19[|`yx;Ms)2U_%vZR׋~h U$,D!EedAi۟>XFyc)~C+ֵ}|?~!zqApim"i&pnpZB{[&l TM;86taozyf}x]9Ic bWWe&k}Wb C~݀m$Y$ XIH9"cU4+߷g)6=e:&`Z/r 14h-t>DrJ~8-.R֝txq;i89nqq[J~nr\*yMVa$KY"# k֙M@i7VL?iMynYw,7D.sS\e*zb܋9 1neXtG&68ġM8m6a;qhCq?J2lG5uvWҲ#K]HʈqJ{ ]}}&"yn x*|^̋sl6KUW|oϔ̴U3Y]wFw;3$OLƟOƟnsv \A_¿n> mwwbX-6KuE$uhy55ϕIs7Z,:I͟乷_N_u2kS܅&rIy .%>dv c uѠ %OkcqޒB!s IWT>@}8'Ķn7s8#Wլ{]eѺ򑼣6"кq|3 x5] ?I{%5u湰&@NŒy.J MyHzV55?+=)7"SH4OϔwEq~%?_njnos+~: ;6pVyF$Zf|9.]+K&Xz*DjlQN24wچ?o0~lpZ\è aGfUc)Ɯ¹r;RqJn)Ĺ^W)Υl8/'F>ʻ8LnDRw?J3*TK!#sz",&5ktNog#Ps.Yg7 D.ɩwrow@kJ[4>gj!?7 A>2 7K A>?BOQ?k:p79وA>2$ϹM fߎYο^Fοu2B2~k/zD.sF󯗑>+q_6v ;}tgyI>ߋߪ?c| w{[u;;I>ߓߪ?c7 ۹ w{uc( = s;6۰;7gt/A8g1Z-%%\Էj^; {H 8||ɞDNjAc-3_C$w)ls$~cc|g# }{V.PLz#,~ߥ`q&Tva$ l\d:=#T ?xGcdce ۘO`9?| d3?9z>#t/Ok(۳Dz9OȮ."^/Qȯ;.`z\h+ C9w<7㼹Zi@$pތmhSjF x翔.k@NrlS&٪J2zWu;c6%?妚%r,iٽd}' $ktѵiSIcsL\߮q p;iX\fr|24#$W4䴂B6~߁Aݙ?O!˯f']j@N+)D 32i'g3\Z΂VPSo2swb/*grB2,czi6?ɕc/vk O'9liUJpNBOc/4u}Bߩ%ܩ8>D ?r^#;7\'SNőJ;؆GҼ3;w*s9D`lr3AZ$'z࿳pNP N??b咸r5gl¹lX4D鳆pBr ZS7$z}Ͽr/u^w"@wrcMRc5Hj8%qtB w6 mM`R?{a`?OO?, ]>?Sb(,Z_=˃uY0cm.֥rv; DȹٲK:Yڴg+b+ E9Գ\*FL^GX$ dihY_5?|kzU^?P1Ny@|ӬYm݌k~>C|} QH)BBf`Wdgx5puZ7zF3?ur?P=E3=ZUt8ahH*笔;EVCRWXoYb]տ*gյzLb<]x UK$.8$I]޻i}rZi̿n)Iw7+&rAIX|DWrz:M0>XH$?4?6 K;mUhtB$prPpay/M2o|<EҾa5eŗw~K~>g3'Ɵsy?K<=mP8<I \%@.M3޳8|qxlZW;<qp6p">\=+>Pz?W YN@>8<~I#6;q8(SN;cg6 R8|";__Nd}ly>iWC]}p< %{Xجs!d޴ΉDs2Z Ͼ U FgiD`z7D{{}~.4{۲[sQZdrv@{ pv}fjhrrs$_eEuڹ[ ({5-;Y(q\hMl?OB-&" oAqzT,>i=yGOtW,#ib=},pz4'mThwLݢp'y$ys~X;ᆱ'w?QNؘqk Ϡ4qkYOUƵs}SH$WOS*O*wQ?;4߷Ikgtw7hgtYmogqF"{Sf-w%"ߝ7 O̴Lf~Qyoz? {{Mfw1Au{5p3 H:}ulg߃l>gωDf?:ȍ7ώ&r `?ퟃsA~"cF8}o%~t:1b&r1q&:sX-IƟb|D.obדc;сt߱2sr&W&m&rUcuaGhI3\5;ف+ίI k3r~$m3pO֫Wޓ6٪n<;'wzEd\;L?< ȝ ֫p;;7wgk ^3^v5K@KCS X?Ru6_Uu;9;cFƟ` RM?Gς*#nKw.a!5x^PHnmnOI@ pEN؋-51gwvRUl:d w2:@ YzIb]tZBU.Ü6sX^\ۇb.r.huK?^_Dx=/^?2}.o?87y4?o3Kz1W0J!r,W);๑Z=|_b'6Zgg71 ۿVwdyNPύ,΍7گO*y!ב 񗞍Wmzy#H;f}t1?5b?%KAgyǬ. \r798{4K䑍:[ٖZ%-h~$ʳ=?{`/hA6$md`7E`'vM on~$`g!Wt:Ouu4?:'yY^!oN3; Yüuc3> tC[_V 9s#o,wL4~Ƴ|d1onxc$n^;g> >O~ҷd[3P@'.}(ĥvalu-)C7Ή[m@K#X?M#WJ/\uoy{UJ@~?`{AjWoݮ}-m*H^;EfjܯSϳ5N۫z^M#z^f-xmqyI@۽M=BVyxw`~?Wy3~/{|U[{%{80c>b3rޟϧ~Ib^ͳS<~ĵֱ|*ԕq^56wk5U.cܱv%k@?jˣ7uUW^+h]HDҪ.?+uy}۝ץ*r8VuuKt lޭ{F}yw6z_ FO0Qƕ#ݵ&r^*>q +חo;:SG?Slef)fiFL Wwd;S/Wy-IRζ3 MC?Y{v.,p  _XvIo[yUC~"g,V"wZa"D3UٚE٪&}}w9mq)d nقfdr X^ߚSv;īZ6rª5IƓ9~<ď6g[qm$|O9It z<*atmqwְ%Ff }RU\} 34f&עMTl2>unor[=6r'X[A}ic{-G:ul&c#9 |orc#U%jl_Tml7byj!%S7[34p*ݙ=TlS W\ ~wrf+(g+E Esϳ?KM`+W'?$jtIKH//Ϥ) MOP'rA>S77V.oo9n:^ /OHlF0HxX A\A\_lUݱ\A\1{q٪ܝuοnTְ8ϻm5z}6m+w iO $\+<ُ#u)z xm=9Vks>֓ v__ U. O8<O8?lrSqi$^ h]FU!m.W6Ѻ<2ØSx]r.RI.r.] {ṩ^/wR#~rS\+`}L6f Mr7ub$-}S. @.yW[ X]W hYWq:?izͮ 2o{ǧF,s)cnKP3.~_Iuݘ|Gn$r`d_om>s1+F&+6:)T۷^eUR]yRΎ"隃{rK- jwnWewq.XqhX.3EʜQȋɟGc}rJ{#Sy9 $k ?M߿k4+6}/FZS< |n{ ε8?/eoz=FA^yi83&r^_䥪\,>]l"ȟ5җWjy%mULgwby_~G~XKViXxyw}NdޕV6Ecy[IҖ~dt]8[=˥'F~Ln|,ʋy?&D~c_]7fvO$r h]vERP^P~y]r.HzץS.@ 7/../9iJx/> azJD?}c Rˍ}S.u{sD}V]F&F2 P= J.9+o%;NYʊ[ɋ,~ ԷԷX|p|ź~axqků=y=3_Й:#i6H֨ޑzW*JB[\`f=UB?W:UZ~aivp:BT﯄h{BIipjX X LJ[ܴp]1)5)----m5AM ;9 ?Ի^Ι33gðYE,wl-X:$QoziKs<_ <#Oy:['a6yң~*3;R9dtqwEN2""? ݡw>.^ojfΫ_jMk U;1ΙN`^(*@ {IǛX0x8ka!>q;e aCp+7_{I7[(8ҿd1̷~|'ŀRw ;Δr?o(4bd%^d1Z kj#p@5a~/6=;ڜzpb7ʗvаTe]j[%)QrF=FJK+72} x[:X?'UxGeH+frt?Z&Gϡ?wp.c̜1M+tZQg׊3ܞ4۳s;b n(#eT?5xW 9kF=k.;$uѯLw޳>ܦل0_ < vYqLEx fޘ1fr8%>w3VW{K~].iQ k-9J~K<ϱx^f//9杣|w »^8Kq[ 9S,xyo[x|Bjw\mw}rO &k6Zkxp6ۼlV6F>G?dwM UROHkF_r6_w(/"\q; ^{}Kӄ1Z:#?^t;INJ1Zp -/٩:ܧeZz"-wB{]Y)sҥ䜋f%OX,E~.ce{;p ]Cܥ>"]?Hp97d% 俽zRWgιgr&|kِ  /#"-?bL /俞(t~jQM]mN_2qMp{zOZ`M?/?I2i{:7nb㿚-1Ιϳ|^?$L~gtzwq=qd=,+8^u<)g[XPP8l3:=cn\O8\ON~=A3TS,X˯g[V^Uk7Q3?㿕"b%DRV' ?_[_j]{?UwIߋ2O4 G\yBRTAO(s_H")dN^O[$[jy:'/URlz%;><4fz'd m˫ye_fA^%cO=E5A?٦ 5]2g/<@תe=ρv-3iBg9<γ=yf<>xgguY"?7y `γ<{p8<_"̃=KdNc<{7+#]Mm˳<[.,[g:!󬀟D-,,y{ϳ3ϲO<>,̃zgMϲNY1kwΉȳu2e<{4Y Ցeaa#H<{n߭bpg,!߭<{ϳӼlxg2<_Qg_(ο"<;2a)׌;y֐jix*] 2Jy2WugoyvzgOwGo_0Ż?o(}])ϳ6Z$W˳玼XgSy:[*,G3Nٔ<*󬮈ĥgyv]Y;kH<ϦYli˳2ϞZ(^|u#Q|xG_$4gγ<,u2ϳT<"-?}Ìg&ٽI[gw%V;;yz!lLqluDH.FɝH۬c!HY3xT o2=ո2Td^c8IWk_Mcp62)q1]ܼ k+W΍`^9^散ݵY3ydӳNW3:6W!{HF:j>6HaF_:ab]VkZfMi91e2qgLthx2Sвa8 w8+Iۉ<ԉҝNPKt/\jXDZpZA*ywHw]C}L ?x#[a;, ϱ? B *NGoKn'|5-3ȴiyh]kNd~9xL Z?_F⟏ND+.)9б.yhKnX_ȇ)#Ϯu Ց\kΖuonK'Yul_6-.7/\X&S72o,C D=n"{3p%0?[43XLcHg,Q zQg _1?\%$!mt(N|w2g%~X\B4z/wwqܫ:W{ @uWKH4#I^ |YY'YL?S:Aq& V5~N dk#uo3 F=aEAc-7t/S:nZC(}"$8޳˼aִwťοjdZ޵"r}`LK.>pȴEZ.@wkV1_/CxZ}6Muĉ`Mw*&:eݞs}݅jZcW檎XuUy;[uff~/4c>uuNuW7f?֏cُ;A8TX!eyGo^&:~n>&[/YoаQgnc)k$m|{qnf˜:j-v76nڽ}bc=l_HاLύo_ ž]r5}<Mx-[+p_ "}&\m[H }>܉kxlݯ=mNډz(UG`Y.IT!uTh߽˵rvCw)Z^݈3ZλmȑUa$:yge!׶bx/oէFk=` 6WPLсH_}a2?f) 2vk&}&hp}:3Oms]:nu/͉8v?2i^&>> 8YĿy("{j[E`/NC`{|T9Q9̄N|'6N@cL?ګ:[|EZHM6j>/Y$J;w{RQkcz2{{['N ;Jek-g/A<:O Cx%[\?ɇT뻆3@[ ~8TuDY俺׹$mE BkR!u:WK- I_F}}C7x]jz_g33dM^:]u`/! /}I _o_o_g׻|Ve<մ_gO7z%)~P:F*w.Ʃʈ.d^ eowωb+/WJ *O=wrv۫M9b|[sh5iqacm#C* lHB_&,&YĿ=bpqO"?ILN.ҼSΘ?dc٬հw+~2ԥnWyn˅N:s>bۦ́VA-dggzo_}cTh#k3sc,DiWqIn=v`k;>(_=>(=XALG`}#}2G&GF,WOj^z$'.C^E[jzjOS^7ozgnaf=#?3] ׻ ;_If櫎kN4_2uaF]r;:O_[SDf0}:Uakשfk7<'>En3_0H뽫ǙN&9[ J'fߺ5{#뉽0Ҕ7WfxnxOн 8%m381 Z=T '6Fc8ir'Oݹ77K8nak:\bې{'|<_=g߯f5 H=t,OĶ?H="n! qFI`Q6^ gd<: /q?A'~پGr.zm>cNġlښt-f;]9 oox3_9^$fϧ\3gȟ>?>o;٫lN-ovd[FhimawoJxJxw-xj?.9ϝS_ KY\blC1)7[xMkHe7{77}7;Ͷ]`l<=gb1V`Wb>?DX?Nu.Jz?UXb}`|N݋ݭ%defW=:-1w/w_fZiG?8B_&}`ogU|hFꡪJq9ƹcs1^wG5t5&}kO]G9Z qP۴cy@c&O7HL 䱳qDFDhDz&qٮ3hRzvP s3ӳ'2[57eFQGjTtV_ ֦y8%g/#fd1t罢shjAM9Cs.#mWr.Ɇ>;ޔƿuST 7% fGLe/7+__^mg!3l GXa>2뇉i!\Wo.C$g1=ĸU쀍iz^o;zW;}!#N+2s Yo%zE.}1z۱VovD^ovñ7CdmÐ7c[S;szI1}d%z{q1$Yo;zPz6^o_2tYo{B to=۷vXwj~Ļ[o$mWȳsQo/jZٯ{}zQ?oLS e}u/SI럢d%z>w=pQHC8ʣLvtS5|/oz/u]%O#Q^?xVU]h?mi1r'%~+ο }'?J {?bE\5rq?Dqz^U~s/ cL5_ }7 a_/?|XmqUrY]sOk1a=CUGz*?Fm#OGY?["J!?Qb?8UsQORLuƢpLp- g{Io_]/<ݔ#O7&Ɲ>`}McTeS} 5p=5с 7\dr=m}\oa@6'Hbw@Yz`v'-%>>pC?p2*T"Y`k^~G.ᤐH11Cbe[#7Ɨ{w0Ӡ1z"?KswQ'Mnꤡe{Uǥ-N/g%6"YtI{q҅P8 -ؐ-^Z*'\s\ϵ{-u:U`O:?ͥ Q)~(܃MF}hC>4E.u_)bH\zY?{B1f@_3Z2Uh_zΥjzy\7R K+64ƣrƣW^2~wQ2b:\b_2=p?ϯ^8qOm`Y?)~xO?=l2[ m///LT ^ǓgW&N&O[_lFWkJlbadǯyz.ȯ'p_L66ѕ+йM<_5~P}.(ƿMm +փ]*۫dmq)ΫSFp*1Az pp4\Q*V+c07Y1f :ߡ?|fm5ڏ9&{qz.˂e꧛@N2n_aꪖF[CBT圅bD쿂‰pLY(\*e&mqjy:i}B3bZ͕_vwv찯ƶih+vWZcҋk·E΂Φ9"xf >a] <"]*͏p?=4g/,܅%o~+$jޗ,w˜-ˀ~?,x22Yˌ-e.͖}3YHRF9rbKOaK,_>]ed̜7[efs~&α?"je_}Z[ݎ=^Ŧanks 8aY6G~H?e1~(g2/0G̷%k9&w`Wxv/&7ئMnMnMmzH5&7ئ8;Umgzv(^̪c_fv5sPno$~~hU%j/sW0w5qZT#wɅ;sWa(ɦ\赁D.R^hZ+%W^< Y Ue l;{uq5k1}ǐam]5s&d6}=D# }IUϧ [2hdi%SӌGL喟j sݵ dzx̅MO鬗.|}>֮.~ @ǯu׆ GAtR{7SU~}'pqx/ ѳ_lh/3e":U9WgD6_KlӓL{ގ"/_wH BK72Y'mW έFy79JGק9At^t'k =$Kί3Pp75fzOܓo$pY{WG{>Cu~zO8?[Pc]'-xwCpȱ Aazr985ncrŞZxaI|G_E_"U#F?Ut 3[Vߵ wNW|]ϻF]t3nnv{zjY]}w>w.?*Sw6 1'1z_Hrlk6u(pc}}}] 7$BlBlؠ2/F|ױL>bO1ȧH |&i:]Ϸvհ VinO3q)+Viv51YF?ja?ص^t5e}, y_*;eY"I_,7;\HR#\d^rT^/JIY˲ e9eǭjṼ,7ֲrȄYVfʲmlekeSa&ˑeu,ˇYaMvY 5אkdYYΚ jpQ!eY>e9v)/{Y'pY ePg9ЦZ5^Y}]M^Yv)˿e?+y?Ҩ*eY}0g)j |MLiie4GBU;|.sYfH2|5-hԉH:]W{ey!27`)O X7\i7H.k4kq끋t*_..fbk'F; "(?Ota4t+SNCN_;Y;ҼY0\=w:WY1(gz2#ڬiU볲/O?oVzDK} L#(D|ѽzdNl*g0"gW4'+#Go"k5\`"-D,j0|;0_c?Z>eP' Lp/T"Y'ź\:T1fqE-~o/~Pˇ̈́jW}osN?*,'??,YA衹fݳ{&J sf{y45JUp\P/nb+J|)d'4_X \AFۗߧReA>_)_5z-MPטxZoY"Sf:ݳm^mҞ #?\MҺƯAf%}bA0`YMZ|^h]8fmO//~UlmSN2xTrL.S5 y ~:;UY'lgRLl;oOuoBUllxμ>qMlQwH#pGZC )fבfbU6~@8+ֿ6^hѾmnj{kiYG}=처pq` 23m{1,k:Ud=F䉪EaCE#`luj؎]ĿlMm$~)?Y'C;uɲ 6n m'~#Լ=Vo$f~m v`(GCOZ*ee跋\1 鲍c%Swr3d%6>y.H׈_뎡c ?԰hkl-"{*[2@KWG>֨eEt!;SNw7>l+usb_/=BM%fˑ#e@K|"{pטD|T^O}3jdPn[17L|&\+E $-|z&KuVuD%ZQ\M^S},Zy9ul"rx9e;r8D UL`S{vP.>f-?J6 LUyo+\l??m3Wau ޫd`_fHɢm终oqe 0g>&}M~% #kaƩ~uZvn^ӽ>CLb{WFiϗ >@J [7-~k`N" l,'-zG}.NY/#i\3 LU3ե8/Jٷaal>ҿ~c~?}SR/ġ+uU߀8/U;'hH߯3<lϮI:& Ekek[3̑g*5|H?_l;\FUM&_G:;IuM[=O[保п#E ʻ4G F}B]\#j-z 4kFߒXUdjgZs1[sFM>-KWS5⌏X׸Ja|ۜ J7ymRCc~;Mg<dGn8%Sj/[?|(?Ia'ao_H'Hj֪JamBͬ?w?m1wܳ\ vOf\#oWð6Aڔv=d@K"Uy?!iy#Z]Oø#RyyY*o?ݲyrqG t$.3 NiznzuBf#V'c*f#+#4 "nL+m3k:=ad<^nEyy4:\1HQ: Ohv#1nK i}rő0Ɣ*_y+'~/7{Qh:\"7cn(7pw$$Kt"7)Ln.;{™ܼMIarOn(7b nI5ǸW\t  p-?zx Tj}4Fc>_a9m7>9|:fq*aM1yoy2+MyJW3{Οf2yrT|ɻ|h.G)~yJ ?A~CUBh׌e;03vZ5L={/A٫Hy2^F*&R_<-{3+*!Obd/"nN۫K7cFL֒noGvT{>xߩ' D!k=3g޷=8*\<ӗ2r>jAծZJŻ]»=5މ {Nѳ=c~}P'U=wYUy3T$~ϝ%?m:pqϝIf{ny{sAk=WVz(yϭ3[ؿU܆{sA}=WoRyϭ7sg:OH.9\s?]^{ٞ[U{ϭZec\ME+9{_6\e:F27є|8As9wG{2Ns(~-gr]Y'5>=wM\e[@=sk7sHV1= yތ'#yy;E߷^ܵb8s#܀k{wm?fw0~5ȟ}k`OlԾ2r FYsHg_?1%SVLx/D^cqߨujx1߈Ib>?_|=~Aflb~KcvbK b+>B]rp}#d{¿QÖר6>&,oG F%W,4i];GaJi=+\3u-ؿuFkwZ im`K3Zl/d.o^h}uB=Ѡ9ѸlЌWZw= kĠ[z:b3>jo=`Ơm*3jſѱMxMmmGf{Fƣm<,qr,?|GiWǒmƒ7$,erǵ|{b#ƒ4c"ܳc3_$9R^'k? f,,{>eXqlBoӭYb|/Be mE cˌy\eO=^ s<SD#%twv}+T(Ku϶v54Nche3nv}nq5 :{ZU9#!TixRU#aci1 ~Nc6lqGEK-?=xi$?I~яjK<JYr5a|7#m3x\Y*_o_Jz {WB|*J-#$i/e\5D~Kץ\M.CHv̟%;x T-WOʷ$ݽ2()ϼ?/Uyi̟|-|W$q8ϒRk\j y$;NLbo E!ƌ XUeI>S|>rs8/mIvyu]% g8ƫ™O(1fe`,|>C~"1Kw1q/_0ܞ%F24hW7_T_WjGcT_?~ s϶q5|33,nF{#[LUj3Y)/TWB~|.UE|.ZZUyт|~CBY>yw<Ϲ 8Qc}yz퓲|.Jp]>OG9.sQ,P>m+/aĿ[@\^>%[g)W˧(ڻahw\}\ORli|~M,oy^X/ >C/y~X]>X -TezkO r)ϟ`}|>Z>{&gi+ʧnlCH/i U_~O`F !_>ZhHct>_#2 X ,-o!`2*+d~+WUZS$U2>;;Ư'YsqCNUyL˥W3|c@A-{w4suMg8d;iUlꊂ <~k@ք|7e~sM kӛܟܳV>=58a-{l>V4\k̍D~H,:\.[*eEET;>gUe eZ^ӲOiip^H<-L eZ$Y?%+~ҽ=2ߋa++ӵ7E!׌/WwHם$ua_ FUW.v.%p+/?3;<g6GIOS䧝Gh9RWfعK*XE媭5;_ui~T/倝v/aY 4VE#n<-7 qPC? r*$.,m_ye!UeYpQ~>&1 Y\D0㢾$o"Fz2r戆$O' c<J&zS+t:z{>G*?0?ydNK NQveTa-P e5Lv71>*`70ٻ AnMm*58}:zr]o=w34ZKTefMDzSOߖAvҭe ڮN119x&L8&eefxDz.Cpi(;\T*yvr w9䢉zN@'<)-0' l67A -:KmsRAzUX^q&#=AoRCbʞǾl y>:EUFw ^pAoU 矧t,{O9 eo9 {āZWx虆2*xdX&{Oa;h3ȞOUv,{Ho_)_eoOua-ݔs}G0@fYS}|VCWjr rroeۆܜ}MFl$֘2c3Ɠ5tGf=p q lUVv3UK_{rv,[?Bfr};cBb}w%ƿOܢr"&vw}5[;GOXn? KAO_Sna?k~@'L#y6_ (O5n \)lW'h{/>>`jzO}f >?x9j[Ž&M월p[E;`༷/]ϯ ;5}EPd8"=Vv`Vyj?? fxtmQA.6UŬ{9Jg_f.ϧ\G'ghUS}:~Z ϫN /緛;,Qˍ̀5Ӣ:ÚOOfvXS.zZï4x7K^_$lflf[S^0 +A[~ n+_N?iZ-b=gK i4h* ;JKs༒Kx7ͽ)03ƀ2ѲMF?{4hLS]^ ]lkW*Ew 9cmHd6G6 e(tctc \8e=Ue~=aK"4y}uiت#1}TkGh~{vf*F;w~t2gNc:~,SuWcᦞgX.繭y\O7T4<ƶ7bm]Z.~$$nXǗr721Gg敀O?5g!:h?7 AƠ#nX=r1pX77Dž p:tT9 +s}/M5~yGg75"S7XvoiYbL*8}7z#XUyHٙڞso \ GV/pN#1CRJ+#F3{V^/ NZ8j}jOVSA*){#>+Xhs<'{oVk1|VHr_ɍ<0H#u@exO"P n(Yxvd}B i#L6G6m]Dz3_ =(SrQwxv\Oc\I u)#X]JfK9Lcu)[֫J鎿SM-ht\&Epiu5;B!~@?sf~< >{Xb(=fZSgl94 1CoE í |Kgb/xy&}﷐:c5=( ~=lm&xZx!\L\L-bxTxwVLbF|McK! 4W>>ز?,l71αi3Ue"ā'u1wp.õgMs bB=?ZrҌy?Z):q- bC^L/ iX:\T\S\7sT솣'h4Hp;n8gNmUAnZF^{[w{i3N=ޠ[TI9<(e {yP)[}Eڮ'p1S=3BZ\wDrFHdn3ؾb3B"<?wUunY'p3! @3R TZ*~F_f I%ʪLSZ*sЫ^^t=~sЅw~ޭrZ|Ww{$˱\gWMA>zҮ*ρdMYIhJ5 c 탙|Gxy*԰/ wxayr0$SG OR3 =-xf(#xI kX6RX_mp WSN#lYÒr~ȯUof#1~pʴ|Xس+I-;ؕ`q16Uibz H7?zW1q-[ l7 H></V{oc8_?sןj/߬5EkkE4^y^BO7aH)+")J_a}1,m½s[\7 Z]3s*P~H A2;:;xGe<?C>qInllݟ;\?+X; ʺ*wϋY߉7eaH_ϰ3Xa\/mD@:ek2?`:]ݦBU\ClbS׻c}.1g3?!w?^;xU^s ݈>_3{%>B?d{a2̘DFcG{kL)"={cT~D1b[W}!l- yN!' /{v5kޫY7Yh޽O.d>V=06m}+شqݦm;!;-x{Fxw(+wj-9ujԎhֈ+55 %`6[VsRXVǣ󔄷-.m6stk=<cO@{ߏڨǟwZt0P } ?FPu^| ٬&XpU-' }x=|gg}Np]LOú>lYHͪ_8 ~c}"?= F)Y/P.SG.cZO~ ro330BCc?~9ys]gúG<\ Rö: z4 t,5(Uqo`6i6./ט;KSVW pH1w܀?Ae|f pf/p^MocZK5t/'?/KOf˛\mYg"=|5뻓@=f=D+^.akף:f en_ ke΀YcZB|ϳ,VVA7gߴϱvA~S|0g<^Kk5Cy/ZڴNos^ΔϷ]p(㬙o-],Xݙ3Θp̂3f1XQۨwxhuZLSo½c'z+Yq秩ʈN|wӯO0s6]1\C⿷c7K-!ժwfۍf\'̵2D.ϣ3I?՞) ϑ;N.d \< (~UJR'>G;D'g;CdZK/DQ'wk}ɿ"Fnԍϩ\K4یt _ymFSC T\r/SDo3j0_^3b]a.ՃjpN%_vʩ1s p}qyƇ[:n6s^huxn? =}Bg ë 1>-8H ]057`k9p ;}x􊫋V?+lwAUGSP|M-5Ӹk}֜wȻZ:|wy7-wɻKػ=[ɻ}ݕ]]w.ݞ4#'O*?) dROJ8zI-?$jOɁ?Z/3l OzߧJ }2t} [U*b-;'H ;,Tf_a~A`s&/NGfOm-7MDOx&I(ωfݽ2\UrݧWG3*YL'͝Yԉ[>E ~7\UrHo<]%H ʐݝ?S)R,&2dx\)|? ?5:%.fģߺ6/7h7Zɧ-ߊ=jh1],v?SU>cg}.{6oWb,;cw<}6}f~7wm͚}fewɻ;4ln8[H-n y7Gn3y1Um؏pyw1 9&~=W:Y0/ĖU-`LI/Sy<_)?ov7o4{gvutSACTLl>h’ `]ֱ.,ȋ҆ 7lɦ KnZ u\InZPt% }=<Ŕ><9~y>a"tЛ0v0KAm$=HA袁^r{|ml¼7`~nkqH~{ϯ$:cSld([Nm}<-ﬗxu;$uwH<yjP{z$c&gהdq;/m쬓w(<& U-OڿmGT͋0={1txEb4x<~Ɔ[MoPț.;\ԩq!}I[}42hW_Ygi7WHX+3}g&;GL5{q*}~gdJ~}cT A1]=G-lJEZ->L!TT!߳12Vϣ3LϏGLUazJQ?#Dgך>8=-n[䇗z? tM&"{\DTiFO\'U{Xjur_\~|5Ƒ*PI=~08l$v,8Q(oIUS~KboUcl4Ζ>0w6\"?{< EXp kn_e{i:. _OV?X/uǢmL]2?ŗIFiG3X nhp?7ʽ[cU/=RX1HfCӣByĻ}27A!Lig{ܶI1DZOѓ r-Uˏ$vpo\H¾t۟M0@z/Kv>}޺OH>'c-u*?OWꓱbD~郋x}Hf%6>Q˙{qy=& TqYO"dq9@Rf\p^y:L"wq郋̔~`8^y+LQ+/Sկ`N1f}""IU/zz=`7Ǻ#w~{a!27;";nI&90^C %?bGp?N{|ps|.L"*>lHFaHQ\:U;?p;ur[yml,Wʈ~ְ?GK3>=ȫp|atl̯-t ҽh_d`܊6`K}K7bFҨTˇ1~Out xoԼ=mA:iӖ)mZ:+˙[ϯ3h{d`051%]H "Q$"s.o#zO`~YuOl_c gc]/7pqa.I]+{= K3 Jq\xQ5a-+`qa}G87z\ѩq^Ffa-P?|{87q2ø8.oa\b?{ܷu\/Tf#>xCZߑZB"?=sޮ3ƒ{ѾAcv՗JJK`+{xoɕz1c&i-AO+g/Ӗfõ|yR_vz; =9|>U{3՞ޮ@OwW'|Pwq'-߿/åkpQO߰FM]y{՗ܥEv^79 PCY >[*|υO>|NEP}) >ɀ}&>9A"=?ׅ#Ey+e>$UՅڦEoOڱ|wEL=uW!Ӆ c]`/h?C]hZغ`5?Zkׯ$](8]B]ҽ4+ ?qϦJuRkG:(_ļpcEH|ȧbgi~)ɾD묿Kuy=׏ 𽮐)lgk'.A݀^7ԅ?x-D\ԅ?K:G|F*]:￙]@?`-Zq.tG4K:GNBʱ0:k7# :ϸPKDLt_rqMYίqq@A3.ԅ&H/Α!!hE]fx*غkj`.sG2URϏy;1R5ܴ9?E)J }#UL.&&S"ߟyZĵSL]1= {}gqj_߽ p>ýCԾ ޮط{Kվ {޵{~u~@|̒7]R_BGs/L'h? d}mDGjpY(1;B<:8IO;^#x_?wCNzZD6ĝ'ymM-\i~aCEօM&gjh?IG )z-x"42Ugn^!6OŐ["]ҝ+Ouz#}j?IBv)g0m>16ĺ\_lTn4}OKaq}&Kﭰ/rt%h~i3,Q~6Wվ84q(?x%ip:oc q<ٌ/U\ڂ/6tK?(ӌKFf\".RghW/{GC\·IrO zT;@4+SX p#\o*x)S8Nj4=n>V+3[[ռe`X'c$9j[3?1~"=$W[cR=Kك旱x>M/90FvT/%pֺ/ 7[@*Ox?p?R[-B7=:c|Ob07|O3.GO4 S67U{2\G"o2qEyǟdܝҘi<؏-u{~ x7^\3VU}6Õ^u>]"g%?^=_{1\ýAr}vg+xިuPg ɐIDk- yG#z㉳*Zޘ fzc)M2By'?H\_~q)&ghD1ꆂمgS cѠLvNLWk]lЁZl-g+J˛_)·?r<q-3߱@ uzoAD?cCzP? -/%~\?fyt<ɣGOlaG OHo3ǟ$s{vr|TwcoqΏ=GO ЅXdkEnTOM5u<eyGĚzx3ҚʠCjC[76ĿBцƽ5N7'Vgb!t;de>7Il[ {#}k%e{GT\_.3.ϹU\@?eƥWe՛q郋AwV/ǎ}+\ž J|>ũl{ 2Sj!z3G^3@PzZWk?R!QYC;?3cw"z3M?Jǻ'w$]c x_ׯYs;K;[~_-cTKaQӤM6WJiR҆wĘ#Ŷr}௧C d'@_H/㐧e9Ig^3mC;OT^9h23oݒxJy}v^'ͪ %zq׉b$;Viުk\wñifz|FV3;0z#EoU>5N3 6rwз߫^u{5.;Ԍ|n%pqÕp9jzzU04W;LwflP P^q*Yu7u^sWE^7W;@4+sAt჋uQ!z]`ŷ_T'ALbW&1F t s'QD;8NNI?vNq+H{iOe{A}aZ?kaENƖi}s&7y`g-nO_cRmuqv$b^N*cm=VS\ !@vXf܀0/͹{= +mv`MvKs!޳q5٢c%g/ꤽB)?W/fPغrH.٫굒sobvE ̮ v-3B0>7 n?@l@D\ j3 5h_oj }@gؗ72ϞuA^k;r"aPէ>bJKaݰdu/kb5^9ha.iϱǠ=b/;O]J}.?ϡGoec6y+;c9~?\ OK6?sNNjݖMw v/3V] 3w:I4 c''U,:i* li&6pe®2RjJiOeI)Qp=o16?W(5q`okl/< kam@|6$o@bo@*>5aAn -{~=9l(x<|'Qp`ͥ 7盘ֿNkoFعU Go<vlOsk)8~kBZjʐW7v[HՍW[mpݽíawO~{\ݰ$\+\0`'Wz4#ߖ׈_`nop8GOlIeRgٲw洗C-8>zI('xǥDp*'mlbqXCsA B.=m\ ϕ9s6@}-( 0!O0;8n:`5:/fNy1:bPH@\Vx\߰{2{Xی= SqpopuVb D\ggJ? +a?\բQ]-NbcGw>`qSŕopEW&.Ǣt׺em7{&q Uŕ}O*loKս%pNd+<2;mygdcZ:sΖuz~q{/V9k-Se{v1{O~8l1E}~G~U0"sTꏂUq3gzv[gHaBԽnݸ%S(;Lzo{!0H9~{~-6{O~'þ$H?GldH:/ye9 Ϝ>ylO,d@z 'LœM%}9\sAEt 8my DxU.$>aqB9l N!Z]q1BV3ʬoœYyV|wf9((@.ҳϨ\ YNgr*8UEk.*-nx.TEcN炚sc-1Kԙ{@RȻ}0>hJy W.KAJmPXMz,ĖnȺ(wJa8J=SF-y>cu؜r>3JxBxVL7,F8, p^gE4W-K\W4v\Hs#_m#? 'G>p2oՉBQx?=Coy 0ӨM4݆y؜ bN,%eNa5:t\2qhcN_`^ԟy't^Wb^@iTlWeXOZV,hEA7:^4SNgo 9$DrJ:O^^j4|7I9{NFh,?PN)?J}1chJy1zI Zol^y!wrt≎WSQi@wg}J$߱Wo$]fS铴hoxF>>}~.e0cq=C?EiCiD1`+$Hx'|wD>{j:v$j 8BguyiD+5x:F~b)W]h: Ӽ$w KaM9Ο~Pkӹ~'-$ u;'`H0 dlœ&s|ZUBq.čD{`8ZWh^G=ӵn5g>sScyc2 m2}󡭗 {v1%c>c%a%\/cV1o{D.;ɺ\$.[ϗ{&|V{\&=*Ǯ ;JxsyߒsGW-}u04Wq}Ip> Rqu,~=g.OHZG/q _[UUgGkaW?H;S5wyEU)\ؙ=.L}.U\9BWߴ3ap}=b~usII_][X<^zJ󩿵]z59!߻B{Q^5W7 |M1]Q\70w#}hhR޺G^iܥ;=w{|E7 gM͒= je+*ZYg/^zi"qo;-a瞧jgWV꽙V֛̒q'5KTba_rZԽ^iBѕYؕW,r+h0F7L&ZixfԾZS(üin%bws& Ze>Ws9ݥ[ ~UxFkLƺH:O9DEu[Թ_[xoX+x(2(dWt_ơzD.9G+!5CzD.'V;ULGaˀ}^9q:ʐ}HmEDlxB?.#0nIs2~#=KJ߃me,/{ ϋe+{yM_b0_@3{Z8&j/QF%4/K"Ug0˷;6I\i6Ky_~%?tg~yf0/#~%׾:Ws](&_DVg}WoDn#/lw޲%zwU*f {gy3g:J :.kdt<2_Z3}ʒU|f< J]cW7•7\7Of sz%,޳\zD)Cɶz*Zl3Tf?ҶROu]qrUC^Rs)瞽TiaVW p8TmHheѫ4FF{FK=s@+/ RNãY[6*f-&Qbˣg 6e~`Ʋ([>|҉L啤hO;>Z<-{N[C}F$>(]/r3~T|QOfzU|pX:\"fܥ~"}KTC_f1>h=i{Igヘ`IX r 0|Jk_My@:php +e.rm%ګ^U!*S,t1Ŝ<'Lf+KuOG `9t1G+^Q˩G\& ],8"+%~3 ޚf5.ms5<Fp/cg,lBdƥL>[~Ɲov`Aϣ=.H:VK=;HD|3_ܮ(-`_yA׺s|9t/m̗/^:O,4E-̗ v Dˍ_,\=f c./z˗U_/|y /2|0GDz3_VrA.??)|ya3_vm0KIY;_vm1巂n=;#_zZ/d|p/}xBܟ"x|yΗ sThPevvݨ%]k~k "ZiċhRy}tTx^5ATmn?pv-ow/`:\wHxEW{5>KۺCn]kMD3=J*=fm237Ib>gWGPkE<o6ѣ]}r7{{+ARɕOƚc"oGZPykUc0 3^Ti^eF3?T4rϴ_|rzlgk qG6?28kȇn/>D8=@Ylf^9U b!͆XHѨy@gDڼf͓0L=KPVl 뎍_Slu>ȁ&R39P=αot{ekMq7xgWE:ƛyygsQzMqiVL>Dkuk{(^)6o4-e'Rl5Vݥ'9cDlygr4OuO)|g |ʈK IEgǿ=xrHl RJ A9Bo0`.ҳAVbO0=,ɨ֨rS\_Kt95zc-xSMe#^~z?<*1/hoO'X<\c;؞DZtAB?pCp "[ pG۟)WFw {RFw•_xn %+X/1=]}| ӱ{f]{wߖM1kwy>A!Ϋ@;켝hաWvNa}>uyu`$4lIt i⪒_xZ4q}==?2|} ?J, 0?~dOc}4~^ŕ?M hU(UKccRg2:qUJmy?ϪK`量nؓz ^dq=馥/n`iG+t=Ͷ=k~&[93z//ZOo@{Wޕ/_,/6/7w.y^uO흥 "toQձ#Z|?SuH_/${~1/흏}Uħ2{'p+nOl\Og{qT"J/sE]=)#.KnOgmpE]x} t?_]np}]&?IWl@9}w & .\HUq\\i勵*.7Os~e:$h_G f\".7K 62TqMo2G;{>n+:S*Drw2 ꙿ&){1;NOR {k='ޝw~Qz>ZVJ~ ].|To!EzA-uU᷽bݗh^A\?.1=d̀kT\+^O?L}'Vd?뼚.Ӫλ y_*y3ɹFצ/Tǧm/fG? ev^\_̧-:u~N7XQ(?.Ǻk=%?0q'NbxڊcCapF%?~U{YQl\#t0\S$x:[pO.H?"#H'O.Hx )\}ߑ ΐ/Em`\pN}v.o/Εyfn!SrW9t1럿GZ H~Q?d|rUOms-k?+:˄Elzem474cC5R:3UDw+g;W|\q*&Y oVΧ6#3to-K٨WLWM~Ȧz :Ӣ'm߲)yU{}>+4gk'5b~cc|9W&z qodHbk7]YzW~1O\#)5>1d;޵;~}B/.R|_l&TsU]iyiw]k5lM?|S'swNof'gsoh43snm{mc3CNu-ۘy֐{S$aSD{d~/1L:r\~rYD+kVta-Em:$_Gsd;\.=Ϛ~O1ܿAZciL Y4Sxܚi?>E3 ji`3z5Ajh<6 XKRn?㤵F^ca_\|([兖D˪T^X#̝eKS0qeι2C(1pR݃l雏W[)Q0~g3=%:6?|~M 3 MI=/?dz|L߃g.7%|Ohd0ߓߜe6#=gHѼ/ R&4֊{T(O9<&h1J`e0ǧT쿟@d|0NL 'M\͠P$}krlijB=μ_?8 f߄ka+JoGC7فPZ5M Ĺ dbgXIkiLY娤x0ߋ=J(|uw- | n:f6U뜍;, ܼu{_Ĺ8S);kl ^t sDO`k C7$﹞?>|_-ۇ*c@ϻW{z>g |rƕb޻pհI:0#QTNxjlL+_"O^/w˧?ISSͺpZ*>]FIU>꟟5?3]9qq3?E[OZ=e\>E4coe`7  );onexai 'yTa3TCWg.J4]}OO,U);R3 ㏔tF쿲Lz3=&u>l,g]kskw[myy\b6qym>gK1浩åk'i3M\\RսTڼ{g͍߮[/Lیp=r) 3/r؜~v<1J{JW>Fpr%6{#=44w:1ť3 tzmXGgwTq?dN6οO>f+?B3$g8qU6"2dg4Q+zgA5NB*b i'b4Z%b\ 6NZX _lݤaLϥg&8:X_I~7= m]7o}_VlL 㹬cZ7h,3% _??G(E=&T78 Ϋ'Ɂ|h!wqw-[?Ώ>쯟]ixf8ǻE`-{qNcT̀VOGFzk/+Jqqm W/ Q^yl m"QyXS2c1v>Vg.<Lc.@'5NsqRaO%36>t{WR>=˂wa^nH8O; "d{x}Nv{q_l)/^ Yڤ2wl-h: Z[it` YҕAׯ^|  z>twnBy _5J}3J^#pײgfB~%3#އh?]8ЉҾޖN'- &֞w̓aYb5P[׀o? h$y  1?j'sK. ;Hŵk2hwGM3BIXۧƼ1?wyP:ba?s^ko),^{b+twںh7mE*@sd{^H4GzyoUe0ѽJRH,i&Msn-j"Nus;$SD6c7s:ݷw5Nw OVg~ )厭c^UVۂh!ޓ$s}R~[POw x??N ws-H\յt*/j:r2~f1Khu`3 :lS6Wg)o7+S=K uFn7)6+o(P/5xϸ 6f܈l,^yTv9.?qIoo/^+*z)*+Yۣ,w̠kuTNDx:\]H_G!lWc7_"& a=[\\;H?y4uy^w075| .B4?_s7w<-cʑMBS ?n?OKondWՌ̲ň; `cбd?fW,dɵܥ0YR14:|zsh GԽ4 B[gj8jbnW,"Ng1Q2aMP»F2yq)ƨӂ?ʒNph#ֺ$Y8NУo1ɉjtuta4цO6?4>$!ˬkTE_[/Of`nUG*q\OI4]SIGw[/tt<˫Rѵ:k,OsoKm-MWj@]*"&5 \ρw(M?]l?i7Yo#DW#\?ӥo_jSӮuˈJx9wz_=mR0?כ uRkz3=tR-͹\GiW`;'჋ȕֿ@X_EB1iXE b ?JHu ` c z2ц͑~ÙOHowanX0os[J;\?k\Fs]3h,6uT:ǥی.3D)DSiΤ+O+S9ް=>?h8h4[GRBx[Z?h8(Gw~ָ czaU/COÿ9Kl~5F#ͤ^W4[h;hHCߛǤ %f]]l[.1))!?ͮhYwMf 5Ghf1\1xẽaO5oS3GÎHߴa|oGNl;0~ SVUW.﫩dn7()ZµEg<4UnA' V̄mQ8_8H$35 \!1Fd5a~ƅ-coG9[J47 8 t GH2ŇWa48/h8iLc9z 3q"t$xn y@ĕ8l>KB1t-h19 PB:%r.H]u\YEaz&3ݳ;\+YH tlK\~LgQcY/a3~ {> [>8.?pޟ1nQ"qum%,a#ݿȅϹa^y%}]p}z"Owg-N4j).X->Ow[8.\g}@OPab[|Q1ݵG~žN__/fs{ݗ,Xkm@ځ'T>pC?0gоt)>3B-úG6X}~o|,,`8i/vv0ylO3W]\cCocm\mMo{.;gƣE/Ff<v;q>t_Q ʖ6c,/Tkap>F@{þor_7d#tw7;~@ S[ӥ\=מq6`?}k` QRLm AXU$%fЁ3bi}! ?u{Oa|N_x8~FZz@ZJ+06zDq-ԄalK86\_HORe[(Ӝ2gCR~C:Hw=e*{麊3ܻǣH~ <37)a}z/FhsXh߷x{oߠڞe`.>TZ+oUWs\M8wӼs='. ln. s0Ds63txa<M?ʚdbw7Z:n7D͗+\4^Jmj%Vs;<,)g. ~}laNq/~0Sz >460WWߓό7xnQk^Mgݘ&{cؗcJ:9<@v~ư/W}ن5ҁ gl=["qow8Y.ғ2wg;.E[,:?.L,bm:/U.2=vn&w'nwTXl@ם7Qbs 'G3%`I\y$ePsn/O,Y>NE(O`^/HRN{V=8eTA;辇a2waرSzHzRk (g177ix#ɚ71޲Ltx>_Ct LuYa޵du4ӽh.v$n  5B`](e7;'x!r(\XF4Z豅L+@nR9gs%y3}{}Ls}m$B?b8_Wp]Ds4t S b*-~$_G6ra"b*gb=l+*͒;FdozESQNG\4Ͽľ:λ~av'Hhnr3_kQNS$4Y<=D\<+gt#+^jnt,g]?wJ\{7tjtP Y_f/`2t_X#d v9S'rJig:C>ۙq zik.J2b_uY,$94_l~ z}"y6:o-X}c n)dKv!K/aOsI;T9g+ \%x\ː-*&xЧ WuL_m0ևaةm*HA㸐S٨-g{nf8n/z8Bj 5aiO,F~ޞ~W~_rf:/?wl聕,?We],~R~'2I&|!-y206~^_~ll_n4\_86!D~2yח2LخFz5Q=xLhgY=xO;km:0q2Y*o쿫 {=Y;dt~_m@G1Z'z=ɶ*jY0/Oe첢sSb)Awy>hwYasʹ gҾ TkI /yMu1=B/ݶ+*Ƙkt;ZHE__=%A7Ƈj S}Խvԃx|C@_m;JviPgkUprK+ɇPt]L>gښn]IpP>0Ǟ61)Q|yNBCTN^XG\JW/6k-6ha?ƞ3%CZ)~aADȢsK~DR `t.c닾oYcW_o^ `L%>k,Af,6K,oP?s-$jG4eZk6gY<4#a@G1G\F{z ŻmTퟞ%Q- gr^ycۙ(XKPHK*WB|f9/H3IٍCq$Z5W*|:ؾl&qlG$]PM5~% wΑ||XXYq5s|FsQ?HDl8az9PƗ}+,F9gˤUnEI1JR RҺS_kGW-;>dq$W#֖$7_a;,zJ}t" cZw1]6}?3 Ѷ. 7Ec6*b1O(p>7LF/_g17%d@>}fUENa>_ ϋ,WZZkKm>]on;Jm=Ak|[ǰF^\i\%, rVZd;cH{*Gd+`; (sը_;ca.0T:qeu#*I{glbץy[U4.P3>WGNk>3ꑘcó'J4^>)8gнY|7r@ύe݅HWtt'#]5LkysAw̥>c֑q-,n%'SHXL@ӎwi:ˇq6&Kk:m!^bm kuo]2.1e\K`&OLgDgO'}x8N?iSEC-DC'"6p~ C.4L/\1GEkղ>2a_ :7lxg.8T~!,~"c)xu3Jk7R?!vry;;%"oG ȣ/{ ~W*giA'{M1jČSN3SE߿ :"[?)n]mYĔ~W/Ę7&p-v /q!^sqM7/cJk;1;oƔ-S6 sS)=ߤ ;rE4"݆>!Z!xh1Uy<7ƇW&BI.%jӏ-XŔj>)lƱi5rS'>}i?#jnȵ1I Gڪ#k5Ɣ8T$ӻ_1{+%~[+o +>yr Gm]KerQߖ~#ύg0%[+y]mLtߖ?>vGߖs5V/%R7I9.w˽{fۼׁn?;Lr_F̆W*(iod$И jGr>Vjd_Ͼ~(w9 ?+,x t?0v??ìL%j>Q^IFh*CaD])M쏏suޓځv,a׋{4)t|NcM-7!9mN٥t t t}cXy>}Xq0˨VC1p.DǍXol|0 C>}ZJL3AȍӘ[(m ~ u[)߀a Q[]zQՆ؎[0* [o`<9>Ɔu{xt'`+&7X1:@c5dLo"2|ꁀ .:eo0Xon9To|sC稷> ^R Vn۳^V<^ O_cm1S&cwP9s>\ ٥Ы_mlCDƓgMLt-z v.u\~Գ (wty~GfuEC" 3Gq>4ֿǖ5;Y.q+A};k<`EΫC|`I Ȏ;Qָx;"soQw5٥T3.]:еonj߬pIԅElf\~!ꎑf\[;Sl>:Ojwb5.] F͸ؿ07݌ F7AJf5y~ }/!mJՋy@'LNFܝw-tmlG)Á&dw͘kD>֌jv}yǣ+zAE֘'̌vf1fan󌮄@7̌y]Qng700o!}`1ߎo0.0?tR`܊k_{̿mqo1 p֟e7IQ֞0|-xj|'u"|Пjhi> fN|F*h=j~w&U)ϵUck7s',2{Wz ·؏sY_]eiU<"K)mmw*ѭ.WL;#ǝG.>*Q4g~P D #?]$ +涮;ܗ#Fw;{Y)(ՌdntJq"/7u{by)w?>yGNFW^wjqrއ k{K]c?A> J,j 8150k(QgOm%{VWj^/q9q\>G+ `QJhlz0y7(#x\˴6i*~IVczY}%j,_mvvD^桳.n) :v|>Ivh'HwUh4\[4E/G/?]_W='76Ri9߆epsm[N2-F*NbEk|X0^lwwj_Ƕ_/oEY)F91"(=/>:?+`y4=g3b`s Řy~%5cKQC975+{r^X#6wVix5a/Z}Z,>}IM{ag/.֊D]ݑtuX/\ kq*|Of|"U}6Ж[hQ {/}4r_WƆ._u5X#U'za]06 [vآCWJ|б/za4;R*|sߑK>{瑤cmsuXIS_|T2Fc~X$Wy#|Gڀ#W,z=ւ]Xbc鬒+^W2oϼ=?c+X>YH~ۇxo@L=<߲s9^lo7י'uz뉥H4EsO8CO,OX]M͚',?џ@WMOH6Mr/Bsβ mb5|Ag-|½WCO)3r۔Dܝ=$r8Q_Y~e\mVn^Yh1fVڧ/k«%/>E>\Z]%* Njjت? >UI>!aBx> ~3ㅏuc&C#?;} ;˄!4?Vqo1C.~&-Vkon޻n+7ߩB8}XqaAu,ܬC%J0Sw9fXOB@*p}-ۊ @1gE[G3^6~hvH!ȑdr8^{6ɾw!]10iOKwxV49c[{6QgVq4濅iXW^ v?JŞvzoMauhiOR˦F;d SI㭈fr~ eC%A=6uyT=YDv+ӔG{+լ`-Y.nۼ.dJӫuZ>.;3y[ϫ7ϫ]`^-_HC^Kg'k\['G$OjSզΫMϫyA3Pxo46y7jPNl W;u^c ;j_no'XbTi_fW{u>*wW+oΫoΫ=7vd{?Mx~+iq׏r;& D͓oxKD2c Y2wc[爹,x~}.5W5Cs=(?sADy" E|@MrYWt IuOtMk\ tGQ^W.fkzϞD#5y<"B&Ȣ%wNCH#x|Ym]d. ]dxOa73QzXN9tw\Z}}{CGqH"y'$Ye{-7ȪT?:\7( >\mXu wٝ!]TǀSymJ5舛m i_9?⽶h8>A륱W@/mw(_ymg =L3@%35gܐ\?5f.Fig3p3s!S,#3|#D^>o#ʯ{vΏN"Gopl%#u{F_\^%&̏d`QNRA񛁜i;ȹ}0 M˧za8KeiVbߠi1D\meX7/_0bco{'1t0ϥZA+OGO3{ fY\ʼcz[ƶxc<{Gu<QxqQ}(<~ƓW]QFx8!O_ׄ uJM9.3vh9^kn0UR8K@ v3s\ uĐ jCq\jH׸%zD>6DE"؅$\$Zp3ņF3.}3\|q1ba`\|6 >\(.;J>4S%h |W/s-ٲ\^n+QO4[~|kTH/0űɿ9R=\?wUp_栎DeGXyMYaSl<[.IZ ϰI QPz)墟}##;#Z_`~F?CSk Qk_^ zߺ8L}90yg:ֿ ;[Y*]Es#!A DH ySVu g& w]_lϖQO>|Rc}/𝸾Uv& |bh8+-hEIBs\S@hyz"7J%{"&dg닱QhkrK3e)W&Njqtן7Xe}sɽxu^ϛGFd=`|xU/A[0操O?7| 5ly@Ӄ~|dž:BQݦc`lxfEzc" -n躋l~Jϧ8Xݸ%SϺ{Cf[w;\Y=GcTswm(sg4hEw/eOgdvԑ~l9| gh'o:p@O8zr=7$; G|L7=tEl؂6"ϊlFݩI'ѿ|C%=^{\wP}\q\: {-<G =K6+_T'6}q cBq:ƮHJ'1ݱMS8XDԌq-^cwNQļQ=2o2F]Jc;ՌRC.xW߸tG+{=ms.mwF{elܮRs.m׷k'nΊz-G<;9ki ]+]<_Yv$sԦ^l O۴KqH?ώ=7ԧEm웜Y]KZ这c|֗>*%T/W`Y0L]rộol?Q @epyDw ҍ:߇);G{ObZ߀>"qXQ]BaBg/B6q<$j:74"t?xt*˷έO)~ "kQJ ]ħ`{+?VHwG3WA\~ƌ߶ S 4}ݹbKz㟵<%h%{g{ ʆe4,ߥ~d [65ަ4"W{[Pkd?z|}):Yɘ_ASo>?3T} ȿݐe?.ֻ7ՠ@:l*w|S\_A{r7_$s.ܠFMgrlAqv{ȱYS[c/)ȋcM>-wc\<7xJn6Di hg%g /-k֯kY`;jH߯_Asnѯw/v*Q׊=pzޖ:}^:~FAhXj+VVYe@;(OMѯՉx>po#]IZHZ*Y$Zo'-L{Kڞxg3TN vqN98 ieJ6%/m:T/-Bמ*W4͚[_כo1o[uLUAggłmf cシyR*~G^@o$Jx~ex^';z[l`P (4dA0{ 96QA`_i_<1Wαs/=nAjCظ\zcDl;x q9}X>,r{MZ ߇uL4);HIXcg\I@k켥x><`I@!@VUKwE?oD@W]\^Ӊ~D8Fk*_fX[j|u y_=?u=1\GI|dԾ5 RJ yVi1"lbt<_+ſ͹ti`Fqv|x^)#M?yN€MVwa.׽;0NyXp_Xjt$5H4".8@Ewz LTwd-&l`~=M,(? Ke.n>?&b״z^X#?{ {+l{]G4}8^#տ{ }!\=&s?)V>37[v>{FAu˱侃x.}lG_SPgCGE#xLbv?<*?s k,lg8}5!μBrC^R1L}}`ǀ?yY -ƃ|H5WK/falg 2dth-' >ۀ֮ن}]S} n߿dZnww&N9Znwܶ,mm԰F1v_)i>D\s~#Q5 oܑjt6#{*C5|n8r͋q ;d!gBxN2j6NMΡHUO Zjq6{ oK,5x-3YGk"c#k;kb!};2w~o`;Zݷ5P_lVS$#Z_btkeo蝵Z?^eZZϗe ʴVgxV?:L[SvN3ռ>{'DLJuv5cUXMmyV_=uyiNqƏHkL[eC-C>WM6zw4Ko0KLޤQhos jx~u'Q-4ɺ'>~5`J5?{y=:; c/2'\je`3(5`+j$U"i z?.j\uӟ^j1yj4+4ݸⰚH82t;ѓy9c?ɩNkBly@i -|f+ޱeN}eKoq$݆uc5]΅׍uChucJ:DlF_{׷X׍y8Fұ^j׸X!?x8n %ZbS9HZm*bc36'X!gnLHV7&~H.֍ ՍfR5%7FZck ۩=ǫg1xc՚&=}\C5SiךWԚ~5XkF[+֔A= aZ3VmZJΑjjPYs둆oZ3cFajug9|Cg7??[kfLo sdTkCs}{Ql5[2I:0՚Q>(g|Zf߳9Z3waE[0j?_)銺%Mo2]AS~rqk=Wrj:'{,ޓnԚk`֚k!ϤZ3K|oy'09)8 JIu8}|dxq>~a:nMA//BМ{Y\//i|}q|$H1Մ,:^#?>T)v&L"qG&t;ws5(h>va=}wQ/& 乭 ^Jt>:!,wyg|!׍oՍ|Wdzv3ԓL^yMұ[ܙY%K3lL@/یjx^^U^o\OIT~h/}(Ӫo} Knw#F#fK3 ϳIcg8A^b^zv~YL=4TuS^d|OAo8×[o8;tx> )b@^6U̠u;bK-x\d}?=(7֣vѣx}M<NzD*?yO<ѐ,+ZD!e=k7Zc<}VϏ]1=z~}Qn=s$l'd#ϣ&GADavUkp~Er#ǻƶ u06|-&4㿃w '.zqIsu|rQ=v Wy'0.ݓќۡQ6-WGCՙt0kٱ8ṷ1޲zxM;yc.Vi*AۅE1q}؝mR~|^ 7ZYy/W]u/QZ}[>^9 >o س/+tC |[elGe/%?u!n`q:yL ˣ_usyt~.nwNGI4'!Ƈ1ݽX[~T[2 c*ll7ƆH>[3"m- ecR{hQ8o)[ޯkub[F]K|\G=}t\r0hdc` Za V/֩"5\%W#Ջ%U?6L,n |+hHwNv^4|w^[K{W;'gp^W#E~3N\kt QH997Ee)DY@/!P:{OzsrsCojaNM8.!?ww[Ўf6M^g99:"3s!뜜?{6F991?7* f+9DUO~p>S[|J>Ǭ|~LU1Ydž͔c$1gi5%CyYcv}>f| c0rK1ݣ}JT֡1+izsy5%}D9vBeۮt%ow^ 􀭹]dLTw2G˟IX!]n\EELL߅oG/=rJ{: <tn^suڃVKūzX4ۓIk߄N‰2& gިP^% ya) o-ww}X¢~*`oTw}U4r^1&L6LQIT1 s̘q8iC;GqO:Xӄ --F(Z<73MZcE}?j5Q' <8r6|=V~zX:_c:{)}u<{]s\ R?絇z9s1'%ܥiz6b~x_;k_@&KOc$/z~[`~?:۳ؗ6Hg{ Z!av d.onN5QuԵ^nwӟ65/䣋6^ "r9"h|Q[C{7m'1v'[!g8Q Ib-jXC#=ŲVk\D4"h~nEgantn@I_2ѕpQTHf\>I߃gtOq\..k.n]dƅk~Vo%j3.܆ww "?q,G@7dƅ;R?TP?.%f\".R?&t~ 3̸p׮p Q̸g>(@_"{zbc(Z"jv,,ET)3." )f\0. @u,3"pG@Dwd7p6wV Ngmyn}ޡ_6cO @_"{ڻgMMs͸4gˈjoōY"o+ @w7zHbn࢘?^qљKX!p4@ڭIf\-֯W=?.EkXn eYrQZFd[qёʑ@wJ_ڻ >q[9X jE{~~?(͸V~& se\} qW wҾƌ H̸`t%\Nc͸E\/: \%XJxD~v3..nh\bE]RGT\}z'["rmY| Q.[?dqJXn̸E\ߛtD֋E75%qq}~풥o\} .Jqqc3.6g:ӌ 09F[_3.]۲@>$W5. _|uwq<nYQbEX~Icq.` aI}{ŷ.qq 嫉f\d8)%3.B Iۿ%qt3\,\.pq.3.k.=s) \zO3\,ESf\|iKh3. ^+ь FWE.>{%7X } _n]\F򋇗qqHvLjeAGr =ůXf\7%m0f\ pt}3.] Kʈra>{n"G Vql-"F3.kP"w\} 黯q1ff\|a90 3.Y/?Fl7ѕpqᣋc./]\<^'p:ߌs.'̸ԯR׷l.Wqƌ,|QΝ3fc'73ѕpؿ֘qᣋ#ٿ7pCEKfb)f\|_'WeW#@_b sqcſ pv|~̌,Kg+bؿqᣋKÇt;0/һcp%qqv~ /\o' \3\X9ӌ3Y:2A\7ی FW`iƅ.bdbᢎ̨ccELk7J6?.Ef 3qahŧY0(qfwJ̸`t# l>;%7h!nNOzzf\4k`mEk~'? 1?p_{:nRwkI)S{EAf6QWqAǘqZHf\".$7QfEY ŘS8O#2esbsaMma6`#(]lk ,"2w#.PguKh_-cugиN;/œ,7+[h 0a!68[y]ϙJܷ\JW/fqԱGO>:qw=1?ٳóæ zg8曬oo)(̘?IDdq1b+?>k̷'1ߘ<8O3cb~nå9ތyFW@7Ɍy]08 ̧c'`~b~b~Zso]LdžWp7X_op%a>{;.13k6ьplq_0ߕ=pW m|`0_`1_0_!05׎Y6=O/ =ڌz\S̘OCpu} {&Xc)f̟H1OZ?P0V ͘?c30%'5?Q|;`?'v|;b]||zY`^=~?ۻ'0?nygbyÕQzO lwiY֘L3 /fn ᲅ_/?nanHtvyʙqZcޙ1Lw& ;'oov[6zs/L4c;͘?kyoC$>;U=֘??ߌcs,'Oj& _/4cѕ097cm$i|,p#;k1S ÞaM_X7?S-O0?{.1֘?c? ۉU.Z)@l:F;/|2?E"k% ?w0qF0$0L3 :O?Re'wt9?恾|=|Pk{-*51M?(qpa󌮄Gff"KtGwM\1?pyW8Ǽ+\`.0rw0CصcCg,tipkq`yo?)a{Z?g,1ϴ'?!wQ[?5U1}jZ~p~S\q~m8gfǂy7ך2A{(8?;;' E ni-Z^WS rpg(%Ȳ'ޡ=gn)h=XLџʵE=X dlz&;/Nj?yJ<{еkٯJkq -_H>?dMMR5S6OIk2'c~GQoSeg. x@TM 4({-[DkC|2 nq.]'5F'y9oﱈ5gc-mq1g:$'0]-U=GϏˈRc!o8=̏9z~<rfnN}HtV8?NJ8fdA#?66WECp~smX-q75ڀր"Nb+W~bތ>R}ίѿ(B3+DNބ12(,/|4G2?@!E@=k>K SYrtT/:q `]erzp~j/36Ӛ\EOޜt-%ʶeuA.~1^i,3'JܿZR\okUP wS+OzG>~g%|*Hr=ړ+L5~O@#nx9B9.!JŊq;G܍Avj6?Pخq?Kc7 sřqqXװF+]5\8Kc3rQ|$-$|$QWDk|P9>Z&#GVs`|1|dv^&Ѭ(I{&r,_QVoUe>Qz} =Y1$p{hbsT{Gw%-,oӽỬF.?ϣ Uy9z;FfsH$#|sh qтnes`x໚o(㲟y\y\ee\z>3<グ7!_4J:<$EWhy_9 4O?vWyί)ί=Jl mO^gALG/_alq=o8B3, PG5v/in?xF:;F ȼrZ˜)Ɵ@yT}@pwbL6ՙpHX+T"?H HU)R?.2OF۞\Ug\sYwe[3O/mxv$y G}PUЃ[HAqlߪ:_:cntlrkD{p&㣙|q=p3|JE#=l9o]#ux)qtls._-M)2uEkZ;sq=?իao?9nYKk^]IuxϢz-qWC]* `>*o Z܋Gznio^MZ=pZDu̝OuxS _Vh|ij|Xj/-)kq#q\AjXsv&J]g'b FiaxO7>qAv{Λ*hT9m5iVw߽ic\Jl.ͳ+N ZlILޕ}s@G,:n՟ߡGOX(5Cs" D?)\Np(i=27vQ =,8R6Kwۥ8%?x_o_Bi{ŽP~^EW9\?+k1)dE8(7L FB(\V52C;5P~yLm-C]+GtQ~#޶^nwW{ʫ*xϔnGy1k$gޒ@d܏~zJ+3ycӄϷ=VgK_*5[)l>,&Jd{BR(- Edž9hP?5]kq n,Ikl)O3B( {[(9Fe˴%7ׁ.dꛌIT/}%}fd3y: q;K~l?NDy }lֳ })N(n?PfKuZܹ hF  5٠ 1cph)ca%E‹('H SruÅqӰ{K9. p?8WW^7k: (#\Vft/7HڏN4\sfk : l\O;rsǽm+-8gSϋq't:ZNBx\S!]\p Qyަ\sFkU6,Zljk:1!6VI ck蝵 @~C2F`q~RgVOC8}ޛ'?>^1 y(3ӞټZGjX+ >ov~"tI9>]mަ!}h 5(#~[$<2ӿK{v/˵fyו73}'XwS4)׃jٔ:Hqx~&w\8?5AЋYLZ`^y }ﻓRP[-z{Vig:ۿ]/5߮`!?F>JE[߸PoE[Sּ,Yv&*QvG_@SqbCg}LL?jDƞ!Ly3i'|/c)- n&m}`lO%Ű3(o@ϠOgJtѷbRv: ]W>/fX~11*[rq<ʩ  rUUe˛KA=.Ӷ 脅 XXXP8aɄҠᄥ$NZXju^9Bp#:gZ{gk;9gu@m=IlY=ۣԤ襯P*~wpe!~QܫoNd9Ḗ'O'O\3yϭϾ/ BAx7r-%?!zFl3bʁ<;[}MBM!3VG_7:퇩i5kӞ?Ϧ*1/PƉ経뭛Yb80)ʷgoT5~SE,7Fݜu.U7 נ}f_mi0w몓ݏu3w}G|6XNC]LcxWv:sR_?u5\20stƜ0EAj)}4ܶ-\͐2uL\~G]?/qZ1ibMӝGٳCΑ5.# r GH! s4Yph۷W&B9B:P YhqghdمDS֒D{krءoz9{pjtm*D[wzVGDh\V/¹kn{_ј\XVv>,O{E6<0 grVJ{VZam{|Yi]Oib <3CwNV:R\rϼUKK S*~!KZ{@{b!G&qym6:aA,O,,Y VQb3`\=Em@I`oS⇮1k{ίs~+i3? ߖ͸>jy {͏{녚.[kKW1'h>w=,hybQz+k6d rW`uǂ3F{sy&SC UQ|>KvB^,wUXKbG6yAu|n~ Nb}#HKK|6M Wdfe,.)B,`jx]iM_ږ, 6ͽ] f]LkYz杤5˸e*S }P4DٜR\X_.LbV>ZĮkcp\_ﬓP|\{k4_G~c_ʻ(`u`g1.OJAU3gbyoΚEg/9gZ 1YgbE3Ѽ/s` *3YYZI+ ^zpoigo1ݯ!?ױ pEo~a[ٹ~MĚcỤu?o9_~j͟osD]9grE]Cj_ƺ>_0]зG\/ejbZ5KIt?@E/'g6qRX%s4?x/e!o4/";] ĺ|uǝB=.. rqᔋ7!Rxb(=.Ebfqq.? ƕ6`1.+m Q|b]fjgYz\(r9(;S \gMkfJn4\rIL+͔KL+͔Jtz+R{J McaqqBbZ˛E\Mry_rR͟.7ϝUr\7$\ϱWKM>+Yѧq].=X\$u{A~ULY\܃:/NuTAKuO5:w׍K}`[T 7.6{8׵wuҸo~.8_QOg8 oڭEtf8BD^6nճn?xTLOrN|2c!'OmLM_k8ʷ)}ÅO1.V"Q}9=.^u7TTDž"Eqᔋ7E\]O,.0\bah;UV=.rE}mk\|!Y7\x5u뷕X6q|.n˫+Pr7 .)qxuLpBMŅ4I'cD-"֌=.+m;zk\| }tq?1\<% /?≹b; bd?63e߶E_~e\_*<e"Ƴ1ND\x FE-mg {ǫ w3}^P_ //Q3m>5[ndljgUכij}nXy/>~@WMcnK=F<)6ܦos] N\_FF6{Q7偢8_?~@Ĭ"5-rѧmo_Vi9F=Z)mzs1zߩ}Ni572t~g4cVaZBuxmǬR?f\6f-kA)mYտݏ蘝J cV1{ 7q#Z9 7p#6N^(W+cgȽϺFnos͍C_=k4=x?x'13Hvl G rq>?/b[ǍF[V:9ϙ݃p^ µu 7rs#FEw(Ⱦ -wuÍ<ʱp7P?ȍ< yׁDz%@ύ|{ng~8Fݏ}%wo%3s)9@?w_cR+CǍfFs9Cv'72#SXύlc09,ߐ#DF_о?W[p##R"FE(k,X[Hdz@aY˅~o2Fni?FE<FE׵ߔ[zSs2UqLmb(\f+L^>w\?*rcܟu /qXyn905rOE~]9 5ssqǍ "=]ƁJ!i9{t t,-Ż鳻5F<[Fg+9޼tdz.iD=s) =qz=3fYCcbp#?koFEjWW)qO ٲs9$2/r+;rC&EoGې [I*ۜf<ĚRO̭,o66g?_w "[ʧJǯnSIr<0F-+osx+T 9sA"7r1x8ߕ zvU4mIJm%/go^O랕 uNUxA#IN&ֿVw?^oq/W[[_1w~5׽>S:C;LkݏنFnjh2f :fߕL1?\蝢fW(Ց}m?xT"G>EloGgyC;z \5n_<5*@ {7JM%NGN%:P,o>r#DN^㟘kPrRyR\P1K @ Qgoպ.tr A{E4ػ~9yU< o9Xa.C濓g4XHu8qϘ6N٦b\i08"9*.!?FnX} ; :ɏlUNJwDG%"'Eȏ9S3~?5$>O~oz.7Gv#[>F?\_+} oW9?[ܼ7op?2lzPO|q~#[*][0F;qn8gI<[7џ#G&Ȓ#G.8IOf%64q+c0:gϞs#L~sփ& &e=Gz>\%[X'_9y-g!_eۓuB>*K@.UJO̧7y o›|!o2IV[v]f|:G)Qwאַy&{upɋ9K4Wo]{8r>! c 1 ,Knpݤ> MfTCPCmmOs|w_:r.B~1zw@ٱSȇѳ[o'!j[:C4uÇ\UVWTuBdcDňIJ`&FLf13nbD?g-w\&&ySZe9S# hRx-T` */ b#v4QA\fx-G/rBEN"N|9%ĚkXz7ǜI,>W??Y n7r5՛pZ6hz7rVmv^WsG1 P ɼWˉu7rϮ OTSNн3{6Ju Sp Tׇ0DjƻchJoArq8b@`:`Opb?OYۜB+:1fPpdܙXgIq}x1 ߄ 06֗pNN{;@Nw;ey/O<õEc7c~0g*\s+}: 'T0T7~𷙈d+W8x-s0 &-QmS.h:/I3 q՜q J$rQ(\TP.*p\zߗ*/_}56}ixbp_>xjH4RάǧX &s8e9a"Qq}26ԜXo#[0:iÆfW1lIߖam"l4:Vcf4b.Y }1[?,\+1ܲ_=sV%^xF4{9&RyZCn-|!nܫMu0 o^ޯ 4?q ﮷+;[ݹ~[J/SݗV@xDOglmA IQ" _\g7۪x: 墭>̾NDycw4˶Wc A?jlBلq'䶼G{^ӻ,'zVop#E 3?ll,˟z0˕],W޲7 䟏w^Eh{6Q~}]g=~ r^lrY^ȟ|ls ;eqzG9QƮwֱU&O4)| y̍y <s! ǘ61& )|{Mc ˳.8kKΘz1&(vry‹>v ecj?1A.g{+<᷷ݿ#fy n3S\-ʘ'= '|:Opۆ{&N%yjE>$ښ'68k_Ԉ'|-Wyoo5R'Cn 9IP,Oz[=>{t<'oy򇅶ҿ&'֨{97YbTbs7+۬fߠfo7 aw kIYa[u]jC$p;iv9G>V>NKy}5zˬCip[~WQZY"_{[:@\8RTrj˥@O1ry_m~<Hs)gz){(%9o'RK}ioכvdʛv9J Vޱ|xVrJƋX;^C[ǕY}SzV{/*#E[yzVyr@&;UPc~\;MG+u2jJ.^\!me^!%Ҍ㢭k;e[4g_f{ω9gZƸ{Kxc8?frT|b\r[.Nd\>u\Cr[.">Y^I3J%OY!+˜t,xQ@H3PȺ36 67aw*F=G؉ȭX*Cn8fs,M[\ ~F~U/\ùXG J'R1>u *؉eSjbY=6 {#(Qbbnuo[%"T?{1nn ߅q9[n}Kr[Aǭoi[>rߌ8~w8lǭ/ȘٿOqEy_Ƹ>EnD׍b&4qp/#qᔋFpl/,.ޙpq=.m>b ?Mrq%q.kWc\Da7/tt F/B˸z[6!kkpE\['̐(Ѵ&s-킫w'rDޝWN[ޙq&ϳ\o1߲AE".n$kz̏֬߶5A~ɾ}oqnV^]E}3*^'=?.W<Yg85:`w?ſ1yUipH/]oC^=S #\7Ci8{\\c?=6T?ZE]˦U~:2OanotO+rc?[UO;墟[@c8[Oxv~3F/D۽Dg7hR8(-@>;hP9tF~LnGz\AS I tBߥf=.rq߶7; Dw~; 4Ӹ;<3Omi~#zq>X-qzKq1;viטl7=f1x1g>Nc'V01/U a} >,iiO:-s@儨O=4KO󴒽bFWQgn[c2EջYsYQ?q_܃<+iS{[AH/3X Ѭ?׮ O3pDݲ;A=bE&p$mxa>Hw1?J Ǽ98c[dw3Ƽ9bC1oa70?̏{̟+,dl?ibޥ0 c& ߉ys3}O1}Ͽq"589v;w-5~ox-;$A οjοΝ}<ΘDqDfm\^;bxms  ο.F3߼5s߮08.!/S. ?ߖ&2hšDj3 ts}<߾u[4H?3kοEs ο}9 oN[9yοYN{;U#.L ο4g>o9vJs.bI1.DݞJߺ4ߢo ο}&uOAw[i?\&r\\cr;"\&s\.eqݜ(u;})3cdN?8̃|ˤ؛DžV Q_Dǧtk߀A}b8?eX؝B]30} {"PɩD:@QqU8}fÞ1MQ}|>&i^9oS[U'@ >^䘵\٧r\anO9f|8&|S2e?g+]H>XHo u 3z~sʃ81[xxLsp٘O,} ۶ILˍYD;Ǎ\C9!x0YGlO118}nO9D3f1#c%=8ί4bJ`_WV8|.)_%DkjeLǚkm[Ny2վO+s*[|}O?c$=pWoDm¡LUE%nIͧq_%]}k$_Kt|!jOdCIbO{Bc<xOr:!\O!8JOz.yTzK?6xNx?)ѡX֓P' 9|7{n1^VU:_=CanO+"a 7-AF;{Kܼ4Cs_oXnWǞKg.Ğؓz'POo:I)g'kMroje; ?`{gD=eʱe{Ϡ'}AOCl;ʺm,o8{zզQ=MWt YA{WeڙlElE1<}޹3֠XK6Hg,;ə?R$*gIi~)e~&|P|?]WɎ'>~Yy2>o`/xs O(`W(XŽ5|7!狽rX/[DF൙wmGkb_NvS 9 ?<8o^r";jM|X_ML7FOEq֎k/}XNrp=zPrgxjef J_7iͻGϠoߔCր5>.'RA)}ٜ\Ė8Wj𡵚h ω9W3mjo;g2C9r{BĞ!4xBzk鴯YήɂgEc}o'z>\\}иdoƞ!^neXڷ`ϐklO[gYwB{zZ;ە!ȓrY6Θ'b~=ιGp߰OC噠f44b.?G= Sz.F$RMT=2M`Zf{;˾?kt|H@V&"cߛ9bhˬ+N/z 0ҺD1VP*{r|*#Wz JQn =u_l?H`5Dٍ\/NJ+~~c䔭Sԏ~<=B?m\?PzT%|"b ҄XlT1Xa. a%lg~ \sIWd~rG|Tl \o0?cQ-ƣ<-א=U΁]w;tLT ܷT^r4cIWsip_X7m71|\o9v6N lZYS.⻼k}':|B;R&VSo=DcO#ǯ^`Mk.ϣߜܻ+1=5L޽A>~mbS"Z:W֯]^?ezO}<^'pNwMd#@Sssezz^yxIc@~G]?r@q~΁{s.;]HbyNø6$6b~żK" a/gzGޙǮwf"'(]'WPkJlAiNgDuKLMm+y׸֋Dy(3X_%VaWU4زpߝD~kL9Ӕ׫#~^|UvmoUޯj&U[] [-wƉ"Xcc9 Fuxqŗ5GދVKAq\fNfQ8֜ƍ:t\ƉUFbNYplq#ou_A'Dڍ\qGڎ/dF@Z#e~Z#B9/W ➣*X+LthAGkM;-[9;<UېP=n]{VsbԼ3b[Uq{>"m=Ǎ# ל#eo."/Y^!^.Qdĭ"{\kro<1pNm,rgr8'"[J62^9V|Q_! j:zݻmbб0JH:Nw׽-_`z%mπܐu1/ Ic,<O[\wM\'~S0gir>fzvq{mFO(HçҘ]YT7kj^ׇܶamekibm}<95f}C,YӚ ֬4u껆puj67]cz[6u=Se Jݿ0~u{\,FwNnDxNVl/vQf xf65rۑV꿊 i VgRvFvȎ!QQ*u{m:\Y^xg>/ùoASG pC4s$bݏoVua}/W>}S&͚:җY[>c,kGGE8<}a1m~'X ߔgbUG,7fXׯ"WnΡnsu.Xk:=os *iV2Vu"[?V.ֿwDz |[\NGkߺົg %>1>$ h;SF RT=NKmw_;| 6s--ƸP8^,6r* Sc8"x]ڈ 7LwE^;cnKС}<#f!kziֈof3䕾z"ZXksӉ}c0\an7$Қ,=%Nrm#Wrc)18[}eLxC{7{70W1=7e{ 0sM22}o\̺|s;g"jmf;[c[ŘuXc cEEIYj f-1kˢ7:/~$H%Z~[d[ӷuq iYuZAW­W.iE.<+Yz?픋~.bօs/Ggc֑yޗHXIfvǸLr@~1ԴoqEAkʀMPjfGߟEA\=.r͜_]3OGqGqqpv"Rr=.)rKMg׸,y}Ed1.6MQDzyunGPr"򿗧qᔋ8i?#\˂(=?bEhIDziEskn=- Eȴ=k)?_74q z\(r9qmȍ)qq[آa ĕP\{ùdžN=.^hmw"MbfEgao:aƸ`/ F ?h|W\oA4w\NìC+=q{[ZzӠCAvCAbqot|"{Ao_xx"4c!_\upE\dn0TF7lL;]\>Є&>S=Sسz[>0a~=WJ'1fG> *Mq=7W?|>Vi?z_]t}C]j!9D]9DZRkn-nX Fk!_q:1?+<ώ3B1XyUS A]Y+r[@87rѧ}5\4Qx2[i\ߒOg}9+,Ԍ_xZYxc_,H? 5ϹǛc!YLkP.?>op?f#阙Jc Տ98ҌY7ֿ1l<w4wp¡x"\NF.i;WeXPO[>t<>_D'C+'\ϚMgV ׿ s7爱7 Ns`}.$E-Z5S_Xg+uW˛>dz az>^, z|*Y?hd=k,FQxg뫗9Vbgc {NHCFC'}?-sc9 5sL|@G5(9_V\[Fyoc걺wQƗcz8g=V`1]XGg9%?:D_iNǦp{XƝy>vJ;(c}i;W{p|+VsK35~,v:5Nw#cjKc2;N~HiC\sLEurS>c#䘊j8rLEU/ۦpLT;rK[fnPIym9|g" M9/h+y7 j}1TVx\<0.$%yv_D^JWtb5cOc+w6WOt41 y3B ND1Գk.:}ٱ3A~Vxʭ^Nh:^z܃녽/>+J=Tr+֜=-8^fW --WjK)R}N{]sd݀"vSح8iݴ) T%pDŽGٲИr|1ԀXK*9j.sIuڻ.v ص&{WXV[y4IN77n5J#ېKj'_pI \R9]ٯQc ٿʋ8\}1]QE7g(챢@v2`g[!=s"=rƍ0~{r0ĭgv:v×E;xN7$bɛ%I;nsûdz v*cvܥSm#1n;fby1J%p7vB-\gP;].mdv:۩./tygT3d A_#2m&R7Bx29lVrm b,Wei.M,E[׭۳d[=4ɍ(/ {;<Jcaն4(Cՠ63L,omu*l/m&n[yKg~ҥUb"j 񌭪lbynh#mke[%6r_/  >YbYNfVrcj/d̥ՇcD[>\DLMĒ3NՉ5pnY_WUjK&R[˵tv]z[m=LU@jTb'gD[};m5s[ Y [e3[\}mU h~ힱUPbWI,E[}3m5#΍hM\zDO&U mK`{D[zV_ &ĒEPCV>OV.շqV'&S|E[TyVd颭J|TVS[_, bUKo )ʻ3zoN%WJ|u[R[3p/2[T_z[+,Cw'ɵtbqE[5͑[P=1 ZlgM'hw܋9y_:5%v8 h6%uuԔu4m4Uuuu&7u:u7a5j,y5 αwAϛ߇Jhp>NymG3mVv'vvv]?;]?ɮ gDzDz?'?v=]o_d/d׳ Jvc#YϮw"5=.\Wѕ'+oϬ=Y]{JvmUӈO>uPvt(F׳%s+55a?~?Qޖkg5Dx6P˟vcwyO 2Mz_ 'Vwvz!CN$Sro?Rroy ~w}dx1_ϫ]@=w^~}5p_ އ2j+ܗ#?xap_>{{+Li:}>sx?+y?=jg}~}}:/SEk\OKR Kܗ# /?Enԝ0k{vs?6t,|BEycWSqJ'V=cC0rrD>>rR^]]cmC;>{5\ݕ{)ԗK$;)ҿ>9Wg׷}].[E."M8|bC\c;RMc>\ =#EVroܪǼ"gDc)1r>'wV0_o.1a 7  ;=%zlb0O7o{a`G3?n8̗ٛV"c'1?^3?U3?kD?U3?OE71nc̛)`ys0G|f\1?(s}.qf=37||eg0pJ1kg1{+ib ='kb筮177-K/G?jV9 %Rkrl?]Siqbꖃf7a:OU/ͭΟ %M :ߥ&ifus+Y-~8 5Hh~4?qgIZԬn5&XtP}mbQםӉt"&EKiE.W z?픋~:QbD}سM|prI/haDɝi]2j%/qq =.n(=HcgqlniAz\(r9\Ԃ;H \'jU9xfO1;Ez\Lmk\|f}n}9Ƹuϊ 'ҍS\̝\.1pE\,{4_okVoufxu_nNu2Ojc~dmAD=N Do#y/Ԭ 7VNq>~Tjfqb؍h@+QvDk4"8?i{ƉmtÎ1lF?mt|Z$??krm.+jx2OS*+?>."(& $$֒`XC%=XZZPZZjZRRXZZZRjZXXZfZZXZZ wfwμB~>?L #n3}4?[-Ku47`q^;8f?/ͻ=|" 3Qt wk-Z{0E8b/޾wmu ߇ G|C}fG,xΊ3,䔴_a`97\tVc{n~+Q0eYL_Ch5鈨:#vRsPhtS@'9u҃'߉*͞>RS@ɽ I'g?(4 AGa a"JR=MZal=M~u,']b/99ǟ͈=HO1lC!CNre6?{Md;DGgK4z]=&vՑL]?wC%:'Nmg/ߝD0wDɘ }_'׉[q7 M frix|b?r8wC#wCxآW(\c}g bW'LR"(+?r~{?O "Ռ@/xR2no׮wy'߁bf<y74!;^|ZU 2/ylЋRd^ `מyagw.@ǵbؖ [^|JECj~:1*.WPt9ŻMn;( l(4LQp qnp U?\&?Bn(m`%Ӟmn(P&ʤwCn( -mU^ } Rɜyi˜%W|v79E_+ʜrDBA2{ 0@π2MoPQ.@B9ΗPΗPΗΗ0Nh;绬-7X?vC(w UV_ 2; *`J\sulC?FcrY+8``%lN N 0?ߒvwV6^p<eΟ_b9? 1߻+c5w{uԜ$s>Ƕ `ha]!U)p~Az"-̬yk|==|2|2|2|2sC}s>XkM2; >k+ >(`_y,3G8jAfNn͉U|R/?ywkF. qK98:矹[;o=c&^Z,[{` R~ϱÄcGZ~¹|[XfGdȜsnq! =o̹v"猽A2sꘞ3K*ߋ6VIo%qM^IE9_@E-oRllyڳ O׬<_}snz:s;=cr{ ^.׸CG Mf@{ݜ 2I[>XomME ۥTY{1?Kx]v#T_/Os:܂argsb1~Y_GDK/Gss=み+f˩^z#XD0aqH;ŻXޏ.~3H?;c(/.)3ð r: ELُiG'?G">'ĿzmNo_fa| /d_5;t4 i2 }gַ:`]}>L0t#wN?w׃"g;Bg?{R/7d/ ?<%Hx*?at}q9SB?;I6kaquE/Ę͟9ճ#B;h WO,;bg\f?3~N97Μ%2vgYeHV yL`ϲ&a <ȥky- 󞝰={b/YqE9|sZ#/^oP[Gw`1 -AH;~;޽8Jͻ|) .Δ_A.5 *̻_s/ҳՍHm;9sF {κ7YvKݝLOP|<ߏMHUQ(v')G& wy?%1ጽ0] Q??@}3p7k?ZYq?_8Gv+~\QOOGKeg_}|ҏ)ǎz?@/vH`]j 4tA3~\iCu_Ee9|>f6'-}ww'wJ~ G:vើ鿬ky=pn{IYkou+8ok'8dHsc9,PB%ҞwO'MƾCqGkM3K{so)~8 +ABsPH~I9CW9CM5=x촺^tz3X׻6^&|vs~)] tbGZӼ;=bu9'zOދGDqK8@K7U'z1?07 ADsF.*1<}3̮܆_u8We{o8qvoJ.;uw.>7UH~U2|t!7>e_#ȱWS.rse%8p'QzkoCkV3Ϩk ,yZ~bG3#͜fe^bzzg'ɼc e2/jxlo\)CI2/\r)/.-b_7uitcݷxq&NEev_ ˘_,/|ƋGM)"oyq(+d^֛UFʼ0^vHãr>ė<G#2_*Y`sG&wT-A.꿫~[癇b]y7d '<ܗdJ #A0Y!vN"R(hWEi~1U(hvFH>f/|lQϱbˇV|Z871CyfNp9㗵2'"D8Ds"9#Ӝgω _@fu)bsƲǎCryK׽p 7oˉ$CV oz8g0DXx#Ƚ}gr=w9 A^RuxFDxf.dUiΜ{r&r0k'@k~_u&vr}DoR%\B(VfMל!;yWh9μd}o[ T MsH ޚyX m3 !1?Vv?x<܂9'%aDmsO~Hc6[9G{Nj ռ?H'.Ld^taJyaH rɼpɥh??U"G /> -/#*b)~|-\y^gosʋ֫yO1| oM_ 0?A1|c rU?h~ǾNyq/U?v7D"}b0C 'dAWy7XHЅCb.A? AcK.|/Y+-ٖAjnAW{Ut]A{P۩mݠ=={>-sc x !XϖX[||03>P}1z껝/8?cN w;fVo+Ę&/c^.W?% Ecρ>O7uf|ǘr1E]1εteH_M,[g6X$r@]0. h;~UsY_5>I{n7e,_-pnJg.{Ԅ%/ܳ[S.؟AH_%ۿ gyo*ٟ3d:u/'Xb&ߧ=/zjqFxh٦"a$ߛ!닭|ΗhӀ/}m/<@e2W,"r ?  r,U}6 ' iE  o`s1ޡѳPiA1i3?I*?H }wt[S̷?qyV3>^j1_y(J|Sm}~BƷgGdK[+|58>=od"Bw{~ ESlfN~1=HߩPl9.7AQ !쾑^ve16:>Io/S}Zr\<!mE'|~t[x݀IXY~e'AxnfZ3[c|[0_KolޟBgXGu}w|x[˼X5vU ??z1CŪi|Xty9z ^`_}ˋe^˯ݕS@Gou gxNj@5/JRlcxl *xld0l˼09f~XX.m%;$Go7`(.sben}G# Eg=ߏ0YA q5'>M9d#}Jn屝ߟ 9a3s.'@OXD*Ċ0r"qvVL9L 'R^lR?,tFEtX?迁m ?,'ǽc捊'y̱H_yeO2X[P|7-e>V?Y:w9>/S?yd)RK[P=HeT=~ *Bs].*R=vl'M"5_?QJ-VGo+9xu~XrPS$~oXJ/o_Fw7cN}.ۢsL_>*c^- qߋriKzW̿\׭S̿\Oy~/\Aw7_RdV륧(\o ް]Ӧ\wRX/Trɥz 'Aclj.{)߷; ̑uًEoBK2O ˰|S58ՕPb^$EyQ\$`5-cS)Ukd^r/HK.E_ŋHKxQ[^ 5Ny?_/Po %? ,bǶr,m Os^V Z[6wq/C[gQe2EE x~)9?_q#Z162bW_KƷфe|+~ZawwlEޮuC??@e+\P`^ӺMF"b(WuAَn'lTOb_1u~~?Z#? 'ظjX5/ ˼xv-,)b=^UK)"˼X.|6‹gׂ;Ud^.*/=ůwlwջ g6bwxG1WUԿ_Za>@lܷw .[qVesX8?3\eK XAd]f5\OuK.eݜ&]6gouـc'ʺ,o-v]0F?}/82,ex M7OԳ!2/f4ωy -<*” xq!y2/\r)/_(7iپIyxPŬڅD&/w6j8g6nQ\,/۸ܝO/#'Y8ٸIl\ywg_m@N3,g}7bVظ bCׯ|qS<  =WQd|Cl%6+o.ej@]6c=?9/ }%GtL3 ?GE+_%G,ú,.S^wY|2ʓr~킃>̓~F J.# ',ظ]O4ɼjCSlűFV?뻀_./CxǔWD1^\&;4ƨA w ,۸/ቛ,j6y?x#=K1Tj O2u=yظa]0/lmzsG)._/?d=;||a_g_p?9]7.o}Mmљظm^ZOe}y& }?#?l VظGc+.&`0YeX-HPeyxAKe]fu2&2\6& ,#·[s!.ϭ]mPg(g E)鲩N&Q7>yH۹IH>Kȅ/o2/L:@K.ŧ@_ gC" /-/Aܳ2/kGs bJQ);^D'y17RŔ[#VYc/D˼0^{UvɥTHFzb:" |VC!}^8SnbgHvT}9]GyNƋ]O<'1]Կ-(!.Ǽl- ʥ?9i+-l9`794ϊX>1OsTh՜"s~bgO`lb!V9o"s%r~=W /Ĝ/srpΗPΗPΗΗ0οUv?P[_f(!ƃP8QoxzSa !}:IX~ |z_r>Han =E񛽸N/M|[}-?v}-Tg8;ȃ\?yǩ\WJr1+z42b߷_֝s srki}쵋LTY3g`=?߳R[+t g =3=o({ ={=ߟYedJoYg-;=bzӲƿL?z#}Ƙk@#W..{=6"S< }1?*?\Onw"qw%g{w_.#kE\n yЍoc:U?3z*7?P.}׋@bF;8z*<7U_=w9?dF^:RqEۯÑ>F`l jVyq,+\ʋA'5fq} @4Egtv5ߥL?o<FW^$: x65/ȼc;;B-"3ڟ R*?O!<)x1闟 xŌyqG v?7!}X1>$ Y\p͎"F͋2/ntH%?t*lyaM`>]H \ʋ7%8'ķYy1rvG_|GG"{c; /&4Wxyq5//b tDq2/& p%~ S.X:T\r)/VM{ل#V/^"ލ 2/z^X0N_X WGr-T;ԼR*TotamƦɼ_Ѕie2/L Z鷕ʼpɥx};_3eL5`e=۲}L|FSHcALu# ML`PcmL'{P|b>\.,?(j5-r5%s<*l1Zg9o*g]2]r)痂[ Fߵ ))wϧ,-A ?LEa U``pT/l[|j?_|`a`V ?b?La  ykJk=;*՜&[ 等D/#}F* [3O(9ZO?-dU'MkaE^tāSw+x8A|8āysØ09_ Nx~"5F8 _VāQ/2Ox|Cz%.zuFA$7XOcyߍG:#;\؅I ~6|*'i\_Xf =5%3ku#'qPz@ '|.8g1Ƌ6[E o?1Q]ȋEPg'^O(Eꙝ@8A݊/C!Lr͞qfGo0')Vsn̉- v{ޙ=]G3Ht&N~H)?u3 n"9˰tB^39 @^Ww n&N9Gjb3q73q& i׆;},;Q\!m3q0w:_?s0H~ bK /gg3+~Lg>һ/po2@î1ގey2IzE?V g ?s*gi7$ߨHc,үaiBy]H+oP.@[-}HqyůݗHOa7 oT I7=Fyqm1mW- f3w:\4ΰkyKy$ wt+x⑄f ,Dd^ so߻OxQL yNj71ɼ/} 'd^ 0\/2E2/\r)/;_/Ґ {oyQߋ2/InɼI̛0X>EzxxlW p; /"EЅAwT S.Xn \ʋ`(q| /N-/~$km:үaH!?/9syq"_͋[&ȼ/ϗ }@̋] o$” >Or'ȼQ͝ oUHu/n-~>P1RYTGS^ֿZ͋a+]Xwm g+yTno,Wr)/fZSt?Z~uN~m+w1Y{ Կ=dy||Es_An~] oU?\*@oxky,E_?[x_ql"fO+̅|G^?fl" AGzEs WDE >Q?' O-.F /|3#Q[]+ω | _;37*c]i<σ]8?߬?8E`!9&ih>>rb"}Y v_'ĿTϗG-qG%<ނ.σ]w({y.2E !qpuܮ+-lK<7O]4vճ<&e┶Vv{r9s'ϋ;"@!oN|۵Q-rvIge8c^b{Z4`Qgxo؏b{(r1ykJk{5=WZv]inW՟q~Uo8?aF9C W; #P`3]A m<;O#x>5O+>߹;GZ z]ڭ3ƈ_1櫅'S;SW7wn:;jzy ߥ}y|2MaM㿭s/s2;dNp>ktu_Z$;y׏)ͣ]e=K@;7?(?X@MeQڽ)2On ^a+\(b?,Tx]< =@ŕ,ɠe \#?*^K.C@'_ lV‹A0$"_5U1?_߀X>}1p:' ί;P=Z"xl#~ }wya~ݻwK.$pN8)2,3e^,3eӳ|pW'Ưkezumdy^3e_!|oP{c,ss.Pq2/GŊ8!(|>]翁[՘{0׻n8r~=L Gi;U^p\Ja6 `'8Q}g"Qsx 0L+[)eVpmgs F6z~q~ao8?rS9m^p7Zfy ]/׈|:Gj{<-$xHӳ3矷JnK&{9a0WϷ]xo ݶAC8`0%^%/.[wTuH__ЊS}7߱ڍu?sZH>uv_x\݅Ywzڔ V`a]rnGf]2η}O.)Έ_!=d̓n[ ??.ٝ>ߵ;^gyq dؖAz2/.j,`e˼0^, .c'u~x‹ oy{̋k,(B.+/| ztwr˼c[oyuvt\wx.w_ݯդ^-/ve^khg˼*| ??/|ƋdGN7q)2/: lyq Geɼ0^MyKy1 ԿƊnr^t -/˼8¯ݒ$w?aB 3V/#㐚1w]xStwX\ʋ`e7i /:xvлR{7;*^, ?{{Gm^ο֨ťw]00]8?識!ŢX8ʥ ̿՚whwaRnQ;(Å[AgO^LtT5/2/]p+]x+xUR^ =o/!>//.F~^bG5*^S7ЕT ۏ2/: 0^R(” rWʼpɥHKkZ5Rn϶u/xrz[Nb]l9q7R~/8շR2kdWARClw46cxҞm 'DGyp y8vd@۳E㍱=V+r`^љvs^ _0'Ai<Q%}A!So#rـ=ȥE@*W{("gș<{hzp9?'Cs"8h57Wgz>r&D3} i3ۣ<3 d 9ɠ1<^6?|Ƭr&YgΎ2~oC;KD~돴EF& {1]jwd_R%a涓)M~o;}5$m/9 \c[۸Nۖl`@Z5O6xOޙV`N>C'}G6dxCEQa/r)o'TVJ%{zz)#:h};=}i_3=%{&3=%3Pd;iJ%})scIWXt/o>ejvN+Gb7OY}`-:s*w27kAOיf#[ g:q<\k0Mq' Lsa/\^ _6nrك?}yr9 A 6~-sR tIh3\EO BZ7ר6lZswGg!מR&4Gր>ځ'V:?BkA D2ْrfY81?oWW!ѐ"Ń՞U|k^Ny< QjșljH;쇱?N> 2ka A96sOFOۗV p=1v'6T&Q 3-c ꛕ~q*0<.kf~bG ך 0Xvw$-;{\9B0ϙ@00G3{mڅ+1(5+1~'?gꈼ~oIHeAJacl_NV`<oGM'g QIxsxmΘlwω7dN7z 9d+GqE Z?3ԝ= 4|}DZAGsc2}s)_!svoMٽ[$Zs }0f>BK?k/!އM޲@lOR> ͞7˻+ad>֤s'~Z=#7 ~O_ƿ7n|\aa: /߼07:Im9#i?)zw3I?l5s7Oғmo#eoFKW]#Ϳ+%dk/\dJN <61_e2ij_mp:-aRKI4bsٍ?,KsV5b{3͐Sga .};F;ibaZPs}o;He\5}ר'k_7Kss?y>7x˂ O0HK|syo67 r~oF3sA<__YMj/E8hǟSs}J5;U6Ɲ릫Gg7ltu=G:jO$sC \EUu<{幣\5lxUf & r| $y/=_eekCg|95PƸc/Ɲ\s~3S2 2\-s= D}=m_13/ޓW{'M/@x樹HkW ? O\o{k'y"-`>Xyl!`>|63[>|şM_ɯB.L <+䚃-M,:{=6=/-MnMl hw@/V {EqL?Dߞ:N'4cO(='q;pi8w3'ѷwfcs'>p{Ӧ {/swj.}8,?\*VݯG6W$?a=V$K V u oXe6E㡳ؽ菰a~ayW:e5Q<] ڶ噾s@ɹ~.>1JxwFpYU }XkT-iKZX?:{pΉ~IL3i3Nl 7rgRCEV ?^ih:Y+vc1XǤcaKrԎ[zX>t~|ggkbo>ǀv>A^C {:UVoh};;S ꘨ ysٰ:Չ1i'_;*qf^ዬް.Ƙ?ͺ4,[1akGp[)2Yߊli_|̥]w?Yl>̯MÑVи~8'¼Sn\`X3ioJZx Sgdݳ?Ee0?~SJ6>U?-v`* u'Q_,uE_J{>uHs!j+\ dxg>LTG2r6ygy?Y+g*~nD'Vyʅ:a?s v?a 4ߟMq}/?鲹gT t9gv[d_ng_ -?s㛍}Lu?wI73y(+_;نzqm1'EGs)߿ Ӝ Ls7+%߆oAge*1߬KM$Ye3~~<é^ g枏Ylyce :?8,snG/ *6ɜ`>Ϲ.uM;p9p9 t.d[۝YjQ[FyޟuILA6^j@g_?k ~BS8Ϻ/{iV?FzzOs/g:>};P:U&6%a⬻M~/<i+9ڿ GJVEM^cN؅N_?C?|D~L߿`Ta=M^y9{PH+gh%?zu_# 5c6)G5ɏ1~p!~F"m"k _/jGF} 9lGߍu#Vyc];gxu^wgνwkeι/OG<*-Q;`ou yS}Q+_9Qq?yg8?$^tN)LSN#[ !D8jbI=l0Z⭖hKb|@2"?@4̒FF.![@jfo6k{Q}_mukOm_gY%ԁ]Kfiuw,X9<Ylfsbirff375tld?t)rhJg@VzfW:qwu@*ksnc,n,7q[1p,ީ5p=nݓ lwNPnOY w{9 (n#?`cH&h75m[ lcqّ69v#ug/o2>l_exY~<Õ;^q^k5߃n2?[fXg ]>{|پ<+|vK-~F#귢oe4Z=GmiRsfzFyfW5>>~6|vnO{5(hczw0:M:.iCN|S7:GI K:sZ~ίc喃T:C^9{ǮCRWْKɟR~~90s@o܎́sxFӼܹɗ1=q1K`<}lj7r>v&6ڢ.M~կ4}fآFþ$-6ۈi_ MT>ҩTBvFu+O DҽT?@GKL&_zb-&_8KgPί"-|K?ʍ|_XT* O{Y,*ߨiF1 ߙSG?BGP6V~f<']߃ WH?DM+bfQVzO7??`R<|ϛmXGG0 4QSlۆ'8톲^1q.C,Yh]lH{U1~//v0SF>h #qžDqޓp*?.8{&!m]W; ??Ա,r%g5QS[?R;?G`d1k"/#1v_5F/T/ۙͼicWLE|r0\1mKcyY/N i/WzK%@XXϯ~ 7ϩtO-ԗ>sӘ|ن׼|Q9# ?x7s6[K#}\޸u^{樍>M>w.۷XOxꍤfM}xѮ)TO [ >ZӁD1oWQǑR̡B~V>~#x뉨\ʙ w<}z _9@s{ sș,u)>l/sd/e]u%HýxYWȺh(~Te];+Z-!r^Ϻ܏K~^K.i3>,?xc?J9?<_;9CZ0)X"c(gxw"?xcc!cAcDx}k`xŨ#X|?O`ƞ}r2SX;}P~MWJ&omG{Q/ tӷը{1%^ 從Bژl3(Ϯ3Rٹvdù{v4v{vmp>;ŀ610~c@mwc?c*ʳ[0ȟϦݳg/' g Ϟmgw͟ȟ(gW vg;s@Z@Ty ( i:(G?9> [GӤXX.fzx SBl O1qd qg+>9N魈}D1X/a|[~`}q,~W_}ZskOY~ࢾ_8^q"XKa=,%NςjKy,(T#?"(\.-ã?=L?󿺘C!\PVF}q }`c9%I<G!}xSP[?Π 1 NSئ?U?jF U$6|&ƻxOLbCic~?58, er$6|<_-|-%._o"Pf%J?@G!|]-~bCKion6^Ȼ|i6ھ {k1b mjB` qO446އ»Q x熞?#۔(fj[l1xFN#]n,qw7 õuF @ g2z9dq+q^~M|e5|~\ܛk_F\Ͼvgl',;[ -@e_FBwW/E_ޏٺ5+=5tK[CCkh.GLLeu.Gl??̸| xA?pQk]PN3r\8>gm }y9纟zg*R@~lWON̾/9gq yWKv54K5$Ps(:'AFCJU/_ "1=Ǔ 4hr{'u9=M<ޓ~F_2[ۭ +b6|'ֿWf?9Al97r^dk0" })`&xoA[x ~:=߾d31KAF9I549=SvTQ㍱ AA/.rX>Pzya_57 +ώ0VL=n>Yyvd2g9ʳYr|Ƨw\(* Ug_}r,'u\8Q솮s -$bP3MrhsJ59_6$fA ڴ|)$r+y#w?ѼbA?%C]9_wIÐrr榋yy.O17đڿos[N|IVO_+|t.蜠s[N>?pQ^+bQ&v"KC,dHGXG[&~DMΝ*r#oL65]s@9g|,wҼs%7}3Y%H_Pg3~C@,LcXU6̽'%WkmjV[Z>?I#>5^ k/ &k[s~w.OD=MC~#<79-Y<'%j%gGiLATjiby+|uJ7lY=cH)N[3)$@)u^Lgr;!4MV6βu8JJ;.xtֆ]x8#k#sVrBZIY+QutSSLY:@>)˰vD(mYncVXgqaW b#1y1VzoV6VZ8mg=3.طqaW1.Z\齐iF\Bõgqam\wY\z3P׿100]W @cD+\};.?Tt:=- 28~R_W_MqI}Ƹ0I?1c)FD-vѤ~"- 6ƳN'g`瑓FY&xM\x") EZ!Gc$I#ik4;~cđTο+{:C?gmdKug);W>F_Gt/=di]~sP޴I Ø h7X_d=ǠnzgyҠ)I#>e<|?hФ,w;h ť(s~Lێ¸Ul>_g_4uv`q>޸RR|Zi:Sr'_g %LGKqzBc:+yיa#uLOD ] XeΏ{%k#anw5hQ1 pt*?k~&1~W dxiqv< 񯌕:~ x|?nyMl$~7͘|d]*~_DŽ nxF_wijaݯ/l0Yw;~W;{o&ߠjV'D;N]]oix3(T;龯8~{\ 093Dbީ~m_ea]3\aϠVsحbXb_`i~W1߯VD\C r@N|S8v${q?"đl c ֕)Ar[mOa7{,꿰;L.szb'JC=Gp?؈=l)-M~@)ʗ-@S|[t:rܧh#F>MS_~ E3Rrhܨ@J&I% Ne_1;]'%+5k:Ai [MjVNk[Y{a5w>|r2$wN1 (F WhuUkFd(}&{Q;3О"ۜi"[#$I/O Oj<sdww:OѽL=)JTN?<ú !n5J0s@n_DԚ"Ln_܂9B|\o?w#>=Ɖ{B{m(Z#/.m-Y]xVZNFY&ܴ)#j|-ix y2lحsY:7.>r2=X+M&&n+_4SnpMݦ/seQιhySlDϗ1I,2o,L?O~\L?XG kry^n?߈_pz.a0g< ,2p_ $9-RyCt8[2N<:\],l>\8\x[{$[$x$tr{Hqo۲EqKxC|[ 'Tߋ}'ݒz ~Oe0d 堏V*KKӥnT +I2~O9TO%r'~'~T)b)eqۣ9|:'DbuTxw"q2zêa[v#wlUR0gxEڽ3^R.uq%T ^z"yER_ QsX55a?[{N#ԃ<x'5PT*tʺtzr miвv 7hC'ct :Up:H"VjZ7tZ`MEZ:uA?y0[kNNrBkhtMaЩ|t-QӥYVxW,W> v lNg<$b- 70SFkii%^@i~h.?$)U[uWV i@VRV &DN jLm/M8jzrZӪ`.ghi՟ "vHK7tu:JοFUswuVWZ͇D;^)C~VJa8jX- ZM~-DN,Ҫ4PZZ]hW!6 vAWVs#׿oh5wB욪߼#*bZ]h5S;vZrZm8yiOUp[*ZZ숧 _V?cUU+O%-N  ˉL:Z7Ƌw(OjCB69/zl6hi7zl.!y;cj UPVP*z-j$"ٚU h|"0CѯCk2.@eV^yZԙhP7z$9ZZyxEZ2Z=(c4jUE+OGI!GGd"'LҪ| ͝ءW׉_=1Z= ct_3;J>*:JJ>;+J>:.tYSQ[QѲS* -錫/Lk,t7ti},Ue/퐤%l-Ɔ7ngoTz#߫ǩxZwfoF>~;ǿ||>~!_oweT>ޞs>~_*V*>Q;xg3ªc_yOhOdOwŞ=eފ=uލ{{Z{#{㽍{ӽM{ -{˼y[]_e:a~ jGܾצA˔\)t' )_mIw>K5T;؛I0ndy̅#l <'v[*x,TZ }囈ڃ~࢟>o%ɍu21kCX,F603Rv+DZnZ7=Y{m*-g/c|}]Z^!i.nV?B̭ܿT/} ӅcqmFlGEKBުVZk3/W9;@Tz~߬* RZZbMދӽZ`!{6{kY)ji.3yo=c)Ü k{ihl|sMދԽG^Rk1giվgir=9l6yJSaK{n{9^>%BѽGA[{Vq{R^{5QzI{R SkD{/@"-4,|ZCsxNᵡp䰜§ga\d68Fc%l9=~}xH㗘tYG_1W՗]^g߃ny"#Os6UC#tbO{݂3˭XѷuG8j!n-F5kB{[W9I[7 ˭]>\|_sa>_ "ǘg; \!OcI.ӄ.13fq2Ț ,$ϸ ]-z9:L[sܺJ'ɽ!98\Vc̭ *Q^7N~YgCnw%q3>TWdPY0k,vz>"37(y_ZtЇQ}TQDq <߬]s{tO$!w+1isV'.LFԭNf,P ZyOND{RUf-Th3.=˵>{Ht:eV?ig F{r jF##`vrC Y=w,y{SCCkxⰦqs^l;/M;RwG z`H!xF"tYfwk,S}7'tg@mEv{w3ı}0uqHe30p%b=wM}k4lzKw.'kyd1&_&.- pM r __xzg&"_6wBO;KKz흎} >$.vmuкޡuCwr\gw.5hi ;G-D`k}}T}? `6~Aۻð?6fh8?{&φ`s֙P`/hskW)ˇU-yʳ8b5۠ԴS{D+u-W kׇFONgR3R-4k*jSd9݊jn'BQF;Cf&ÕtnemPyؔW)PDjuU;_hxd=~YMsy/lTa)\hK/E`'GE!^fBk7R oz1Rl/8Gjq:=l[{>[kMA:oeZoLA:o יL/8):?90zol֖]aγ+RB/>"=.i*8STcMIaF~[JRM쨉Q|J.Fm+b[5{]HkiiYqi| kpZ-מϖVOk+!ry{9_􇵑9.³#MUUK}>պmH=bOR{їwg.rh˗1G Wg*f1t.oG(ي~>\/hCowwbӭ-fϖ;M?z[&cOf8ǵs|לsDsAQX?'MK&? j9ZtW/3JXzgh  s]4 bZ?1gIkZ痹AH>xvw3?13|cGHKC>f9GOKi~:sT>gC~givk-D>jJ?͗M?ͪG;eFviFOygCC'sGM?y"k%~`9ܪ_F?&íZ~d#ϗ:/6pFϟ2  Lc_?MzRI~a=X0w81f!;T{dĻϡDCOZ }j?Lo'MM>|xTF3:{pYN׋X[>0˅qR CE~E\F3␍Si˘\ q5&iߙ}?g+v/uo7^AsǪOp }N GX3ޣ:, okB>x =zѷ}aQ檤z=*wѷq?lm~Z}ۤ6ǥ|87( LS`7ZZuk#E34EXgFݥ0Pcq/wy/u^&x+;.oGۢMRj^O5y鞥~wzxQ,]oy4I}o)}NRzl(X}6Sxl3%|a-/0ahS๐67GI)Nk2Lxo0e/0Z\"%F\?[u8=u0Og`~`bn}Qgl$ؿؿyz?̞GV}g~-}"hGhy2o6:ɏzC_z\O?̞6yL?|0h>cRaPN;H&>e {ʙGSz/kR0`0o 0lj,fw)Hf/Z~F~(p~LY~"!uncbƏ`??uaiO%j%}7u[oX>a 뭻ZO&%fXA[._&5_(5Oǡy^2XD7zhDOc׀jO@IW\䟝Oa? I0,'!y ?9ߤa;v j/V B[fdGJh:e\4tOG}yaCV2n0a?P~c w6EK,z:7pKrN+?1;Cez[نvS׫X];Ymd;돀.#]  Uz#`[+/I'io˟#} _.a6Vz2냍|(|R73 S; 6B ]%^Otyq%im%~>㾿nKBg|R{ԡ{v+v:]7a" CSb `Af`/y>O){7lD܅FZ{T]0?ڭkOf0ߎx?L@a쬎?=*n~^4͵Z\FyT#t1\N͵n?ws}EÝFԵ?u&?B z[е CD:{qzС`g0O=k[yy_Q$ݼhy6y.3_ jonlW$郋Zg5nvz݌gygyc݂#}?[vsuvqp-O Okhann> >;9|\?3jw\cCqtQ\ЋM?\;:ӿ4/1ιiF94 LYB[KGw4WGokWǤwH !}~lmfYu,]Bwvag0*!mk䐰ctP{h+ཕU+@OtW8puxw~6mDt% ϳ'aCkcwL"VymCV6yXɊ)HE^$ƭX62pW7xqR{)yDwZbA&L=Ϟ=;Vgx=BX-G~x{9GEq7`xv٥َJlb?ԩ{v3?ۙKAap[qb|^?o/ڊu5{|Iok'WkJ'Lp zq2=jkJѶ&s'd2*K\Gc }mZ]0]2M|51sI{\+&UwaUL8vg.i_ʾ6l^9v6^;-È\o6m-\;p3qHy2Ƴ_:=*x"S`a!ag*"zGF}dTm#D~mq( pÊcp'rh7ʡ~BsKb1G~F-?n|F6+44F-?n E:}D;??^gYX G('Sø|P7y)G -J^JM|RS|h֐qor`,8NL|W!:1Ø?'Sů" dV;_ ߉շ})+!g5p4c,ӼO6iWV#kieZ톳]Ox%TihuJ̎t#M:gv}2;Ǡ󜁽?LsBY-$з ZH .ƅRC[]{+r΍?o8爛f+pZHJ1nu[۾k%Q/<;bxG4L |r⌰6ba=v[{PCi tZ-k+b 'hWjoIO}+ K{ۘ)PzkG"[/[߈Z\O ;suGzntE6~wvuv5ޜcv5sZ[UWS?p?!:¿]poqzFmd{7aA3a>HHE >;<Ni.V˳OqYng \gˈ]~"-?-ϳ9gaNƳ#`F쿷x֍#Y>IE|Y6\l/6#jyr\Kd>{~D[z'wirdODѥZ~|LyOL-#LyuOn-d<9_yL 9,>gzgОq׏Dd}Dd:~Y?oKyNM- kUcUWIoj},Ǥ嘔kMKNi.uڤ*wpn<'=orɰwVMty<7!r];&;_u3qws=08et1#Q7\2DjϤb{wW=6'VԞIJ4_,XR=yC˰l-بZPT'8,ooXޱd?pQ6 l> v3^_G%'C:֖{*,+ /^ ܇ZZfZ-$d\f{i(?z/D)^[%'u'J~ktuv>/>TOT[ {2-[?wvϨq?w4'_u vSmؗlM*+뿇vS}kޛq-/0ڽsBq-=cE:\{hb]?'NN/O럨_lR'AL&.nayǬ|(cRD?:Cޢ{SOL .ؽO4hyvE&O_??O+L>Ѡ'MK*$Wt<Ƴ8g384j'BG0ݵk\jZJI1kE{6U(Ozpֵ@ߝwz$5/m"F/&1(~+[1Hi-hȋ?Kp%i-&&5NOv$`=GRbp=}v}!QmU,jUg'"u_I:)ʫyyU_*҃yj҅u<{}5K8텊6U,?Pi#S}?}W cuB,|+)ZAԺ%EUVlǖkX՝an<؟w63MJ _i> MS2XˋB՛:q>x=W̭)KѮwxbǫx^NÌx>ų^ڭ3R;4t F>^t}\\W _nJ]LsnXzsc-*| Lvd&$_ IagðNWk$E"mSb#mW"U<@gBF~s*Nps Z̾j}s݂3{r$~7/2|ُcTZzgn~7tp=['ѻ}}Lq.Oc-bjg]%g{ǫ?Dodmr&#!VOK]9Fch^(yS.Qf_@}6N=d'WU GXXo+69hg+p8uV@kmcA$W,Ղk>ikMSHG~18k*#/`{êm@97>p|W`҈a~*vm`mo6op}W,QlﰏX>̵~N|bU}T{}~4hR6;t7gٟ۠|e~k*YFu7*6}Z?,9 ճ}y _|i9fdyUy^Vr'"xC+_7o[y_tX%I͸=4z=b< xծo:6q>_YvV5yw+)o^A'{풕Pkg}VpL}(O~/9{N8=tUB{,}(ٸ~zݤ]ֱ5=θ~G>\o PFw~:Ze\-m~?j-֮߰9]ߪ@Y~׌Ю{~s65xߨ-=[ wNw ~(~"7jm\%Ϛ]Ǿ9]bp OA{(;,"g -L!7 HX#ԶbxQ`xgE0A?ZVC/0\bXwϋ T[BؽQ7m eFmirya^R̢LսRt|~ xO5V˅ب6B=v~?t77OoCs`1'n\w`E}6g_rv7h@IZu3ݸψW 3v-R\&pZpiU{tJ-c՗e0>t([siպMkieIZ7`ZZ8j`S5VӀ=R~0֟~zNTǼ\x?g_1lEj#=85"<;[W;#7?෯Bt.땄]߃z%p6c)9!0&v5t}'[vi$N$RS$VId:T ;rѸ?glkB?kk.&/"G9KԜY8D{@q+O0/눜&ڿyLޡ=*߫֩sZyߜ{u+7_;4!ɢ.{+'7W"})3]; ߽}jpj<gE6ߝ,6, Y$Lk?o')Ә,NGE.uByX>$>9k.c_L&2N1c!ud&x[>Ū]0<Bw.}t/!RF)'>?R{cH1?N95]PY$a;X|s[pVcD {6GDGY(gnG>hYrW rkTǙUQZ*1u*>`@eIjll336ieRKNaHZ}$]p4A`=2V{$nH:*sRom:uzԌuz|uW2LKҽ tjU{u0{ka[:~u>= |N30-:h9al.u)5op}'n7M%xyV?M\>}2 /d_px. :s帼ߕ 9Fmq4ު+-3 | ^Lvy/rEbI.׭hw;yQB-DQP(ME,"jelzȟ7k2ڪK($+iZ9_=MYr~G*<syL9ۂ3z Y  =|4Bry<-=؅Sf ]-UZ[ꞥNک=7ݎhۘΖ0IX#48H:P(_A6m}_=)HBSϿOFc<"q7q_5sh$FPTskV\n'L !cju{7I.Aٜe2`{4#_BeG}<*{I,$q߇"{ n ;JV ?fotP'U+OWwGiirg{OW@j$9ZZ8U~&?_nZ"_I=%14ʤ$:hR){ksŒ:w@]*RIq<#pym\۝:I~{< EK2u8"_`[)Wwu]H>1wh>~9_Nq {GNcY͢5 wi!2?slY&'lclyU\kqW%b5xK]xr3pz#7Ga6ArM(l3`C:h/vgF`r7Z)>|gPSLD9+sۆnb-D3`& xd.m1y>owڣ,$8~" '<؏}rқo]b䶃od.ٷu:qAǟ_] 㖐od ;><⮺E_%|<?d@CoOsLtbOa]Aٺ6dd%yww%y' jG"gJ8WCNy,)D PO׏AyCKOwoJg)t'naE+t5LONTSn0]{_HhɝLǦ {wy8C,+u2R8<'y~.D Y>Ձ0"?=a[ ƹݚm bt}>#{.'Fn?$m2x=ri<=R=tHcy£CA$?3|Юg 6~!U7wħ"JUк6Oxf-ܐ;}csg\9'q-{TW ;m؊<-seU%1{#eN{̍>$ { r^iy{u-<յqa:frsC!v. .r>$,댠DL妙}(=[-k`1Qݑyz&EjmN炸x(8}/ui?s>FCܰ|A/c{7d>obB_j_8v_^ ZuaZ"nHC75D^({ggs<x\I>7> J ?&XSl To1nW_$_nT>`qzhl=1'zz݉+a- $!ٲ֯CSɚG('wf2[?;ϸ.@(297Uu+̞N,39Gמ̺媳O +dixm<:`1;C`G|V=t0ȻOe; ?S9g<7۳dܥ~ƅw>{7 9?=k׎!gpvxc CQ:a;$y g!1|}"f1<El{Z-ـw4jϱQp9 勵/&ο;&bƸx%_̀LĬsh>Ɍvrˡj Kbym;=';m=|oZL!V&žK~zit":_sQGuȘj5M11;GaysbS6tzȕU=~9,'Nה9qFB.rS w b=wrKϳ)A`]̜8pZ gKv/;EO+98:AԠ^\-0BcnQtnѳP{# QHa8s#},p/Y㟡2BBÉxm-Sy8jyQ_ȍrzZ׬WvFoW䍊q\[vou/4r۔OG5QY0G1q.w ⨉d;Si]5Tvz,r/L@3Ks3C2OAy5Xˈ=Z|4pk Ƴx+={:DqGau_m^u":QO3;Ό=5/X^ߊd=fݏ+f.}Orʢ/쓜_^C i7\]_X"諭1Ӻ| {,XM@7uYv^]edM!ѭw/ec.rz߱a϶[q<}oC0R qN], phoNLꡃwf%摤̃78>@aqC' VUKCo`X1n6dla9údfmv ruvE>0ӳØG_,>տ,_ynLlA5XT6ؗL% {#Eu^kdJi-fyb>/-0&DX[|vt!D })"~buY/ wE?*|i8d};#s&x:$9Oqv}')Z :oOr}mx؋dW8{dbS;}݄_n!%Y<5 EY<5^rA˞{Q'9b:݈_ |~ܸ~U|n/BdžZg27's_7*/:#$T~tZW(1^ ^Xi}ek 'Vro)sSΓ*gl}a@7;\R- mzhH/ `^)lc_R c\VmrzsRؗ:/Qۇ۽=-|!>_iImKAiD6{ҭm=,lk']tu0w9LB.Fw%JGXۑrQ,Sɸ z1cR6#oе!F NzVE0JЋ 1PۋmyL!H#{Ya'^. xm^ ~h>5լ".q^JtEy1߫ Fut#'0BG%>l%.Gc-?B?!l螽+9 {&a/-o Ǡ_(?j/Fq 6TŹݭW:U/GJ=Ԇ|='D)O=B/Ʒ9Zf}?c|O2[Y׺߭+HD.1lq&ϸ.=9¿N3=*aB}3;ٙygܹA2<YEBy:Z03Eo!N?¾#j￟7DXgo'A{Mj@?8ѵ[s;Z],F1I ~; ru( (wS+\s~ |9w/|ؠ9w?+sY#1ě׎u/Dl9wc؋̹4W1}locx۫ܽvyA#Ô= umIu)]pIs^^+a٩FO)mS!hEė弳"=Ogyy!S_-b|N>Aֿ?:l<׈!=.彿&͕8wE^~oTiۺlަw_M쵣 ?{-?/ېբ<[O3`݆ϻ乍^jrinm,6p+mtnGw= t+{n O%si-]=LkSnNcU'3QZtG39ư9^3i|͍ؔA^,{:"oEV7YQ>;6Q hZH쎖=ZKpcb=i}r%5jߎ[a|[L_;|_zsK_OźŮ%rrǿ/wqt[~,/EbWl[rX/f]sc0ǿ__.U/kg:zawYGtNݴ:OJo.)ޥHDޅhϲ.|N$! KF|4c\O.ѵ zF>ShOacU/`>F3죙G<'SQ;دK?g_'7=Ŀ3|)ÿ7q{<).յf  ~o lElE5mgOT/5l#{w5]C~!3E~6Vj{l_8_N uK ՂCXVS>I^kF}Qo^>%y7Wz}éF,8͚P=TM Al{CO9c0&q-q>>7BW RUX/9v$?ω9J_pn@T?e~@׶1oce])MG֛efd^kzDžwy,4d2<㮚9c23=G6pRY78Nylo#Ϝ{k(ت4)N%烑 W +6%:+{Z]jܫ}]&1]V %w;֐z{$+ݫv߭}_󯱾οCCƸx߿&_w8: zj<"ͼ݊:w;?bwggNآ j[;)Qw5̕@!9m'Yw3'b+Exu w^knC|Okڂ߽bWHKAwrK>ߪk[0?`#d}.]Cgw pB[Fږ~"L_tOlŁ۹a,[ na-`odeo eU2wr{znH%v>F9wG#lk[ Y 79Aֱ帳v <1`g!^iokVuuW\> z `^̓d]Vrw^W.Z{cjc wͫ=߽lͯn" <[tY7d^!QRv}P|ng}y WgY ?s' EvϯچfƝjk_GڲEڝk?ȕ!6c;ͼ}6EpX2l?;p0m`|f\ V+ lf/p].v#sjZȗٵ4a-LXg5&ƽ֤];ZrVR`>ᅵ :3czϔ&g"?GgPuTrgWz^ g_ط ( 3Jyv.v՛>c\owwF<`w?@GuWMyjw6۲-MN]I%X~7JYCź뽳;|^z渷{%n߯ޔ6%Hu/M_Vβh,sեgd̏~=T9R=m m_Bmd/E부2p%wt~][㟐Duv:rEcv9WV3.hW5M@%N3nyt f2}wy$KIuBzg3jw38&JyOYn÷L:&( M痂!toruG.u/oYMޗyMYș\ wTu~07#G ss|Md_|'Km⬏iVv6<7\yfo5;mq7ŨMv1`75osK~3m3㟖zI ?[lWF0[~`Y&M\Vۀd[' gқf7CD7YB67Yo@o2gv2W^#;z/D6p; 9M,_H_ sobi/MfWnk+,2?.LZyM֛YV:+Aɴ~ Bvz>Ϊ7مd2;9fO =gdoߛ"S:n@k7&{ں7ۛ _$xZϐ9Єͽɼ(jo27js9om@&+^#d|MGuMurv> k./3kUo^7s)UA MU3?؋GQSMKdlli &6r2Yc5_sv#fM0\/ZWmP|*~s?ko#/ӵWݵ/G[/qhDŽ-2/5}W{y6/;OP֖ߨ~yi}pS{=~ze:;}ud#|ErDިWjW+/c*@BW뗽+OkTarADc5ǿ%R4_oڷ_ſ~yɄׄΙ" X+_.)=dvZ垆ZUa'2~l?#Sh~֏_$%8ܟe.Pm/ZZCoc\T {]+zl/X-lHj^vEhGvR׃Ό۴[Vc̢KcJNeV|LYv]q?»lYƭ/ &Kbb%Yl9a̺_~*yC]뗋^ӐTꗛe1Vl fJۃ&\l|K?>?P]Ԟ?h<^@dyյgG[rmGo0ˣ@K53.hY_EL G<saz06ͼϋZ_3^XyG~jssWS-?;N> ^zJnCoΖaxig 9^zO}XKY Kdg4鸓ށxEqO@͟[(Q@|/Z/=k2;swq9^z?󂽳f/@(v /l j㥳*\9s dxiN0^_1 ΚkUzs4॑K /= ̑=whe0@rm7q/ld~S#x駶w/![\Ko8//L9bK?5 So_/S=K07^z zp0cvbnss򽊗18 %#@^ 2G/mvGtK?^/ / gEsr~Ŀ:a>1ӄv~ίysKs&+=b |~8/s^7lnOp~bڏ`?~'xi~b5^cV['ߪxixi_m_;-YtlRcSο+66хlƹ/}pK# xٕHy#c=N%m9?/}(e?Oxi5?B_s|ErtѵlϖrC%ܶ1W";d9~,b_s}LjPw; dTaw5Uu\8+>B5\ߍcgG|^~_ih;?xDx7^z Kϲ^YKۜ ^Zέtյq `-#A>,$6ϸ3xыv cxW^YKt &׃;sa =rzeu"1 x/t/k4؉Y5 ANw^[NCxikLÉr/^z ͞xit"lx酀Q?[otВ3Kdxm。c/>@/=la^z çuy/,7S/ҙ/-|Set!ko#xC]/1X㥟]}=~2~e,^;͔M;|K/ћݳ3x陙~:/7oy ^B=;}?^>f}̲+xi8_3 $uk\/]1%#47/K+xxZeS#xf*Ĉ˄1}ج{^30&掠N ^ܩcoN$s`Z)U6}yOZ_ {mxGf2_[Nֹ|X?e1dZ&a?y&q mqd9~콡h>rYyZ4~{]ձ?IZM܃3tJn~̀T)سIT&+#oѭ |Ķ- &yXf#!/FBw=I/ŵogzۿ<2řR,d ٿ;I@_aMV,d _{!݃ _>q|9=Ҝfwf # ey QJ|L|ݕNnC.Lg7S 8=jmF*=<-ײSDzwi\hˡw 6CGfX4ߟG҃"Ti9Pss6u5[܁YV#0Ib90`8d]{?Le2༅xn?AˆUFM1k==—q~qn ᛦ<8Znj].͍:6Fm~[:չ~@j7L>I|J[0Ii#o֝LGWyQw9Y'NÐy_PwZ1hzX3 [Ȟ =<-_y3מhKJmn̷yڂ`?Ǡ؂gGۂ˻*b#a>]pj:/gZeī?yz9ޤk)}8E&\!Wv"\:t?mO~i=BcG-/3|tYQ%M{ l3PaNt1-?Ϟ!]?B97>1ljS^$4r$^gnwDSmm֜"d܉~ƅ}&}Sjv~宊_յkumxN¿?iOv1hb\geB7 mO=Oϖ6Aſw_s(2vøhܱd\Ys|Ae*dvn7lJ;Gm5wǸ}<յ*gߟ8`Ǹ}<}* ux1_LpWVDn|l{D|19-EIq*^οߟ=2 ΋pFͯ#=&aNmwi g{'kxOY {*[E6ڽ̺?M95“3]c xp 쎽=kޱ2MοSyﹾZc~ݳh'7S͸"ꚧ|g3%?"4W*%DN~l;ge!]}f)U-W i )?rOd;U?ṁlxrfd;$3.4e(9k :-lԙv:]uõst-UkwWUs!Պa"ki {FSbWu^~yyg{g<.7!IqFs:Ky=unAղY[/4(Vf副E彗JUyd^Z?~ޫ4QՐ$w!M |*D>s39Okc,Cm޲:?[Нq5U3 (ELm1Bsm%?K1Wr31R8Y秨gxnp.Lm/>9?ۆuvEMz9zlɾi3%f=$cP-bcbkPk-{eLZNt'pBoutuƈ]c;ב׉32Oˎ8$G8upj(pLwοNJ-I?z؃ PoѣgJ!_OJzXA.16P;!/ /8χ E/}w=\& V*8"ϸ` OqMUO0{b=xNz얃$|o>|J vh5A|5vK;]}"?{D2.}%NWM<;e6nŕ\&=͗qڍ\Wޑ=r#Jb%ŀ-\q,;]JZn׉AaNr w~]7zN{k(7m{I>>m^`c~A~济{jEEYk0;odf煶sZO: (o'Oܧ?^Db?W\Ƌ1(|vWkQ9scfgT\g5?@Yfےum9P af"x\xP%l`2-pW} }b3u-qYfn0;>;δ51; fY,`Ȏ/dwi`vAGgZlA4;_|y/b] ? eyĞaټ ^Ь7D_#t˘ҭsp0 ˺=:Oj#{jf2No-}&TuәA?Kw\=gᬰo6{>( k6svBG+Խa{1ӽ`O, /g1?ynԌ%ln큹3΍ܘ[g>qv%sN{8 FXSW<eKJMqFz/>]7#NyFgj!S- ΍[N ع؈5N.wǗ fwnG^lyUl4}Rw@LߞI~ւsվy,u. Ow3RJ?|T.a\w@?C!Glo|!637[}sI8࠲g6wBN+ŝ_ E i}Mj'{1d!ڷa%u*[#/㗗2bN~[*yH $S>o76;mݕ>E5]D1.8 _GS 1\W>P~] ?M(uZmZo\g\科w/|׃'1;M̿~yh?WG`\Ut'-qe<xi "^:A xi]AC2JOUp9+0\F1<\0dG:UNካ׹y:DOwõ`;(8UZo% qm<S.<\{TlCE4M|py,x,B&_!k|D k@i)֖Ն4K?gS5Z" 26濙d*s]Gb[eHb"EM,`D^w; x%E󗛅=g7ubc6\lc3gɜc32ƞ?ѰY_ce)P/illnsDP|Vσ}`8]n<F !ܡNۈۍP_ЉX(s5Vy cQ:f+^w<7yh +ɔ]!/^t|޾BH7u.ƿzpY7F\7;n_78`Dnka2<+C`*A {7a٩lOשv{NeqW>LFG˩Er,; OWMUID4$Xc mu40>&u4y ;٩ܴӍ5U|$3^Ƃzoݽcfqoݵ6]~?)uC?3&тY?|=€h_}8?߹D |9auA2k޺eգψBHȩBt~o_޲W,q s|!:Ia ?_gn ,d'sܤ _(+9EW/DO`2] O`dC B!~*g|v/D/5zZV- *㷓 )E|aag_?[ {COomE_*v u o[__R2n?žDQO2CΊ!9gob,潣bs*AOH3Q>#aC@q&g go}_m2o"Y7õ&֐c_>|!0sE2ڿDE;Q ;0'Y|5J&z舕V1ZP4$lNJvY#EED|> GI/lleƕpoċZ+=PcjKxEB }Z q"(^N:9e9;10af'wDw0;_괮u7}j sX9oc{FL#z ę[iy#΢n"ڡn OLQ&6;b'ž<|#l?9Q14b/k?X `}Y֪L]ؼ>G(k!fž,a';<#:5֏ans_B\!FS{幌qwyWろ7տ}B1\oJw̎f-ѵ09fX찠ŶY 3 d^B2gB̌q^L]g\xhe b2{j&se>AdQbMu°Ya6+]YkXo<ʪr(fp<םC*Nt!2v+v+0a g1ѓ(bs#QB`^=k%Hހ<0VDoȏsW ;gHCܷ-koPz׈ovD(ҝ%/V93~u]TNcPf爅ĶN>߹8o<"׊N &}lkS{v םY[K$ #] ܢkNH[XTO@nJO.,c um\{yK[Fꐝo =02s6ˤβߪzj2ʏ>5_Z)*1##-hm̶~k?/=M`/݉u`[ߏ?(_>Gw tuWp>Y YJd΅ K1Ā]u y^,qG,R A&ľb>ޝE,7pwz9~Q=- ^ĕ3rN97ϑs#a46\>^ݪk}"Wp#{[w.LύW܈AΒfnĕSenT=-K]rBc>z;7ٮ64v=C4j_i%wU9S?^_̉8zD ζD]oD ΂}[M- Ӳ=MӑoKXp")nC \D'%`6FPKE#"C޿Pc$1ǿY_,A/QR3J^b޹쟁#z52AͲ4coԴYܣovP=`A7ղ=`_B9|~rX]bg>I: =:BtuO]!xqLe!l@|R7@,],RQ{YZd1@dɳ0{:dG:Ad9:Z:ÔwGBe'k';OGY5f R?\ y}Eui0| mD${|gz-'s|5: 9\앻PN:t6eסb'dX_0%N$g*\}dgucͿMt@6QY/5"7ſ8VO6QMt 6G6-X8ߢ#AEd}FDSMd#DW0=9o=ܵܿMUD39nO|&2lʼngm0^;G^:9rWCqg6!ָh1)6{)G(SwO(ѿB#oD;LΆ=s 2!Y]>-CN#gJ':^OF34_SDɸYezs: ^#ِGG ͣO'gWw0Ґ#3tWGv"]~u8'N6+(d2uAG~ws3U>rěV{ lDG7:u q'¿F-}g~8g(ȴ:~xiWgWs]cXG 2~ %I%D%ʹ5`927ѽ_`qf]f {<{: d=ID.=wA"z3Zc^P"5aCt6u&|DŽlvZ{;ǔ{O\umcf<<_Hy Eq8_E3g쐶ad/G֯PBW8)ER}j2?O ӽ~ Co7dP9gbw#?ȑƣ{=ȿH8]1揍L$ϱiz T]vݹ7Y@4YY GEYePIOänja/tAN0۽AIUS|vqy> aߘ^v1ؕi7t57|,pA~\ f_v|6kOCNtbC~ R!&9e;,`tnH%tTsFu.kl^v'^v^v7χz %eb>ҿ[g˽[!nz eNY0z)jgNǃk)=UF 윻Kz1A^k|Blkc=n~ս|/$qnO~e/6\rv!+~n6Wzd:qK]ٟzi[SH/ɠ#. Y3 Fe x01zٝ{=i։Qfdz5#!e7y.{bzҁN\!V/k1^vZ{*D֍a3;(]7&B_z]#># r/Flˮ^vN<4^vޙ?E{ف{{ٱzCopO+A̿7__o%cka/ 1xf!=in_J_ם6k&~Lk4 }-/,#synrv]QNu:s&S=w"5f؍cp8!: q\Eo^B↑ֶm5a~mah yt _FEj_ؙ5\Uq_v7ގ@/]ۜor.gR3J!^Jt͉iNC"/e7I/e8I,sZcD1A⧹91=eM')#Eֿ3R9NFE3 d뿳c,LզKf{Ǣ/k|y*w$_ی#bhb9,^my[>.ώƜ'߯ Ҩ m2 ,j~?7-J!S ӏ=ǡ4U3#cPso>2|A/\cKV0c=7Lc`ǧx.D:&e~fϛsq+ؖNcM vѥr Ǥ`Lt- n&~'֣'pc?l/V.ɌwR? $9D(zEqv>7)'l`zftoHV^뜓}֗.gt$/o9Bڣa`nͻ̜Kho1z 9^4^코yh>lŇ&Ug<Ҷ,tgԧXfSHlR6dsD6I)}kC72)_f_b¿?]~?pNY^II4bZ4յaߺv}gmީԎgzLiAsZi yFWZOEbFeZ-Z/6S#ܡ-p$&1K S ?[G}* b`n0Udom:7eES춾={ kzz>̨,XZ*>zcP?q4ksm~w+[ wE I2~>?s#!^zϵ7纊\u VO݊XȍfiM9aoc12F7 :hat-&ѭP^WY{.k|AF0kOUXgdnfcؿvaFUQsjHy+`t^8stE+{ԧ(1I!C:+}ct+jR1m6V*)JCۄ cg__ /c]е*zn_2w[0/l Dsac_{Wǘ)gr:泄7: |2߷x>G!}}~3=>9}[ 17~vƄ_}1խj1߱x?lȐqo;Dqk<_a,~jBG=%XbAW~5Zߒ5d?{~ۚ5cP;!>q^?վ0f R/cyNWeKO|u ֺ_9IWp_}nuZ8k;RBOypZ6ߛgcZ|D*c*>ZUПb#a sq v ;M|֠os1{.k}[ ;ˊy۵鯳!fv@k2^s ?:;-d~z0wXO263wXq{GP :kp`*S#6lI7F-3"G=h 6`koVc[0s^?,'Ws]7cbea]f aa {Y{u՞w;n-PE//o6;vu19bW-q31QO391O>Oꪠ_]uLw&~ t?r[7 R"_Qk\{Xt2,VYEֈ n\Z-Uo G zc˷=FЫsj:4o!"{S o_B ۃU=0ss:kInnN%mom=ڃW(x}*e} - ^;Z 5mf1vX ^9þS<p&?`> 0 ~|lop,+jq=ֽaZ;:aGuuXV:܇Xg!&z 鯅cRy/՛9uwsTX1<%[簥3UXg`UޱEufpXg{(ӀuC~:/ Ez#A2~jbΦ0k5L9>*G ֹH8om l:/Al} ֹp/s+! 6XcPKaNcTd},:%CSXfXE3w\(`\:_?ps= ``#kH/PQYv뜟нX.b_ym ^#LBuy:gb뿯Z$uju u^^LV0(yS}`/v2uA,pn>Ϯ!1W>y!=kc s/}5I{¨9fƝR|r?u#>˷w[:-QȕK>Ya5C15M Yo%3V\"qsAޮ%͎&M.w?/?ִT؃e_An?RυIn//tAun6Xy/Jָ*I#)H_Z҉0]Qq_{N6H{a"e?r&Ɯq,?\Fs֘LKN8NR;WdM-%6s3K ΏcrV u75e{`!J=Pmxz>8oz~"ŲN9~zrx؜å_?2b_>cqA 6܇}^|kqRօR"Jb~lr*lfU/+l~KM;?|^Pb,g/OiC88Fsӽ #0Ҿj3,[N8\:B3_q 3&(J6L7 ]]wTW22I[f3U+T-N2#e{.0=8?3ZrvyǕDq(2:\%P۹1DFe{+brb5dH?7B_$˖XIlfו,0-r|^<g|糖9xbٴ̳Pܦ;ojj 6KMX6o%F?20&̓1h,\`?U_}̀;@H_dYPKʜl9 d;=?kň>ﳆOlIԿ C!ӫ5Δ98\ϯo5&}L>6:3NO@geς WL7}y4Fc؎D (3fxlϤz(_1ހo~{E|J.9e+nY.-Ө%=KTU,%|fD`X?R:{K&tk1GxɆ~5*A-io1[yؔ1-o2nnGRODdn)sok Q?l@:vB4H3O_Jo`g\Js`4k;/_*? zGtw>b̙g= {/ME*OSY|>+fEE_Y= ^8Q f_-?n?9|~qciw{6scI#jÁ55[Ln7eo"ՐG<[>z+6 _qXaJHtW3293hNg?Ȝ,?1|иmMnAz6+T W3,7BiH"g2DhNr739<怭--Shp6k:82 ~=QiiV1M})%FWylglG f뚥ۙ=ؿ vf'G~zx&}QC}dCֺs[Ln;OnƽBƇo:_ŷsog` nۍ(l7-`gqOh2|iǾ= n't>_I1<4RYlGKȃ͗{~a^$yl4jGc3SiZp%aNy9bS^;>a}ͳ&޹`}=Tb9l.3s]_1=>ccDGwB=n6\o~nlG큞%s1>p{ČB46}/g^ݗ{s&;Ė&]#7gf3"]L8a>8;gN2 9|o7HRa|a $g ͞0y܏&^cؠ0&nKMjY?C0m;l g,e=o5/T&MjY 9Y[6S=xLb;z?Emιˊ/Py?b#9wއSLa.~S2IڠؗM2Sm?.&>3>O(ʕ}_<k'u ]%sW&&_,gE=̤o)yfߋ욾]ߟ }B~<"}z'?ħ' ]џ|_/qL!_ Z:]ϑtS1\y}KeG)WYڋXf 4ojs^$110be[1}RԯIvܣ}O3/y9l!?=iXKmBM&}ҊX`ro?}Ui'@{m'e7z9hO!:caTg !}_:Ltcrwil܋ItwO>}ād|铃~l(GgǾg ?[B:?l}&g>v tq5g ό?z zuc߳}Oxtvw~Y2/׋cO+`^/^g&ŠA~Yl Ӫ_ω!̸F~ٲI_6i 6w}i?~fwe%̐]\]OvO #\22vsyw1?:~.L*2ig-D?.Ϝ%zltM$^kɚ8~7{xޟ_%a-{![bz';)O)Ow#<FOH8Jxb8G )wh0VٻVOk:Vi2w8Js&vTUL_QC1aNy肝z+u8i]}zݹs}UTwf 5be_׶p2v/<5Z/%EN7ݩ1e0zQJ~W d(b<>zs ݫqǨ^<+߳y}~}!1z(5tׯgHA/\jH (?{ѹUݫsu9._a)/%!ټ}5ӝ.2}6Jf!2g|E&3B9svWEO]/u9+*_ :wF: 's{"~<' }q^`:get˃d.2y׹r2gٮpmt=XY3:%cCt!SOx9 (*;wfѹXUo?[~(V5 ?;~|rҳ8U)3ߔ"a\@ѳ8 ]2'Fd>tJ+Z{D=1D?)iC9Ef~j }xY cm(Zy>Bg3%(| 3PEzWĿ0stkhЅ9)I/9E|h/oB.`syuMx0Lw,;]"9ٮ[[w"Բ*澼vC-3eٍe,s'9LISn,;]3lXv1Pu{e꧶ w5ʶ! ;58Y&],K@w;V.r>sS>d,շ{ey]ZdYc?"o,M^n$t"6Y '',gȲAtMæeN刵,<ɲ;<yY&]C/ˁb߰N.r^*CwYΒe9"{e94Z-˿Ne9| /˭ː>B|{/,ϝ),M,Lw,K]eNOQi,^Y^TPY GoL7[ 6 +2Su٧e.YK+/c 0o#t!:ey]Ŀ\"rX7c`Kb #w7~Xa, j6`__}f\ʺ ,.y޼ CO(xQMgl^K)AF3vQ<ds0$I?z s?Ɖ:]{+e9f,˫6t5Y7 *dY^!6-E',]忘_D qՂbSeYrcү.2J<Կ3eYǶb,,/wY*bA*\Gd9`ZFȲ H$yr6SYx6L7B.rs]>dǮl^YV2f,+|7Ȳ)c ʲ42؆uHr,K]cLg+WP2z, xYeYFxY>/ei5d N K.Qf]Re,+ˈjY2Je(^D,o3m1,MLlN(+Y`οQ#ܽ Vr Y5|{bo?cOɲ  uu8\^G'VDY.eyٖm/Mq^ˡq^D1/1A <~ݺAs'᱐k=q_Dq<w]%?p{68 Hl(Tg?cm$vxxByQl[#F<_/Z?cDG'y<-] mB?ӿM{P}?l.obBw&_(ۄ넺CL7Z?upp.-֝7Rqy%VE%- -% N'8brpZW?֋mjqтy b` R7Wza5bOvY/ыF!.ZVv 5YG:Y/LL^l!/^#녇. )jBW;ϝcY^؁>Yeh2/ҥHh,B/ȩ,ML.t;Y.~^>dvg1, ֪ey},˾}xYw,CSeY^T&q&29U'0Y )L;RӉՅW!jYeyA/˒6?<_%@vɲ421WI /e o>CwY*b e2IJg1(@EIZާ I'>erIx>kxRy변jW,<&3)k`4곀냟c})f}3xJ}d-xMD=M}3P1@kO=M+ׇ?'Ɍ7~k,M +mtЅuF/%A?rJnN#G:=0Vo_~GWX^B=FC˞0~ϝ?aíOC44yªꕋ3٢ͻgqr2+ZcŸgEgE񹲟yHx1q0LiҮ ?A;^m=PG>LF?&}#wcx|փF(}>EY EXq=Uw*j#=_cl}kHL, a-3[2Wkڽ0k1vy2nڨ,7.S]Σ )1LԴ׆!ײմ ]AiYQjėxj`j&]FfH ]L嚶I70.؆PP=iA]iv0/5H?O90k,eb^0Yo=ta&2k'b^qϝeY{+Hu*Q:/,DzեBD4D?u"^8;{`aYe,elU.&?@IctɲY5;Ƈ,q9ӺWAWe2/ Ȳ췍坓)Weiejy0q,=tAw2U߉vPez]neheMeyq/ LӫdYK].26H։vOrdcZdYXr).*X״EB3@W'j=e@Z),\R,e 󕩲,ML~eL7E.o?Wt"^Y:eyi,KG?^/GzlY ތg]!яiЂɲP& !KEMX-f_ /4; __ى_ iѫk◦֕~iٛx^s _e+&'Yp\.T5$\oٻ`OzreO8/ql#S ==ɒS]ƜSH:1ğB]]%g?)] 껋+֮t!q3OxꉋZ8SۖnQ#QWz.-uף.mxoN7;*?9OcO(?Z gː֦8?e?]ҙH۹Ek7}j]OE3ټَVE>_y{m鮿tpkLW7X4tynܼ>IC~'SX7ȺqN/XFCEt Os?hd[|d +_1 t|~$;I]П[_1+Ӑh>ѝwv3B+˞Ⱥ(`^F3 OS|>zr#ە.׬yljnuS0/'pw.,5rڤMmT̅HjQSjːլOt? (C?si+]d9d525댉n0##|qEu7u+*LJLPV}^oL<_}?7eCQ/"".\L"!޿w%Ҏ)_Bz+3y,BOY#VP3U fc7-QҡeVS?WQ?jf6U[ L_Eh7㯨*gf?GQ?bf8* YԲ+߯e9(Ҏ(L/P~=_Bz&UWԬp,mi,g {EY_{*5Y8^QY^?=}5Yq͞8Ok$׬$b8w?lNԬ#5k'vhY)=@!O =2NY(_3k<?6A[%<\<|-s!$ϙ%<"]puAJxi*;)|9/?$s<L <<ѥgryTU88Oq@2}d8 vpsOE]Dޮ42p@x>@h!zhy~h,Se<=+?#_獇HrWNz80P~s.S֠ _6J^.>`)WLȹ`W7{pjoYJ$_2~뜼̦t_?=#?MOt!{E CWܯ_OZ,َ Hf~,,Yo=tab'r7flP/,S~?iEQz8_tS,:ѽWԚʲ{0}8yT8y=Y#1e;ҾRY^V_/n^Y֩=,ۍ A?)?{}s0]爀Q~t=meY~HS&{ N&Ȳ42{`eYz,o'/;2{eǪWr2T>,`.e_8o2T>,Y`If#/{# ECB0E皍|V>$Y{eyYi5 X~Y EϧF[s?&9"ywqzE;:D~od}>⼃y._6 Dp 5̣L+LBg%26]D/>vMb)][_LNpgݘ]7B3gEsg{~#?CiX 'dm'֝LN{m? m_`xo4's9  'xxyQ.dc^LE(?0ObҋL=ŧ`KѾk/D}:^֋).`E LEOdsuR0Y/5iՊB-0dÛoU?ҝ-op=[{T<ҋ<ßt]LAY/>UEzQ'?^`R^ ŮrdXlD"(ZWE)Җ'z;};mT/b[9/!Y/ w>ic^`T/JΠŎx^?.[[m#ׂ-( Y/LLoHv\ ] gCW؉ՍOQh2G ?85Y7˯7DWWca*WR#?*oi$݄JE=B^bw ܼkO|+҇yшySpW{32c>Ҷy 2 f_Ѝ6ma?.Ԗ fOFՖ>ܟqa987i&]4ΎCz>츢Tq{sRۚղVe>^qy,FoeiejK He bT^ڽܺS-˯˲`/˿T",υ@)1WI/Ų,=tALC ⃤G˵1,ߏe9v6>X&r I cdYt0L7F.ȲS?Ce)YOD8Y;ZdYt,K]eS+!KEmi5^L{,o&,B/$׊b.S[ dYz,_+Dm齴j,{,wxYE{ݧ8n_[LO<܉һ˲BRdYnpwSdYV '?&u, Nt+dYV ';|%?-?нm9 L̺-߭H۠#vxY'jKl3kKu]euvYm8so+p_NcCf^w+0 3k=ϸȾKvAS +~GϽ_qWF?#!zE{}J\[_N}Wlt7 [ϓ6g25Oo6Յ\<7-|Wka򿟉>AzƟ#;E#IsFPd}Nد^ѻ06sg7ag @C'?>0 )=태V ~C }icOg`tlL]^c9⟤?q,?A ky~13X_2Q^0'-6Hc~0zlow~W:?Fk3m~ћ][`cGȏIn|O6wx]Go3|m,3/EH+a_ Dܹv} /{kXXFVx1&C `z_ [BbP yckϣ<Z1Z)w8$.<.lL$ >Xm&f@?^&xj3o b3q|)tC}#?z5l;uM*S-0 &{™݀߮evlYeY#=v6m!x/ BO&Nȑ҆:Cm\b[ ߣRsK1$ӝԉ3-mʖ=9ӗyuldy.͔H[TGzipi@]XNt1 ]֔9e0럿XwG|5q'K{Gh6m^ٳ`NFZA#+?&./r.Y{'#9p:+S<6jow_ G43]dyux~ܻlp@k%~<E@s %y|thY^b?W !_jsji[mQ3t>@uߋ,d,OSk.=*l=iZ|@+-?lB,]?`c}Lo8|Fϡ3/8v|n,啰.^k|&Ȝb_sL#Occە;C qO֪^4g \X7$l1lbncܶZٛ9rm} 5!geH1ޑ`~0>3ߑh|fΑ/[b%^?_þU~{5߱-|φg~l+FE8ܭ5єY~ IJk ͖oK4lC+&x?g3ϝ9,&K92|3l'd2hz0#sN5ɟXg$jh,L{SgxSgEZxuA)Xsfx~,0`kc,+ܙO]/ f?cD_Q`  5Uğo 4,3.[aC/se&toU>9,s6.AY_UT7`,!ZJt9G֢칙nydf&VS &փt.)zqn^aյ:n"7T- ub/)9|h ov9 v~*ko5lчgp,T[><ۗ~' $`eX|mZ#G=xVmA6wca>w R [b=@3p\݄F"Y?}VL>=H30ه6Qo݁wa7YE-תe-ewa-B]~4/ ]XBeR]~4/ TIvsaDv fڟLi8N= Nn_üBxz]qM7"t"67d7P19siO@p9;JS[j5]C>'ۏOm4kD#Fwnj^{L_0+zX3iOD}o&=`m2N)B=5밃}9z%Q|UQzs%y'#v0yr=(ϮC%\{0g3V-eƩ?? gG!mb{Y?fU52$?"9g'%^"@xc=m/ 8{ OZtBW;*[L7b6@oy1l'أ~'KGzS-<NJ1_-?̌aO*î9z?6д3 ~\aXƙMĦM7mj¨2k ގ9;vnQ_>3|8'"m{yӒ<Ɯ~ Xg`kt4ކ9/tA+s\ߛV4~m3x4Ͷ岖*d;#z`KZ.'Sl=Zq8#wȯ#5YHLv=ך7jvOjdc1W6}SZωg pF !3fb2&j ;ۀiճ6qs0sD2tJ229t\F<^ s\F희 G ^=|y~N(9Ի>s>w:$w2E%'uQ?qnտX06cn b&*틍\kb^F̯MX_A0V4x}%DƘk*9{Ik}mL V:,0 ->fWFw>g1'Gw͟3*MSZ8a$uPc=' u|fH:zũ>SL>k8<zDwoɴ޲hA6{b\AX+8|D=V4?_xG4ОW &vP9Q}w7uYPNZNEޙ8 _Ye|T0 s|j 5Kd\SJ`\Fx9s\A^>Av:\?|ո>~\Ya\ȸf@@Cq͘e\30g4Wq}ta\Sd\&zt1q]W7?KEIM,-IK mz76l0aaÆ balZaiiC,taa]tҥ=u}/H}u<{9hC_w;d_}  \E;M96TQĆvI]sN5x:)휿{/Nl6TP%>=Tk+&Nzy%P0Vw0>V_b,U;X&1E>Wז_ԓuu9}zl{%_FN}!ڌi?e Y>AElK_9`M@Mzɠ7S>Q6mks/;ֶm1wG*mA\жLimSm/t1Vi }/f-|!C>J>a;-m5򀽐= `3d͐ 6C.u f7-b; izd>bp=fy?ꊤlzFu^jOU v\/Wtz6 L#@mBKƠSn]o(!+IV *TwDuMD_@~Ym`+䘱II#BѾ I4=Ӭ8!h+_ҖfAD |!m+CV2:F*m?rן眯i/V`|Mp m$y-(]0[kx|M|Hp O;[D/ _C 5VlbG5ŠKQ>/}^*%cGk@>/#߫]m梭Py7+akp?'cHX&<2%N<_rp\E|g^߁5?|?S(?ist|V>P#?_ : :Agx h˳E&g /@]NB~|< m$?G>LϿ|| UbOο +$ HNn9Z_g%?cՃ~ lk󯐁\~܃CF("CJ|j=Ơ|o_)</:g^PG_*y ?Mkpv眯}ȗ,:gPGWOG\sNTtNn㚏ˬ:硸녃^뜏+QDG̴ph/ѵ9ODsҝ? o?gQ69'\nx>Z{{ܟ<ti'.|ѥo"ݡ54=c \YJ資l!R?<!R?| v0EֶmmKUڎY6ma?۶CiGS@ob uQߤJn*"7:wuSU{ !LtSdM+IgZ<3N{i5ftJLkǕ_k|:ϠK'&9tQ7%|L:ϠK-n?S~K.=4l쩚#m{H<- ^!u%V.wXux]1fK:-ҁ?_!Jrɂ?7ė3*#_Q0GHfWߐ? T` f9_9_S1GBpWv uERk3 R'眯r+Nt uE0hG!eʻ?(^dMa\.fyu`{ϋOBK{9l/gûA@OselwI\M>;PGia}vvYrٴم%涇ؽ#N'K:轜N=Kz/eY}^bcg*-*TUtt еLEXAZ9^>*'v{)\j:^M !δ꽔R{^6{ ˂1M/SG'^zUsvZ^JƗ'q^95R/{WSz_AG|9W<|ݍ#}-|[M_O.W|_>aV:``ϱ=/ޮ'3/vBh3S~٣{TeVB]=1Tu;<5s>|'cHX^/{e[{DFe͝.R Q%Hfwl f'^fyQf'^:v 3D%dJ^ d<>´JucWJ ˄,/ /@e.Gc_&08y)sa2JďB DtQǽ%dLOdv:;;; ;}jݪMmു ,hJ?>ywyI?g.,MAIFtA쿇 .㭸F.b"6ARpFqw1;!nj>>[YuJK0ލ^O6tJyn=TE0eI3 ?^|%Yp' 3B\J<ԋadREd7ywO|S}>|`~{<Ƕesۋ>yI%nShڱ6k'[zϣ>wZ/.ri?&(<RO\Ep_ qEI>;ߓxKG"{o%F74kmvٞm/V.2=ogn7>hEtI3:'CP˼6'dz"v~n|,. v/; U{`ߏ_!F0'hW6_7?\kI׃tRw ˁ."2_JƠK0)#69E|/"mg~͕1{f蹸I]xw7I?'B.I #n߱$wu$7MG\O3o//C)^_xn͈a·HzC1xe7GO Y@3 n2B|&`՟dO&'܎ۚ#~-6ch{!0.Ii;݌E?(ş#=6dC04|^KޟЩm]mt15Qچ6ۆC['Zu^|#Q؆]b#o9@1YGAġ+">;Нl|0. 81O'v9v>1Iڅ#va =EVԋy8jt]Xp6w? 1܊K b~fkz0G`B#:5CBנVpI9o"o#&U3!>څ?R8Qu9WāSB|%o&aߌxg]ګŚ#jU^urmCҦ|~6VZk.qv$ֵFi=oj8s{3ձB|~3fBs㈁ζh )oU͸)^ӕ f ,kb)a NZ٩mX~s\هDS>{ASӡf<}'RF|f4';h ]oo#c:Eߔ'#n\"bTkɑ^+k1ԱBg\:k Ƹ6١ 6U*ev@zi^ﷰ5a(mB $Z3={N9o/IܹϷ="mwn3Λ+49mg͸M'r"ϳ wL3"d xnv tY_=unb gF ^Nw/%A<wnH5@&"o |ōWDQ|e s q籣Y}VD}; /DGtv%DUP#߻ƙe֑mbx!,_lt~C7( s.)n}"^̄J }hmJ۹}8PIp8}X d#dz ob0tOS rd.r~-#,>4cAKo)d%~ߍS"d?Am K?ttQF_cKw%4ѭ~r+=Up3Vv=?ABd 8˴P O˫s,6ԵCx\&[|_Dϵ"kG QSk^gYmp.幌 6@F->(#A>~" }z9"7l<<LC"1FÓMO1H9F#jEH7NȪ!@w]i$s5>&Q#D~I=09\3#cmzUP> *kp c 4zql o]‡s55nwH6KtW K}Uˠ{Q_BL%(u=Ѯ52ϝtq U$d5&~^Wc k0*~VcuFs w~Ɓ\o7Fͬ ,-f4=8te6:Aw]Ug1DŽ$֙Ю#fO p-snƸ`6鮨l]ݪ)iGsڿ>mQɒ-@;>w}#EMy֗r/;ˊ"]\g=-_y '޳欈^5崗3%#@k9T(,gƘ !0{8O3xk|'uW{ g2wf+9_˅y:L7Pz8M/=d27R)cQU%?:WM7u\Or3"nT^v;a'\t{"=2t]&gVi=Z=PxOBI&φX,n^ylfE_r3F  }DR_ d'Sջ0g)nɨ*/*>^czi 9GWuÐf-[h,ߗIT\HH-GygKꑎ8[k`25X{ 818?K0{,{0޿%㚃֚t'iBwl_D"?̎u1"Tr9//3\22d`l0v>@sY2ˁt"GDcҏ(^ T׋k W H?*@?~%؏+l: 8a5hz}cBVXkX\#?a^Q'rx5cϋ)^;:ky?WX\B`qo2'6_|ۯõU`][%S@9Xt~uUcnuUx̗Q$d1Y&s_Qkl&rHYs8o2խȐ=#gY/ е6'{=CC9VY❺M] !o1mH5&> %t^ĿE!)g1vvO{u_:$ }y9snѾ/ʖm1lxԁ7 &_Aޒe{ݞ|M-9_JȗfhunN mQ'pqF3_-9yy,4*0޹m8 k21h6rwcDB][Ɛ3phxeĐk mûm_Msʩsx?Ơ^m|?+#^qĘCۢ}ҁ/|g;.r)+q6tNx}Dگ t<&f9s}W8^ p, ďPUrݳ`_u N] _T=k䥤:5D8 7qÖu{\)e`~>a/T ~.}¶܇ҟufw,cprtZF Hsy"~`Lgp23J3}K2oooo{ }3']i}43t& "2b fxi8eh 4Za64z I` #`{7;t"J` _ˑc_R~>=8 o>˵7KCzx%~owgwퟥw̏o:F11cq2>&}mDzmHOz?ϒ{l]ށuO1ώ Ms&՟iV\СnpaL_coWSz8W]j>vrhG݋uWPemp9y9g3uЧ+WXF~(o҃1j=+r_=FxF[.aW6d.Ny=7VOwQsr/9/̲Mi{7QQZm&yϦ(mfksGN*m=ֵ>_UvgoWyrmb0~zP~ngQ3>O O_;ghϠ To>cn<_{IcuCQWE8~sQv?չ|1?O]5`sf4f{ZKrb-i+ yp_Z eD#>Fl)U^ѷp;c]և6q/J2a E[@?$2W@od}yʝk'xJ]uw Z?C?fÿRhvS? ay?E?t,+_)!GpyCf'`Y_*$YC.s-Pb*Om9eL9GV\ySƖnfx|bm}omo*s C7u+6d9s}L?ᝳS}=Qy lr/K4#ƍ]8e?t}jXQv12oA3G[Bɸ]a,LQ_9#TZFJ>Ϝr><7#CtyUNwzND6nݗhCɇ z <7s.[/ayޏ(ױO$2Mbೲv]:G`kh`O#>@xH0.jncۃSd~}0;x#''x?aށZھa\ԠQ7oO:ⱳsW}ρ/Vة ,Wߩ[qMۨmP,+HpW\l_-?搷ruoןMD۶do{[4weӶPڮMDۋ,O6_76cI@?%ߖ&͗zE]7߅z]S;R0 ڞ|6>?wuQ|fH7<tOEFZaތaތaoeohz9zi&Aü oG$08li=Lh0G9_/z_';7M@SijV!5+Q_sGda3&{0 F=̈/.azn/Ypzwz|0{z.z򅺨Dq06YgmR^fh+aҶf!aҶs:C äm'*:f]9S~TGq B=:J2g_aWGuB DOܿ_/8E=E=i6kaxӮ\ +֑ F'uG\R'=:r1xȅN5ԑxC=ћ- :r)ފ]-ҵ"j3 )Sb tr|Ϳ_j;%15l")a ] Ezp޶ ]YI>ہ7Ԉa~Sy 5!sޞzL{B /|}}Sk0mh+o:3MX7Z[Ph/5j0E|6Abi^w}VΊBLE?˩WPj0!ōbU6Pj@[Q-L~Nk0m1餥G6{W!Q`2<4Nuxze+jLlv5g 0`Ҷmq􊹒OpoOk0mSuULPS-țLڶ!Ѩ`DRܶÊ[2-cy"(u.k oCf}5"T!^53ԱB2֥`fWo``Blmh+j0Ѷ=/k0Ejj0iMDk0mi5(]ú:od[BNuRMߪkvmh -MLpkWLr~mDRI{7?ĝPyc@k0mQj] ~yߵ-X#`ҶT9:6ٺSyEW@B:K5-|eL뮿%*[ꭑL[D 5Q O4'mm;lڊLm_nӥ\{iO?ƥ4*AD?B DA>@?GBI.MPrq;|SLd[{;?7QiMyk\Q"DIȿŭm"r&du)7MVds6Jsqo"7M)^hMnY瘋[Ma6?']inI.n.ŝR@7Y5fy ^Orq_%k\[ŭ5A7.Ńv+k+a 8غ,ufՍ1^܌oirq_hh'sq{9#78;K0Iynk:smJ>[aI{I՝8d`qxip#ssHwuoۉ9vM -3g~N]Ww"uWdg$ fbaI~ue_҃MF۠i8#X)a;΂=qe1mY~bvouX ±cq by^Xܱުq>M9`$y/B&'~ދ6whwCmsX߽Xw`,4;;N+FGZeNĝ;*tzgJwM ^MY]cp7WnϹ{j"v%p uWW.^q/*| ϑQ7HU7?" fQfuP3WG k쇪F_Q޽}E5+)(}E7x{zXݖp?Ke%W X 옦PyyX>aURm~?ϡsBt|)mzk^__;G68/KFYJqO"s Hw4+b{N ayRϖƞ\i9߭&jlfo!aƝbENBφ;ZY1И3F~6HGg+Kn#n$jb=W{׏rMg$>loHqoKJ]D>_y$/R!,4dy[1˳`ڴGm:V8lXNFbN%٘KsIa;cNs\.lOI9?1oq6Gw>괋~M{՚ۏ:Ei2rdmзc~n_oO>ƴ](^B20R/A'xz :k0F9n&ZO^*3(=m?dn{SO ~}Dircr،{omoݴUǣO kM$>?-?"? {Cqk;]tm+qJšLDSJ^Ox?|!m9ځ8"}8'x;ˁ.V# qJ>kz>k+9&^ q{M?7Wo'0azEn|$S1C -)ߧԵ?``93ٰu)][Cd|"?AZlWZ&j8AgmT;2'bo8D0쁵t&+l?t>Izqy5Bsz@8]x̃. Н@$eoګ:g2ss]"˩˫-TBw"5󫣉,wg{xXev> XC0sV,_+sW{K]/)!4}'u}Ov)a4P+T/u})^|e5;)7.0~&ƌ-6q )οq6-q223V+x AxAKf=˰bA\gˌmn! a߼ey-1X qu (ǪXX"X:7Uv~1CX~c}jƹm3]-tqXx ņ]وo#[d ܀LܾhHN36r}/3~v1\-lI>xV>xl=}Ϙ>g}AnT"@/ }߹ p ؿKl߭6Ӛ^b=72{7GgK8͕*5V%j\/oxU?^sw zyyY#Sڟkeӟ|Hof⵼?MS~z,~_oU`P;sY#AoeF,kXU-VԬ0 >YJߒx^8<lm_ҍx Q0^\0K`e)ǘAGl9>RSq<# )}{;m5a<3#M{wY8a9rum=B /VD?`+Z^=󌫇Ithbn_wyy|quAy?p3;/GԀ6l|y0#)r?}bsCzc=8|.˽QЖs_sw"9Y}^kw>F'矿msq f>J亣 U :e7-cΑzBC瑎;&Y!O_?Ky͠ϫI\9v3yѠǵ9Ä.-ĵ#%N,\kWaz 8*j<ҊWMյ|zIG{H*"qbZ3N\CT6{XqPrO6?[h_R#,;;x +bE[GT՝E"GXQZr+VhTu?bn m]8?|\cE g=#Xg7\_"ß9G<{Ќ <+8.|ss\P1.DLB\ 0UvTɎJskqz5)\#<˸2ڿnv1bἅ?0zE_`V3s@w]]$]ŨPql T-?Ád=tICya=$2A>6T0 B# 0賛ݧ_l 9څ ]W>V?;{ _1SP>jv#č]$}kzn;-uWp;Vyϥ_<,1iY6:LDyۗ0VG"{,0\Hz V4GXWյstq4x}[=U|= Yڅw߿'$$@}J $ca7}Lo.ѵ]x9[5/6$=b0nyCb[:-1:dQS C| w_>QO?L2E+cuwa]Bٝl9Z]W^]fB$3(]&1ɉVqFXncSLd' ƿld1]9#0 #~ǡ7=7ra̸%N6 \ws9I/?gwUyfX~7cմŸk*h+<-ceL'쐣`7;cL=by%<N'gJ[c cԘg|c ,Xf8jԱXK̶|,C :l,2n~jgbc a=8yn2>߅3brFPH* rF@.3Lb]Nk̤/wlkhk >v͓q^}A>{'db[ng~ig.N5bylhYbe,VlNC{ Źtړ6F#{ LNs6zDKQCk's;OrncY}6XP]ڙNvӵ'l]m[_i{;ٖم "ܦ!EvG=ۙFPɤ yݶxx'ɖ{+P֓J]im#HҶxه/o/gv"/ Rqo,]^B\J6>pqe\jIC5J1;_Ͽ޺5ԇkA$XKDT*]{TVw*Rxό.br*<Á. ܄W|.g:y$?DhK?uFه-dB,N(zwؕkǓ=;8@ <.\k` X`Fn~Иhxb|A4.h>^02]~\_v&֗j!4N%< 1·:F 6y眙-cw4EÜ+DZb,. gg1_x7{:Ft¾qlK?'c[ DG 2t-9~ڜ\{^F'`.16k&# =+   PuÏr7O>}MLOg#}ʭ1MrsޤG<<&K? sׁ/L5 =!sJ.xOu՟{x,NA_1mUu-c]{5h&O6avSxh8:=nyTxA r_g˛y?:Řt]{:nsq?#a%q&s;Rv>el|l[k[pv1r9'?oLsW=>V׵򝣙`=`=>=cnzw?'O>d~Ca>=京&_O7c<37"/?O?nkݠ#5Gm[kG@O)_xߟ׵E<\콆_uU+OY]pOs1'1B{6"#!~,OcǸX\I?٭k?>zXC?_%ewx>t:# :5x*第c X㖼>"0rF]rʁ.@+HSfqֽS}M͞f<0޳ !OaakɈ9pX\$֓%$5ଌըau,xMr〶G䟓q tXNO+w_}A n'u!a^bǽ$zӪ<įt'yM`h [ >p%blycEDLy'6Ic2'D q.tV/Os$澛]'=U\&=e=s6(s\qJsꕃsr8ޯ/xŽWޏT{Ft{߿A@ˤg}̆-?wvCb3߿XpoY/rPUcoG׋jn&`IX#Up I|ZIX"/L^:>1^g][i/{spo M?h }3UzldXgv*72~\fF=?пX=D-G|:;350׃wk$Ʉ;٢kI" ߹`_CoЙ抏` nwR- /=_{XaG8 ^5 ?Ȯ>^Ǐ2׍}Pmg787^ݿ|lvČ`ln9ŌwCx 1XibXglo:J-<cqk\݇$'9^ћQ ]2#J0ïm35GxH5 eGKnе ~&~gMzM(뺝?Yxl7_WT{Q2^b;-O>h5y]Y@H_Z 'qZ8OSb}7J${xf$ r%̰ykX}\ڑN*}w=Czt""?@M4cBݻz0@_=`|J/X&/zo}AXjP0_QWL4xМHhN'4Gq81i|D f3H}ߧs{;A5:'m;fT_g9b´6#t) zը ݹb-]pWj*]K]|:ӵbr;?Ƥ6$қtB/bu=pJ X;X;=<,N;y{?;F1-7Jy/5]<&iXS}g||QV2qwNM*S!יdoplƢ=sumJ2W`Ƣ_>r a+*D~= NJgydۦ:̮xwo[t-~d)yHI6aF8f$  ^$fmq#t<:.6Ks[]wv}c jߍ0_x&rgyN_9}As9>݆9W|m;F;s{+3oc~.1mn|h]su'ELWr5|*O$1j'{|?w$;Űo{Gï"uR&ǬkQOĚI٦{??>#^Llx=ŕ|>:#m;Qf6F[6*\@3qVe?Ba|{2}9d%h"Id1׵1Vǫ=?t݉tqz$er 7V}ySؤoh'FwӰ_jo\5po'>W!#m~cVz̰^^*$ߦ*] ij_+t_""⥿kS@a=bL?? ˁgY[DQ6>w& {}Ĭv}8NL3·M]Xc=vp;uV#@D{O/QOKE/bo76&WW H.~]b//sF~nUlŖOYg]? :t nuܣH)"_Y"ؒ{qz#z \ '}V<λ턽&%j&Ŀ݂ogV[m&(o7$X޿|NO~?*,?u+u햭 =Khut.δD%YrGʘI?|DT7b[V-c?5Q+;$}c~}'wz|2O`u-ߜiGڜWj^du>r-ߜϵiN߹;ۿmߛ 6x}ؿV7|yCwoV&bs}hEw/GܷEU}opRr֘P`X K JKK jaibIIAiiaIIjaIAAiIUI-I)--P}gڗa&gg?{~Zh8&$u;M!}UWd+'9X\?emV]Ӏ?r]  lsrL?IifmLr12r5^^L >_ߌf81kc`g2h2k/D ez>>ο--6GczY6RC |m}E}c1?ik@x>'/og0^& a_lOhnuE(G3r뿒ipS2X_ǮGY4O{xd|j]=饑"yσI@4j饑O= u{ڿ\{i_(spa$[r}gu5j%mz77 ?ͷ_*zR_u1xnFwhu.z~OՁY]SfEeS^4YUԂJrmA|>g.07ܕIXM"L9Hk|N@O(ev2]sο".,.Σ{]7 3 B;ʂ̙} 5D\B89ٵͫC'O,Wc{AjWiخ. WG**{jC$g9>ݻf:\(#8Nj6 4 .V4Mi1Ok=]EXy^\.E;3K5^8^^ k+x^tMc)ߗ?ؾvk]b1/;x^tcbȷ$}X|3P^l@;x^^CX~H~t^^zx^xo[q"pݝ`-oㅹa?fL 0N5;1먶fq+Ao:kޓx/A<ى5)mxGk]Q W.ͿW'"_y-0 1͛M6v`pnƏG?眩SgOwSrbL=ic:Oÿ~15G:Cn+cjzL͑ژMw'zĊD&5| B}uZ}k|=,SQ+ 蟔zXI$Oa蟆V&(PBkzVx|d-?c"5b`=,S)?Ɨ8s*VwXѼ*P?m1!펏nkm ;IlP>K<N2ò}_uIl=YzXGGMd}Aze!'znG]pf|/Xd}tп `_^s߱ k$Swkdmv{6KH/fǗP^ O`ηNouJS;8%mSDl:%$oو/AN4"ژoǼ-y)$YaZ<\Ћw[A r P;Hj$#SOsV@Hz,`=-c6j;9PmE8v e d 1Xד1=x=Yn= x~ƊcE$V4-Ќ{c֋7?]0_Br[.|g*y+Qy鬋Y%z3wL \iplͥ1.. CZq.g1=b/M#CY[㿛F/O='"|}5}NH#Op@6.esc5.2 z;/X-Dkr_3ulK+j/xLce4ͱ6݈%l@X%~$sZBɗ(x%>qQ"wT;\V!z?Wp].^KX\i5:׳&qФ%;g. cD/ ĵr~LOkZqKAR@X.Ѷ%yz85e8vpGM魠Б{O=ƑwJ}]=ˈHq_iV̾E辉ϙ(6!wA; _I c]!R$8%sc4 Mb-ld zµ=:0ݦX6$c/1|ִ 4]2bǿSy,mv |z:2aJ1~р#W+ /Vb;5`Kb,.<Ĝ<ތ}Ŝ f!raN$v|Xps1 lCiәNrru;?N񛝏C;fj^^꿛ngX㴴ֆ<3|wi Z3[kVl;N7Ը^׹IγGhNSRxaj^Ԯu;9Α)5^y4񺝃 NTqvDS&i$wu;Slv΢swW뺝yZhnGnO1چ!FÖ3A6ݎT]Mv'kцn`0hXM۹{98E۱}$Zz͜'@Ou!yd 2aEzw{IV#NŸM'Sh'7kC+/1/!_>/} AG\řV1/NL,Ljþ L,o俫3<$ 73]b,X>PjAg&dor$lWvg\{ݜK|/\U~H+ӂh, ?1F4ܜs4S }1u{XN)Ew.O.(=rߧŚ yW=a]h~wo+f߁]GY<ݜ>K/ޅH-wIA[Dc 6#]wQ[p߿׋<*WXN@w,Wor؀o&&}Q[p]b,+Xӌ}2o#] ]>Ǿ' UA&?ucW3<@Oy,Fcyj$W 42ކEi91خS#78ڝ09:cU HzeS RI ˯Hn݄3n eS1?eeW5, cyhen3 屬gja/<]p}&$W_,2]k܋b,L2H.o౬ej4|n^cgwNvy,mv Q.{݉/݋1;Q<_8_fX0e[<]p:ciK@#~^,fd/9sŤ~2~>C|b-֕t4ҒqԨ.7gCOsqB?Q?Nf_Q*qv W^/^?'ʐSP|//21KI?DZ RǖVi3[2{cj8ffĖ t"W2Žq\cY4m\bFۺq<]m8X,=u"{Ah/vr:+ "w1?>[A-$k&o"A/霯?\`ۙ[Rv?߈"п~A_v@!ь _Wu8ѿ~fk,;kA(P-5_`}BZZu61/*^ox п`|{P׿niv]UnԿ'nֿ3_ ؍Fr@9.ͪyQ!пJvnwb|݂{4/FNz+_g ѿfkuruf;I@ZJ_@mM/fX[]ԿsR-`b %L,<?_ Ҽ~7 %U>8Ӈ_ ܬ%!п$њ'_п"Z{yQVb# GaOXпV ^b7 W/pQɞx IIԾb^9nbW&ϋ4v#KϋV?kVxkثi?JŐ=#ż&^{󢘉x^v/Dr~! ]‹3Nb ˋF;yL&_?f|uW l:kE1/JWXˆ*$#~?\\ElWg9Izwj?1/1%y^؍B"i~/YoZbkT5L1o8y'At׺CT o6/O2ef:os5o+NW?'6o3b,ScG2$H~{eQ=oF]y,U@ _, voN׎p/_9,Mc9l< mɿ_3Nc_[_rn'ˉs5JˡH 0QtjEkx,mv };QUK; y,daEH~Dzy1|.IT}dlw!._'oƹ/ Xn\=rt$c-bljhƇ`<6f]ݧl;'4MŲ̎f7XD(^h6-<]paPW5X,V]7]b,VX2t8c/υŹ<]汴%X O`)Ќ>ýX~C <+@H:_,`?%>2R 4!aK]O 1 ~Ų<+L4WB{Xvf&lciK< O `)Ќ׽._3WIKsg$H//NFgnX\gvjCl9]ɷZGuEe<lv ~K| 4d;oSi@r; ?9 l_i` b 1/ڷxG E+D-]lf ?GNI~ G+n>2xi6ϋhC?[?24RCνYٴo*r ϋ<6|EV67yG'QN" hY\O9x183ywϋƮo& y^My@6x$k}Jxx} \Pd- ABAHJbw+"׃'l/ҐXƋYb{/QTXߝ9@;XXvuƲ[8S'XBcY?Tuw n㱴%X~ ?b?8Zwc,t/SXfXLcu,f2/"yimW&?3 #' Xs3N^d˹̻s% /02|}:\=Ir.Qخ iK,?YmrF^_oKH+>?w@O 3v QՆa,ts˫x,TX:?s) ᱜSIkLH~R%X?Ymrv2eecgKg)c҆5vNv%?^uda7?mb^HN?3{c`bFf;}11OY1˚y,gDg:^iᱜ? eH~\Lg+yroz|a5U4Al3sy,gtvv4F?_vduvYn+ g/^L jMoqǫvj/j72!a-Q<ŴHv /yV|;k`,s^zN}( $Oc秙]*>M_h`: Y j-ȿ$9_Ol<m<&!?gg'ݦ<`.t+v-xStKI<IKvb7e_B?bg_@>ָ/gy֟I=hd%i4v XT$Rcjw%Ew3w5_3<4gdKծqk;f`Y-4;Rpt_{@#O[pOg3]߹t~:vvȏp?bϯ&?=b6L&?ݶhvvh'<ÞY;q'@'=i yrϝgw[;y;=nt𼸻<طG2?nW H ^_/E(G/vgK̋# ^񼘴#{8} xkXiZvO4H8 #<%8H8JUl ɓh"<ŞxI5Y/yy$x^ܵ&죙#t/y;xw[׶Ƌ+ļŝL,Ɍ#a& sy^ܹőMH^ ?e?xъ}4^ޏ ^y11ply1n-xh֯viv<_3P ͇4&;x^vP'nyaKx =sb&nhX.JcL;fXx 4k@9y,AAo]fƉ=C|κwfh,&"y<+h,ߊ0|N T=6l7f`&D,{ '܋B_1TXG,9G0®' O|JsϿNy#?syDc\n® aWb|~<η%;9@Gi}ə^嶞]쮬0>؝uq>ej11 ô#؏dTCn"~?q4ikg{ ic['gf"O2OVLVd9_݊իs\{e> eHcy#S ikTZ;#K]+ݥZ🰌-0&SZm1ϚsM런B>czSIրkn~%aS}mTeo|YUloQfWoi9mvgâd ^hܾ(itɜImtvG h\L8U~s& XBg[$<"9|*t {Ofd]WC~lkL%1X7( "AüF> U-[ƫ4a[FGx`O{z$qmN!o=9^lq3c[+Pߤ`Ln"Oߎ;qV>[GCj(Q]gLT?cgG8N֙`g#S홂3MS5ZJ~M3o3$QEG]8%Ϗ|#+u1oW㳚K7ũƏVԞo;FZ;]_KyW\ی\e+t?yO!O1'?d,U^[U>gZ8`3Y<Y '&yqY]d$_EX6C ka?^`/6X듧Ƌ1? 7,Dey%dl'{D'>Կ1cϨ,dXC[R%7Vb.W{pn6{eƬPrމWNbgi/$Eω ࢊR&[,_b5%w*_u6)Wr낐|I ל$ #n]x׿~-q ֿאzx?'݉ωNc98nXvɽ)@Vq=,{WrnixܑK;z_?5l?O坃3k[k>fZδl?C 4e/3OkݐE\lى1ddZe{8^{)iR ǶI(ƕ2XWEg#YX fMQ@l?(woMæ8Y;;SWJ_Qaʷ+3,#kwmݘŻcwvŕ`cMn3S㤧bK7+8a= ZɉY d饬Ɣ-j?I-Yˮ+2A uN3G>=jmyBHT#?֘{+xk;'ߔsmoV7AOyZWsWxֻxŐZ ?98xy=`n53͹H$Ŕ6bQNW[;ۇLSYW9o~{ TvFwŨ-FSc %Fk1*cZ*kP/_U[v ~}}6G/jswr7)~#7H8$gis@G*$w? ޻ 4^aXw.kYƪ~=w;]م] CÆAİb7ۍ.Y 2]s@zKVY@ZHVWI>4Pu^+-G^?cJEevW:+Fkc!F3HSq=D"Oʾ"4w^4D Sת}O4zD u|W\>Dv?nUqƸs<?Ŀ5hܓsW(}4<qAd/!0&Xm ƻ !)|!dLďq)ß?Wkkc~.{>c\=r@{{jdl˦VK%SbM<+Du籺ws&"sc_޻m/ r̿ہJr{1οl Ǽ]9R|_a`(SEklg$Ix2CYo*Ws>J4r&Byݛ?7q^dޓ8`e||[?9IB0/N0ǚ%y9m򴅶:'Q?_*H c_mj׉qZM]ef" /EY;XlbbA5R??cC)i8F+yC)q /I冃zD~1,7#Z:I`Wrs3=V7lW_n六OkgNK şK#oġ3ss .8{} _>_|.Ys3ݝrrlqv0ƮU[M/^JLBҀ(r.oyhqQ>~1gq" .ȌyYX7Mgb8XƜC:

z8x3|v$s:Lh?%yvw,H:|.0ʜD\|^Ҹsh{ssFjʏhf7 Pϝ?}i_&/+ؾvj⧵>5^\n'yTI6 CtDsRk.Hj1m'1Ee1Dc;F "c2<"ҟNY#k~3_/~N"c1AHǬzqQ{~4?f1N?_Xuz}lm̾ƬΛ]Y Esl;6f3Ͼ|z|j(sܾژ4%q_k ؏Ϧ $gk ϦcqM`88Kh1Kc|$rqxK.?>㱴%X4O{q_ob٫mOc Hf`y1^K`'w5,=\R]Wj]pT5m|l7f`yKt{ ĔRowF _ey֛]@̋ÌoHDbN~El)>?mv /ne9a:w?Xq]Y'N1C=Ij|yJFjcGq?>焯?Uho U $ﻨ=H4]Ÿ \'wx}\Ɲv;5SE`}xw a}qyjGz7K|!hqx{; ~??YG55H ~B?S W!^?mv Ƨ‘S})b,K 4HzGN??\\@m#"]s;rGOvbXy=h,GD!i@Jg^:5?mv ' GOAj;8h> O$@R@n[iͧtN n ohy_]6Y!??o]Z&O]Ÿ@s?׺9yݣbA3w"$?0_AsA3w6?0_AsGO"z1O]3H??d- S\3S\ 2 Q?hgj8qs؈i`?qaHZ3iКQG}#O1Z(x`'=śoat/pP*H9%?>p'6FEȉomyj/?$9fDc o7 l_E⧵hksv*QHZ=o7o]{5]3 ]‹@x|nx^򢶟 ؅!iUϋ;F*5^U/jfyJ&! q OǕD-MRG]‹V(E .xҝG̋/>,ybݕGe?@G0y1'0I/mɥ|HuFɌ?!?Mn xm9)I/}Zj}Vqת煕=YTc~; kw ɘd;(>E>?qƧ0$e _o1{4||zb:>-x{z}0iqL)Q9\tT` ϶d~ KRKJKKoZZZZ>@ϜgftG{Zg{Zk/>Ԕ6r A M>ʻw?/ WGYV6y#JX{3T=z(ۏl6%| yk^;w&ﻧ#g=6{02_J<8L'bW?$Ɋo=hROٳ [k,ljmCZd'daLmOtO~'D=w6#~xIW߼[>Sc̴>4|vu_dy*cJυ\*ΚRWξZbO;^f{fqi$n2WFdozذ~lQC-S~h( T'C?4j!p7D$-/LR? &/&bC@L+wW[xJg0s pA-RSL֟()~[S\뇯r vs-Sw'r7(L[qn(7? ;fj](>ߍ\O0V_A{9oU3w>QwwCZv &u{䷞ɛϊ>Bj7];#Xs]+Q O72zӕ\a f,ݮ\'?_-OY|~ޓiJkwڷo6*ߔN2 u Mi&ok:7_4dɯussfEmP]gjXa:fMa7kg4=d!x-/O%o8KWg26%YOD(~$)KĸCkVr"1ĿeyƿO`OZӫX2>4g&:XO#Kw%=%+^=#dZu8,Y_T}*Sںׂ*Q®Dܲ,c?@7X?a[}oµgeHz{؏%#s V%fVN)k~lolA`5dž8VwʮꋎH73 |'|?_'v Y@kr+ /}UU?8c mS:c_|8l4~\lk,|e.K #3]g>mN>'׍Im_!#~vdž~lq\ڏD yo%HZ!Wu_96j!o#if3Y`AU'Wjzd-ls'A_u;Lr;WT_Oa[mW$7K@o^j}'~IRU!ߏӑTӀ6`h_I~gWCVg8_D֧\n=uӍ̾ۅ2\a=x c;W ^c|"hU{ ۶cT:3WTtU U~*yyo]TEW-|e=EKT؄qL]ݮRJڰ_Nz-s"o43ع_C g>f◮~/5%~*fsKgй_j'~i6KӜ.s+3Lq19CQQ+՜qO2tY$g\A͵o6[]o@y]oJϏw/O正<BY6_?n5 ?thوĿri:v^;Ҳ;bs*JQgZx!jLҳG1GV,sb'hJсϮ6^/SW51S ;'MYbdAL dްVGZǛS+#fQȲU4Ŀ6GMW!vqG tTOjW}n=s59L+b/פlQjIVԔ]rǩL Qe{-,#a|疃!JDTUڝj6%S{Jعj$NmcX6[؛Sdy#gf&=3Gc]Jl+bIzV<;& ߍ|Tym} ߃}cxk>ke䎮 ,F|*q-cȦ=lu V}3o8I~76mqOM;#yφ"nw%ׂiw:M?H(2o E3G5'5wo E2GM`!=}U~IüKuGØnu3HL?%c.|!KJ?y }Kf趲S9#ZJ},עgw-@kV@ _5Pe{GK1ɇɌ\!+μf^):!)x3u=5aUOFLԱVZ(-x/ZBV;da1-]]OD)ԱF&:ROXB|.l/M JH|\ \ouXՅX$:Y؍pLYr~لsX_{:X eЗ u̬s9Ʒ}?;b?{7fzhW|so}?0r'tYXˇq>^瘵Zs=3?ofP|:~P ֚",z~ic|-Yޝcs5Ӓ^>Gqs̡}-Y>Rks)KzϞxp4%s dZm2=OԺO%9>/ tS%x[?L5(Yr_P>0b|v3&d<蚇et.f ؿRE IL->Q7|g,O̯|.%g`>oBrGs&pY Of0CX1wHil2wsZu'< HmZ}IO ]s;]#HH?6(5ou2#׀NPcw԰[kb0|ڶ803T,OiXv-Z` kV#t,Ԋ)G]c? kc:*kcRHoEwWwhd娆1^7ARI2H=e&}$cgi~>^$+Ə*8=ۿ dfE?sڐCK G-3]*Qڐ86 ku29] 1;]Zfg2KdX<=J=uE]V>O(ޓ]~9F'SNBҳX8jRFO|r]U !lJr3Ց5F$iTH珫G:RvR%cA~4Q9$(n=-?a_?t%:k>#oem*$cs+Wov Z<O*VdOn$WLm:iq\_}SI `bVvȝScoO;mvaw{7S߷v*?A]NUX5(;%aI`Zt|_6:SoN}+ykRcvzFl7ym_x ۣi{Mm㩛)kN)j;k]xȀS)㩭xjk5Oa)_Bl=g%~bu,:z_mi㩟;)7_헂#7Wv:L/|k{7Otx*7~:~Ԩb=y<=YouK*3C0iQ>5_6#N28JOYrT2ԌbqLۣQCi{%vpO}u})G ^ܰGh$zxmYsأ&ԮۣsFֈxJdjuȘLY|<5)=Ѝt3%i:O b}dOMۣ,xjs5lv +}O}S#(8m6hS0OET"݋~Pvyy<5ms;_]O}!a>v{5yCvnD[JuAgBS3xj}Oa ³ ,[b>"_Ulo,_~0_cx*kmFkSOgSښFۯMk Wr)Oe Aڸt);5ؿS԰$s[s;nOAgvsF0vSCy;5|ltU/uOpvr:Z@SkxJ믕ruأ`֨k|} { xj Cۣmt< "kZ[glŋhQ:G9t<5x*m>xd=jrO5"u9e? xd5t%'tnz?ZOIHI<i{$d65π1x5(G6}.Is/"A٩55#u8r))N}cP_rc;,NE,N*Tj 8taKMシb4̿/x;5V U 8;7O5Ht<.IGگklZ~*ۯد[]ium2mVfy<~cfzMu0:+_ :'t<Ւy㩫+Zǥ:-#{gg2;z,O]]Aۯ1$'tΚ ?@'S3x*~a<0 Yw2x|͔ eM$߻\?z?|NX[sz?#-=2yB۟ rh\[Niu25wR)`:OWc&Pmk8x_"s Swvyf"凑u`k< cHcZ"]Qe _ؼRU}ZN}9ʬ(lc,#K%:{W.S/G<%X_8ޭvd|'?Ot|_I!.MοQ5p=Yt)vP%@:_j/_0]l7/=_?u]'Qdl+"vy~<2[[W~F}MvG!3uMNO1fxcqrScڙ4;:ν 'M:wGEU.}ˁleUKTmyw<-/eH"-G8EJK_B} g3o}m,a'Ry{+WϨ:q{v{͔/_Zc ;&=>Xܨ괷`H~6zFk!iTHqkk~%ğtd@ 55%5e*v=.E`גmdv=sQ>'vmg$=凤XYK"}(I㣎?w-P@OcFb/T/َ8Sמ<$:1 O.١Ϡ|b}8ϠN gA#R4u>j1~E婁:p{%v*NGFkW#y?Wkyɓ,#O>(9{U[˼Y[$` ޸ ZE8KllxPὌeaU7Me0^fAyfɽGELtq^D b^mUp/C+kBA+@7|R ]nk,< ]5u@^fPߺ?74ܶ0& w~/F4 C +g_i2+>IPlVjCg]p67_@e0un_37̃MIJ%3$^7΃-48&)΃` K{,L2΃-&΃)8r#^EDΠ`AS =Ydnc0(?C'c轚^Su<-轺 _:Vx,d ?fX}UJ+ T4 2B1UlSutRaW~Fu?g~H:͟4Nb,䝌SLX+DՅS"X {T0|`-}H] x_C{)ɢ-Y7ZFzQj4lW#+%|!*gq>o[Ͳb dkRc wU^c@ɫH,ԿRw^6~CTBgIw}y?W.ecG8DZtzoa_xj\wW/{~$է:էFQ!/s ?s/V?uұzX:VOc}xhO8V$o꽃X]{a?PXH)2dбϓ~>Vݑ VWA-Տazn8V{-\XHq9OXYڻzTCO;ؿbl~?c"eYz37r8ۓUC!4/&! w {V31]96Kosܟߪ;8ǿq63Y4S,KV^2gH: x̲BW%m(ZZyY:YZ\2 Ib{,}wNgeJBbPL[(bCbF.:hMІ%5G'Nw CH bO}7=>(~^FX't^_o2[w&9B򻲘W_o~ZƶҜl7YH:Xݥ;!|>=7YIJdp`6T0KziϞLӼD}S g'>97OI=Rgy9(X!/1kOz`WfFImweu=OV%߻齒z8F|6yJ9> oq^'#I!D>cmz/ [5=lWL$?}z/3}njY:$9ٷ qn6{f?'IbG|Bˤ5?3OwlBI? f~Zs:ӑIpo瓮{kQOk2wIy%,K,l-;,eeq-]E1DHE^%~j:@ׂ_,FLV䬟/n~")KjIabCVcY;ޒ:V:羓w[\2a&ZDǛxɌnoXoTF3ДqFǵEh:IEۉO?9t{L2>EG<A❟G۟LT1ϳ]?FyR~{u$(x5zv Y ]~<Эt}'r?Ϲ >Ϲ$ײ:!@,&t*tDU!\Ѭ5>?u]RgK9Ι=_QK͏ 1%3CRb}GOkNr~5d^W&w^vtנ 5hߢ,9x0)m49p MdrW<QE~*$XDw\1e?w/|׶%ޭ%z?ZoGRq;zkA0/ێXZw{Nq{3oѼ=߶~<.~Ѽ ߶x\(t1.]hqKp1Н.%7»ۡp9o ieFҷy\?B*c3qM ,Cgvxĸ7fF Z]xkoI<.@_ay\8\\~e?E؅Ѥjswq__(\h9<.g-qbW "*w.E:XJom{W7sg{J'O?iNOg!>=E<~Oq%3 e_D>p$[8b:v:"y)]$$䱳U ??bO@3ag"pqd1.vfz1-[{pqЕutft\蕾^iZϣ<i,K)Y7Oms7%X3GFEk3M7wwyƱI==3a?'"f<6jM_BJw4>kt~9zͰB73iGF0Aח4c:Ȳ2=WLeyumGҧYy_ߓL+3 aYylnWg?kfy]^*8,>ދ.F9t,0F9a?3PPTnR8Ը)YHԨt[adI>gF $5޶.k,#k&ƮQuSޓzyPÀud7o[hߍUN2ƴ/huB!ͼNv%-t \䙼NxwE}bU~y*qMHx/o[?mɼꮯwW'5ɓ>ٍV뭜N+a/Ϳ>ǏBWM5ӝA _WP#TL.vzZzв/3_L oc_U|&?l9? ڨ}*?HgMێ; ɭY0O9 U^⳰? 41YPw<[qn t}]p-{!: iHzN= = =*? +ӲIUk2/@瑼 }|IMLYK ܴg6Նꙮ,ϦHކkW㧉.G++`L7Ǐ.m_wÆE+T˻1ӱKв CһU/3Q/]"_Agl+ ^^;ǂɴ݀jHb \?s-9 &ۧnIh3~-S3atM:?ʾ{VC/O5Hh^rj퐱rjHjh"-xc#sQ$-gާD~ πBW[|ЭB&'t?Wkh\(tA5ӭqKp#[̍yލ5~e,ee -ˁ3r^в?4BtSyY:Y7\+˃IJ|/eE/ZG#2[vZA/K.ȿ^^D_n__,,ri/˗iYE0/EiY~ͼ,^`_ieKd=W3+_&e$,C˛yY0;PA/K.sOtyY:Y~7pyY1ޕeN/˙hY^:IJxYe'z?B.5ca,t,;@\/_%uZ+u^$3|CT>/釤3c{f>u^Pcvgg,>}40/ _w>>I/ _|d$&f/O't켥?>.ލy4YDˮ ??{ڿ=.~2ixa >3_̧gI;_*xE*݋"i"YnhPq¹}{Ct\Vx]&$ x~U?Z¾ p髸(о}S~J^ZVuWl6̮5ٔYG<ʽ=2H :6$/XoNLYTd`y,;j>x?B}X.ӑtQ%WiW7?kR/C~Usi撷2w6Ȳ@ZɿB}Rg? ͸:خƕ_, ?; !?Τ/z^s1]?-][q4AγN!;sǂ`8ZvHzv)Yoo67y8-J9<.&ӼL-/qQ4E`Lz9mpl$SOvrv$Zv='!H !BpQpо'_qt:[J$ 柼H?6,OӸ 柼H?6'U.HJ-Wq>qoPOѲOEE<.f̤ec.0},p`\E<F!j]x}4 ._(Ab=Q7pIwMRqQ]\l+qJ'hF# L ^c\`:.$63~Y/?MPo@=u@=O$[aVޤY'Fo?)+g>ω6:6cro-yx›=X;IJ|0/˼C,M?˲,Zp_=R7g7#)0/K]"&P*[F|y[5;m Rm=^=@8SOP mu?2iSC%ʼ-y?m;`.ُF`+ۊʼ-."t~6vMNucĥ꼭Pu'ѝ]k xbJ]*|:0!)|96BWU`>_0_z4z|oFlY?co oLc? 3}q,e.χ ;O;9^o NhU6y|yԃNq`<9Awd?f󿘷 ptϱ.t .Vo;8$Œx/_D}0Qg&˜߸  Y4oGp żMfo []=!]A7͝o&Ēo󿟁 AHER<>T'L-"ߵsџyх!)bޞ`t2-C1]6 \,;u?~9`,&“,3Nв<<IeG=IyJ7/KlIP?A]4eeY2Żl4x,ӗѲm/ٟe ZKAz^ ]6IyY:Y.Oϱ?{WveT/2iY:I:hY.%9,ˤ_1]?Hr (a?܈`/cb_*XrG;t%r}=W"HBw,]#|=E8 YJ=OGX|&6:MyRߢIWۣLS>s~-`?)>OSL?;3y1࿨?agH`q1*rg3gع?c'&ع{8-Hye???t5 .VW%+R$aj<.J?c.E xo2)HV.oqaI<.Gno"\ nț1.ov=X[򸸏_.0}lIh3\,56Fż0o2p63mц?.lN`D؇,WWqq7g`\,"EdZv;t; >Ϳqž Ob\c~u<.]m'2o.-qŷ8gC }.ل,ZU\ys9u\ܟtZvT#)̝o0_mEV4F1p{3nԿW@KeLr;oԿԿlō{Qެ\l0?=el -mHU2e-˗As|,dfyY޴֗k4r/;//o{/r/S&}i,ڂi0ߗB߫e4; ]"~T~/pwS0/t,߽~>y]2DꇤHv%+Y?;9 悍/q;3r? o_ojvl.43r(곂?o,ӱ _X@nn#;89̿G4o#MM'/1?U1YNz^ ?n󃘞:?w>m8}oQ”㞝*^;;pCaYvn,(tw/:7 ix'tYO*1x"?V= 7,Yx}j,\_Aˮ7s[/ZvS?,`5݋3H'? ț_~i3''FY6> ֩gqj=9gjP4Di6jK 1Qdj^?}-I oז,[6= U5ބ}K[KQO߻d(uhXi }IrOW~6'? CʹfCٟ;UlkԫQS3[ڭ! KUϪov)jʮ{bQE㦔\~'CR檖]%@gۨ[Sڟ5;*v,b[j)wdyˆS߅:339?Rދg_:4x("325*X;9szwtwͤZ\$]'e꟟ɂk3rS4+v%zYP? Y3T{7j=XS(׻CBh5Cҵ%t#P|^0`f([q ?؂`h 1]O"{s8?Np}E ]V?;<[oq^F2ع›w;#tDi >x݊H$]cg8פ Mh.^0b`-qqC $pG qn qKp1˾+E"lWqq y0370в{?Iy\\Fn"a.0M xx[n )/x$].> ce1]0p{_A8e?iYwI 2fot^-2fW7, "^Ҳ|w9oey-s;]B:n|7-ey-s;?f矸7^+RCxY^Ari.-e905B:K0!,t,#;]R,n2KtI$/Ttӄ~{yY:YT\RnL /"US 9,ތü,me _"xY*tA\^DcX\Yf*5ʞՓk&&FMyɑ&"ǚIlDOGmDfٶQy^E]4.?™x~ .x?.ًA?$竭w"l_g"; I;Kjlٺ$_gWp4G4me6#;$ g]V$uBO_nV,b uwfx;qdӰ\9#4ra1wefFRl$c~?E`tLoHsIY?;E'er#t_s"Ops}#xIY?🪰\?] vD?}O\z;?k`G?9x{IpûS^̹OWTS%ymz@L/\J.s ?6 ӭtB0: ÜO_fQ zw 9O=GHIt6O~d_*̿ af>*v[hɯQ,74o 14ɀV>ίbo3+Kd ӐeQ;yE;-f$ fj>ƀAl_{約Vp:1. +h*cLߝ])33/3w3{2 _~ϔM*$2I AI{ .d@8&oYN0DPw63 .`*;Y1]AL_Opp[Dg= CoZ'%!YA[ Sw/?L[7CFlыo]431go}рo]Z6K -gYNvr@E^܎,]1o pvZۦYvouV<.Nyq֏Dž酻x\(te\,!tt3 ]#.sh*:.y\,e7}5|Vx c\`*.|&m .qqb 1of&΍ϗ,qqĹ={YN.qaax%_"\d#KK\dMqq$dҲ{YNlqћyO' L_EgBâ9҂6XXPPXZPPRXZZॴ[bZb$$ŒԄo|gڗ9=O\\{^{U/7y[of-Qy^x1k} s .Gfd`:w .Cc7u,Oe1]8jwT.d)~tO$ydx?Uu[X}y^vAOn< ]‹0/,H~/c,/A?ϋ?eH>%n(4X{CEL1/31`̟WMk1Ͽv5r^S+'ڎ՚ DTMqU(CVSu6ǦMfM-=m@DSj]Skva]VSM V49_M-T??F ԒNY _ -ija49hM-FүA9dXSԊ1ス?@SaM06ij==jkjپoij:`񴁚Zd}X+_C2co&?}W 42]o~%պ]rkjI;h]gjxq'];9߻ ^@_Eb^oyqm\$.пoebۀ@`+}ɍVF~ res%d:h=Eϕm ݋'ɿ5%/z]cl`˳< 4HUpqEt? lWpqe83`rX^'@ Pcyr e};!hK]e]rտp@cDb,y,>Kc@$c'O\cX!vK]enI'X η?Wb,[Ky,3{Aj#ٝܤϿ_cXBϥ<6˛Ҁ]ρ)b--'IᱬO|n _3wA}79k}2sخ@f`7eX,y,Ҁ%XFkux,|v83x,ͦXQ.S{㱴%X?XβS{X, cyDzrE$737ߖuUtm$,oԦYfg9ciBc9z=x,X?-XvAmDl7f` ԦZb2g0e g"2 P Tmg`K] zֿ:MYk2{=-M<5i,S\+?^?9LkS&W '&f.6eQ3PșTL|:t,$ZOGr &g>4~/VmtNwB-{J._ )C^ӂ?9ObR]柚$иQO w{YY0$QHQ0z^k9u?$9 u)5b^M_׵?)%aF/v)GOwEX>9ɻ1waO:{2,{?awXMߵX>ɻ_oO=kic& {AW&{z`??pHf.jRЌ׬jrppKu~ף9%ϡ2~@8;o?Q킞 \]f/Mq`KE;Uyr^:w~wߦ=V*w{bS{*wCżh,וoӾ6?3h1 .'a8Dz22nYcY_Ecyb9ckt@lw$.*r` WXtj.>\$#S^Wk.BˎgMK 8L~t$ߞcrXQSmWzA`$Q%~䕏&^cM%H pZZa:m )g\j viT>#rIו_U둳{)Z&{ElL]LW> 3fÚ>+*'MKsMy@ 홥*LaSW4N1}GKfӪ2lRYO#]%|R&_;DsXmtɋ )t7n; ;L?$}%ϏKHߡĮ~":b# 9hrA&;m]rƁ:<I rw{59#%O5~~l3: \qml#~68恤 (572 jw^bCYQ.VNX-2E7' ɿӕ.\"n{c4n4yj\ 9ByL鹊~EF\I ]g'nC]9(wcf׽t^H^?}s`l7s˾V۵Ľt%VO7+R>3y ny}}^_9bϫBz":`9Hr8aSw|wU:7▪qUA&b.%kV ];EXs2WTyM[T>GкW%{k yD_KgHfQ&b+s .8Nf=H:RL]3ߞR*w;&4H#l6yg{=K/T~@/eYjJ45ެqOժü#q;nv;<@֚y{AjiFc#qe0bu %a;N] 絙]Ț?;ǻ3 ?׵$q@?׵מkmy.#%k\0> _&)]7CYʻZ,鵨;6 iu1z=ZisG[Z[yo"Q?Er-hk[m6)۱*!RQ~Ldg l m?;,77`s0޷~cۙߝW޹0sǹ(̗1,_ϊ-/|J13 n&;.e~n:c-Tt57PgY3æfbTHM>$ XxH!]iNKא'\>'\Cw_]by-qS)g/&5hU{B`]'M}q_T;pdvX7  ;Rr:mOj79w@k_ ;>JGrQ%{?I*ڎav7h[䲶 vgL#tM0.eKkK1!/MV9 {c_-u^`JPQǣ98C^_F"i}YOA>]՛YP~cHHލ9Z~rMIO?[Fݭ=${jwl=\A?6XgSO I~^F-BgIJh>11EL^:=[.|Ţ>]) "5 etAˣ3@=pK Wk >le'|ɳZ+۵g+YE]$fR ϦSEWAʹ ǍHZU9{$gq^Rݎ#w`Ŀsi%ox{tBn%M>M%zv>WͿ#_? WK ;ѧQݹrsVOwntO{&ds#\HlwKxy{\tk? HйS @;g9P#[}h1WwvsR̋oGXD6ɥe /p- ExQbd_΋Xn7 7il}ESNᶋf;\ f-< qy~$/fdx.cyѣ΋H|'u_NVy\s*A1#cA w}σ*TP_F X^5XE_䣺ee_>$/C5rIo;qVڷ[XP6 []$(_KGϖFc,V1VX.ZIcٯ,п/{?@fo?,ͬk"#51^Ub,?c0$/>aM 0nvO_}Xz2ȟXCcyS4XIcysjK=X,GMR4K;z *y,0{Av$c ~_TXv,H~f`{.ꟳXfX.o,ݐO'XϢ]6_6 n<+_Aˍ XX7rƲkO1kX@cyc ˙A,? {DnvL7?kp ֜ ~H3(`x% 4~lp|PpP;4x:^b|b[hsy,C+<TJ>P<lv V\C^]q'qYm. sc_>gu?vҟݟU?X4}e]k{|4e.vtPW;no8{w)o [7ӫuy^Lp?OwN ;sa4gS+y,goX ⿵[y,Us$)籴%X_kv3{Xv ccqeϋn.r/@\9딱X^%:˙^o \u [R Ύ׬G:K]eZώ3y;RKgX9HcRjjz,;f`iOGx3X,р)|#/o ,ȵJ7s?+#Vo8a esGy,NX7X.L ,oTb,4w#yiK]e [Xn,g×XNgWGr@},/Wbi/y+a8O7R c)1<h,} yz{h,}^6R t }`<62v{.m۩[矁F$O???f9Ӹ!iZNcj?Z9Wbs3y˧ _G ^ц%_;bsO=j,w΀;EV%[{hEr;s $CTEswKcYUfC|zr"odaMZ7oO'oL-/"'.~lO10rm*^wlGN)bmѻ9,ԅ@S~N1 1"RWrs\Ƅu+gx/O9Ҟ__3Mm'G ۾sZJ/2=\ uXDx^ Iʻy!l>Y'W2$z'Գ)~-_5jGu*O>O+";R?M!C-!I:;źB%t=*T\#u+sqp,!d-1j4=.딙N'$ߏ:M-VNz_zPJHվV.$.L P[(|~ck {}YD^kڴI[O =%ꌤZ+gRb& \ ?Jϛ⿂⿮i[3Urb;Cu =I%o$ tU?)Ϭ#iC_]yvQ HϥUy.UC{.y"yq_yUQ4#cY\Ȼ[˩aר}+o?\ܠ.jIS7B{c/r䟘}e@^=%>ޯϫ'\iW_ #W$W}@LYsbC>7xxMjϡ׫#SYc s1gKsݎ>D:/mk}/==ޚq;/62 CV)\E kzw/mŞ掋a!AnFHFuo}AG֘gﮉHg'?_;MPC&bO1_o-{;`,z?|c>w&L?%{SS;1>8٧;t|ع H;3Or?yտ1O|;t ;|z1x|ķ.H0dB=_qR|-I|㲓Y!GN.=e +ZWX|'] b|&Sg_|p51"w1<|U1_f'MH~ggDбȶ9>;/{K.^y^^lc-|U$`)sEE1߱tw,>.V1={ۗ׵}HL}u c}1271ۉc>q>~w"vcEMzw": F8c|4xݟ7~̷/s N5O|+15Z7a|wxo c t}a,_9L%yq0r/m\w(N|hc37!%S7r9!|̗>7οv^ ? }07;hc؝ w'maE`FF'yb^y|OڷH~b߲ ;;=i^mv/Kxv$J*4^=fLS؝El8[H5m, /~3v W"H5Ѿ3ik `?x|C_\BtǦҸb/Y.g7/]D*wn(;2v 7=+U93.djzzP[؏07g} ;R[@l5<<g,|}#y4[~ /ql%G\gXΔE2n$?b'3䵠e:[Pl6Vk;NjvfNʯ[hNƾ?LyCO.BrV6@}ZڿCg|-q4 94kwK.Cor&.r sЧ#CtNЧи?u̹N>ՇC[pe\Wj%vR*=f졫éC'G9MG 5W"yT3tV~?ҹFzMν;u{ǰIߺUz,-Օ@1ڻd{hmΝ k'Kydl[LIb9tdsx^$fѾ-El+-]_'gH̢4vWhb9xbFb^ԬyJ8ϋA4vG2 Lίi~M*\qsӿr 1,Lj_(a>A˥ XXK/+.[-9^?@KEoFHAc (qt;[?,sn[ iDzьbf!?.bډߎԸڇ;U@/ͪ⻇bi pϝz!c Qs#Ej.ϋ9oʐ~gi>^B xq`fp`wB^kk,/5E eGxz"";yg8Njoļx69B$TxY?迧ƛ  b^$fBK@,"E>xe W&#9:4v},[x7׽9^|5@̋x$eXM4@hK.>ۍ䱴%XG!|͝or>y_h'I99b^;h*'!.v'm83s:& yqgTaOhb:п~v &wX>Kcs cXN.XvALCy,mv enI'X bUbNCygGg C-~799^X0qo?Ű]oS?2jAۂx6S@{$"I/nc,/ր79^|"ŽCx^L9~yqڷLB }!~19^NJy^oG"CӾ | yvl7.ŋ`}K+5^ˋ""Bc7͇߰ P5ۧ x񑝾4߃hj#yp&`;Z/r?[ub_/WYT 5dܦNTy˅ǔ(X*zgYy֨z;y[L)}X4=AyVrr>k/YI EԳ2KyրI<~Vpuq 5CQxʫ"8{#MʝpZWVSS9H,/s4=J;!ZrSL8;.&SAo[hG}&{9{>g=r략_f)o귪j~I~s6)XG,a.>~/ּo@g~7H;u{k";C2gU|c sz ?s]A.YßC;85`p;x,{XkGX`raς<=[s$X`j>ƮvNÉ=?k8_C9iF5Z_1^sD^f_%~v&֖(ZV%Ub_$^՘C۳|^)LѳWD^G=5p&[Raf[Jᙹcs\zwΥ+NX/ FF# soRq#56SuO8x]HV+oALۓ7Hv#s- lvov2搷(٪zPR&@)+>2Dz⩬'ksB_%P1 mXC}y߳Ԫ޴NZHcn$˂4`;ۧK9fְ x=},Ej-_/UkRS8X뿃gY+I;K_^!g,B^VBJ? y- Rw2ELsYQ~'-eK?l1=hG"}Rmr˙E2ig%AwRפ%Lݧ;\gT0WF+m:e 3r"?IC$3b\2ų{1 Z'W6ewB}zpOZ?alisݣ^2̉셱-mNqju%O9f;.|>k'wyFw+fDk 4J6Yw@k##Oq`]%'=D #E~ͳ%{`yU;,q#3u.cש7T`;o߆}9<7?@kqx⧹ns{żb'ÌoHgHPwS3 .Wd&6#AM flNnglcy". i,Mu ǂ@B:O=w+ᆲy.F<;|FXX"ǏynlWP< ߽KW#k0F̿q1XA`M,ˇ@ko=n+cK7h]+4#E1 $wlϚ $wg1 Y82UT9H2KDvb7,͠-cⱼdT;z=x,/=IO>LӃAERԍ=nvO>LpPt=[b9Q5PX {h,vG97 r$D#Fs$$_ʌ: I{#| 3<_;9?-G19 >wQ=K|l#Is$ tIy$XIr$~zdr#@:GbHIK\D:+(po9Ղ[DZ7ΑNs$gGn$P[ r$~99)s$/s$g}99ɸ}[ ̑jZQAO[=F?OgFVOʐǓGpn3`#JAOlHjx0?l"vӰ]A geQ?ˉvWDXNVA[W-ogiخf`y/UF`AԿn폤37w^p.;Jrj͝ԿtMW8mTrY+*S+i,6`]x,ݘZppR Sg *K]e8?*,ySYb1^x,O&X^S#W., }G'خ@ȕ? gFi ,_;Ӈ2OX̤ >~<]p~r屴%X޽[{NN4L;=*y,[vXN?x,Y2Tb$䱴%X+Xo-=:]_p~;NfuM| [o!=۬:v8X玛9.+I;AtfkJOsDx#E ~]9N6L{ 􏎦gñ]yFh?b8k5J`n*;Hcj< 1oAH }>pԿ,oտ UF|KSer'柷3ooϛ,uz$!??wdT=2M\[ u<.%h[rϘ(1ڭch3msS.8dDbcy21gu`Jg烆^4v飐k.ϝS̝-v8` \?^<#;HоAI^yBlWPuk/:ێ ꟎3O}gm#O3 bT΋gT/:Ɯy{Og/ת4N\w"HZ'iO2kP$?53kao@i/$FlW?ݨ??l>>3JpI}tҚeS5?Gc qt_,O_S&->9>.ոSkGbΝu)4v)[Ts=S: OEVj)yQ-MF0f $BOMӀ]vIƨ5x&ϋ=ch.ARM5ϋC̙/`_$su-?Z#O!@CҞv?2O/}IivkdizqF^չw!]h.߅hGal߅{_?U¿ ]8*-].\7 e6K{~gSѱ;.i~2kGI6lȦ8\׳9^ĉR#oO OALɱخ oKx v28H?h,D.AW&Sמ丹v_5z^{#: aAeb_$}/70kqA}_I LR`ྴ|1e4GR c5OvLuUX>.Do9HZc3}ncw| vy,mv =]vw|3ˇ"X6zX~#XG"۱ȗ?yKϋoB]{wAT:p4+%__vfyxo ~@R}ϋ?Ymd_/}=ksh/|愤b=j~J80$'W]obiF@W#Y󭆙-tmTt+?ȉ\I6g͏4!=e~z: II ױ>{).7Ҕ')>M0 `ɭ>G4sg4)'?+/!*hb-8yﷁwl?S}Ypr'Nbo4f_$mccmhT3HciKX 71 x,̧^R r3K]enx'X r_&0;u(K/w1]`yy}FA| ].ݟ;.8_5`).$Y"\0{f;/Y|}6 ?w?0j92"Ie`54эgwWpU/ڸ>_GB.F#0c'Dz,2j6XVXX%pl7f`zw|]6X}V7 =>x$M~X4~.zK޾ɤzkKտ& ßs灴ð?0gN9Gyj:Z cw>3s'M.%8GG yaKxqRSY'|5nVOXsIx,wг 55<]޳IX,/ׁb"3y,׎ /Aҧ<Gi,σ=x,U>䱴%Xtଵ6X,IU}h,V0};=]:Q0}>sv߷ߥv}_5`yZoO0{Po$ bSn'2$?}E?IgA{wgO'? Iճi,C+@i$??MBӰ]6ZILIp>Xm`;yU4!Zj?!خ@f`٦?~י|H'!11887H̟ /h[&|0?jXg!Gr w=vk78l܎r] ֿr9^ Jfˎ2y$ϋMɴo ];*Tf4~^$#X_6ˋV"5by^|A׼J@u^$-pY5\Y o?}yY Og_oy=/@Rq9 ]‹ 5;Rċܓhu΋/y^|4H*ysm_j+X l_yisb^[A|Y !#AgZxl/){fc]‹;[@{ӹɚi!ڍ`/?Jb`|:t=ilκE ,N_(G|b746C'?|qsΝ}uÞ4v$"iq6ϝ4vGAgk +Zb^ y}y^n};-#x^v/v%879YwZ=E:/6xXdXÜϛY l_Erxϭ/y? ܜE x>YI_d=DeO;z' OI i_鰮[[.}?)à3_]Fb~Ve ~V,m/\tCw8q\EkJtM^)-hs<ޯ 0yL^Yfwj m{MV0/Uv;`1O@^ 8`{a I掎1e+ƛ/}fA+wSk8pw!濮`87>;흈Np}_k?qۼD[b76w<Wr0n nyJ֬Uߟ箤/ A>迻U34OnKޕ@W?#kf;7й&ߟ i42&?|?Wg!l9PIV4M ɻ~ KRCM.qA&eri%Gh%+.dr>V"-<4$>&dXRtln* ]?*5xWnTb77@lwe^5yӉ؜S/cf8'.WboQ߉>U9ð!yn!%ߌfSq#?<\R5u֑u 8;r9&'},oW\.YoM}ϛh,ƛ#$:wwqz8y2vz?GyמQHz w' 5QYmѹxNc_ Izk^Y0#чtσTl`\}S1WόuWٹ[jo_ ~@Ix>V*3n.fBG.y-`_?ک}>TΛ=[WAcofYԼւJv}5КxxN(}둁7 x^,{"jzP65 [?:#al*;%'x,XvBҌhi-T?Tԫwf`ԠNb,v ӊh,}q7]ps# ѵѾخf`#/OP=?x8KYHVc9 ?}cu>n<._`ץ,u} ; rp$ 1{npTAM^ф lv @Cqgl䍹R^a7j{}I9A^:y?asq[89vtZo!cdWA< "hF?]%J j?6?߁XK;%k^h,w:w޷ܙCc'U )λT 꿗0>!}-٪av^v[‹h߼~oU/,yq$MYf d]a0̍9Ʈў[X.cKEH,1ւOx,_Caخ`z-^wa,_3rN|I=i,=F LL-7 ajaڰ]K]e%|P l:j Zk]4~ݼ4)_ގ 50~Ȼ<g.]\~hռў+2+y~/bܯz_qv=iݱ0' ?׀_qwy߯sEҫCxdj+{_cz2ޯ;&y ϋ&ڷ.C4A&S Uoyڀ _lv /G__5kx:/TxyK; _`j/E//o0[9j'o1EQƷ$"l/Nȴ{ S%^^l/E^5/2 q}QoWDa(cr>[A\Q Ÿ"[klvd//a|sGRe:n/uqfK/ļiup&e/[y^dl}{/,@ҋ\Kp.[/E;څofXX/FR;'d*=[*OdXSgcoh`Yl଒n v |!\my3Il'e&_Ŵ^G1&-]9g>%?g2w!s|y4Gc^c1']_e ;ik'X bǹnÚ8;%X~ چ=f t >"= 5?#~/M=Eq0;SGaYZVT{daqy <@_ uծ[l!vS<lv WWvr/иg,w7 {4l$y+ l;ð}-آaKf9Nj?yH:[#~e>x#lbw8+|Ƴ?"^ /1 hهX$=2F{ ο;يfLxq\y^Ѿ6 I#h?"?Y{ vh??x\xkd!p?ϋe_G )>>ÜyL/͊L2[>Ht"-CZؐطf-?yP͋l^|/?D~hx񐑳1/t^i;0Id{տu^bas8h ;my)z>Kg/}͖j'?V{Y G",bA/]{PyQߌ { #-2 5y1ZC;iݑ Ĝ[̖N7yZ? O2kK Yݽ5HBߓLo>?/ Ͽ4^<`d:/Ry^ܿƮї?i l_ER/~>(E2JxͬuHz}Kd¹F輰gBs ݿFҹ,-(-1H-)I)!@ &habiIAiJ(-IM),}Ғ{Ϲs1{}Z2޳~D]&q)X.ʥ,$.NrN)rD"(0|W $rD" rP.eYWI\x7b[u!gM 1^Yc؞/wv3v` K8Mo['¸qKgǿx?_@;݌qȥ)ND=LzbԒZn*guM; L1_&`~^PDQEμ3A|[a=;ypeԛV爸[.XE\r5\&ra".r).)|y_RkZL\fA ܙ)pv/OpaorHgVS w$ڋO\I/܉e 1b_4Y'(0R;NQ.W{a/Ծ)]OQ@IFNdIV^lFWK7r_;\iU^}%U6c3 gwX/ytppb9[JY{z!r՝b^U$.]GPIoI.W.bq-"s-xMO(g<+% q+ĺ$1~٬.7+E]ڸ^Џ䈺8φQXTQT[O7<㽫-N_e~.?KrSA͒~8χ>X$o( Fnyz3]&Q7 %VE]rAgFطIԥC.c ǿ݈\ڻ\.ù^~Xe4< (uq2|PԥC.? ݽt6s/fqx?jG^z&VS@8w3γœ8#Yg`a%?LRZd0I˒ٚLE`r&x8h˼\=&vbnHxY(aXrX)丰Ev%t;xsI ak{``.7?7Po.7:r}K|7_qe}w|W(2?_.f X r]Fd)55(S.z!?cWv ,DԥC.C 16}K&{W:ɟ2ZeVKoxoƈ#\Ku ǿzyy;4?6$jO;|4zHLk{SR*AF"+pWomm;yN;D!]/~w7C.u`_\܄vQTwnN=qҞ]85D#zs=/ǀ*~wsxGXq*'<k9;W })GHhߗrw*#΁er]K.٬. K6G,J^}'tK.^WZ X].H}࿯X˕=9{4࿯5/˝#Y] H9;%_#߾K9;;%7oG8%kpG8w@?IE};?G,oad3,sk?,f_+ b6w(˕;$f}&v.5%K(g 9c|Dn 3pQ$_EG;44;d犸\8qKqF w\txK{5Rſ6Vw3Q"G;;x7qIs=NjPo3ٱ-(A꿕".`v+v\S.fpȥ?>eͻ{kr]^*LoV/Fj$p˙ެO|+r>w/7|yr!5.1?-֧O\[@|S7|ʿrij:o@S)6#&zW炑W";gOK\D0^__]ʨp,WRK%?=_N|);yBp"ΰԿ&Q?;`w(#>eBgX褮~Hc+Ϲ".ر (\S(Xn \]_2\lC1'x/6qq bu7?RO%K> p>6{MQe'qBD\̎mvROJ. G0X7g0uRtYFP;YwCQ".Y?.|qC%QTZbgmcK\LW }@`7ڟBap%kcs ]",ܙPfϰ@vۇi/D2imH="q0߮|7OǷQH?Icc|kϠAG,7lfC`j?},s;7uGH|*/b7]A-o\)IFbͯÿqu: Կ2u/o!8& cǐt fβOZ>{g\gF_ҞW#cwQ} _7YʠpUD]:R]?˅.'}N$Y] ?G?a&]{JrθF.AjO ?E.u'2rc걙T fqN\:Xsw~.3֞뿺Ǖ&y\K<ϴX9~Z&:mC'#_ď.#NK'ȍ*ROS]du7r R?r@Qf7qb9oNbw!#Ij.Yv,.s\Ij/S+'\lV/{t׆Vw#QR+|\lHȶuk/No$>lH %g -I_өXC.Ņ%uWR_zE8.aR?fz>0Mik?_w;9q%H@fwm${=BsGbo\_*?p)\f7]M\qQH]?WYݵZ>'higg##~=Z-q.R$>gmz?5OO]H,WszR$0}o~Hi:D{VVwqIH}J̧9.|*K]pS8[;I+8[7vK!X$V@>+E=R_y3&.lqqVwân2Yݵ7|_Qo+3\$pr1H];CV6Ƕ ].;cwm \w'R&xwq1Gq]L/'b [YMTp+6Ik g mqH}G*l CZcĿ('6ߑĿz ,]rr]~.}]k$0$MmT~'A_ug D]_}JIY]F"mIl.UIr/ѣ\IlWY S]&uY!_ڏ吱H}KR[_JR r%7 KUުOui/r^p]7Jo%_$?f9[.o] BQ+Dꛒ?w&[i%RYX$#6Omx]\q_RnˊxZ7[Տ X6qɽTr/+u53 't(6v?-G AX(??Sne{{w-'>.߰&NJg1="r?#!-܊ugG,jgx˛6I_l`u9oH_g_/j?Կ(LRb=[BĿ?d(V ˑr]~,4%H-?- U\Wr%O\Y ?1G=qxyJyx.؜G(on13=dyg1BkG/grvG#ErFqȥԿwbE].r@-rm*'1,R +7#u~QTAOxwuŢ.[H]"]+C7/u{SbQT@w3t2.׏uj"3_I5] 6Iñ\I5l z =yQ  OSՓqA=bu6@7ư{d8aw3"~ǿH66$^7coGpr],M.Ï!uaQo fu.s="|R_,! w/.MrQœY]@E]:|sNu{DX;EԥC.?#cR|7\eQ X_* c>Xrȥ<9Y#^ AjJ=x="2#^'{DSg{ǩ;P]J .asս Eyu  *I2vl=IKo[+_g!R ]w!6^śy.^׹_~ELy:󿯕WWJlE:O:g AIsY\\J_gzƝ HEy9;jgSX݅#9I.ĿW~6b('y{%s9[JsoK4?+x<+vȥϷ>.ԿAf> Iw݅3:W_.r]`Yu=$h${g /(Ajx{Q*?d`$+?r).ԍo R15M\Hg1s$ߋ3nE0>{.#K%->% 9[ ~SoPX${! ^FORG\{9{ ;_YYݝ|I+\.X";j 0j'`w8,7y9[WpY6o$e.{8.w#G;j1Y^j0;bqVwݢ:K]e3\sjX.b&g I_E\4=@|}Frȥen#eZEc_*L\zXӍ{!u$%. ).n40{UMq4g 8J_la.&i+}(+vȥ vsOy9 'y QzOK /A땢.gi޺OI /Az^+SE]Nfuٵ3$/pAQӳY(,WY7#a]Nrw?'Z^/?X]vm {Ic.>X$y. o|'v}ˊu%rs/5 aϚӑҽb)zb >|%qPW>~*mNc+蛁"]9O3ǐwIw2#2qX=Jf?k>/[2_mo$y[tߝK{!ey8~N?:~0v^!?6wyQ[}Zwϭ>0Jv>}`f|Oʅr9XF[mi{rj ^9͝?Rln3c[Mr绐KY9ȍrx@s*&\c~򰟂YLk ݾ#eh흴q/Ͷ7 m.󟧿[,nulPA05[ߓv !p]AE~h\]{ngvX$;q! pv0b밑/jsqvXyɆvX/.smfx[ApkKv|7u4[ <"v?BT.>>8߅\:s' !h[i2ו +M1 14)ͻzY{<I|+26ǺgP5/#q*ϰ@A9 1h1xkw/s%DZs?g6B{ZOxFg9Pt&Rgڙ̢&o}vg+>vb9>O@>/+h[C=RcgPScg8;vdo2y:y>8MP}0YCs"`fڛlo8aBeߧy7E[;4ݣqsk@W k@}^Etku:%r_ zOD}I#ǐzc2w|ʸ |ɴMll"B.c)$׾dZ}@[?=?$\VХ h|qԛ;41>U Xͧ knmꕻ3ĵ}6vv>:=Itmן최Xb7v*{Co!nx›tm# wd]'u'}gɼrKv xo^? ',K}/qU?yPw< wgyPOB @_O@l7~R j?hܟ07@y)4!Hxg]IgK ܙ @rFym$~NHn!0cK9^_69)H}_/z1e?]ȥ{g:'9yk#qx]ᵧt wRo̳,]T-6DXEkjY[Z{Zz%Xd!;3]9NlӇ;MNdg uRtWi >wrkN ܩU_d˝ڏ vDw@^"wjbu(&gWj1?S2[y;^ΝRNo'3]O{/49N \6s=ƅ\j/_#F'i!b\k+M_J[{k gxƝ*GֻNo¬sNNYXWF / 4rP2yߛԤ%`~2j/g6*P,7\: MYnj|o9M}[^w4oU RQYsEﯭrߎr]ȥBp;+V op946aܦyqȺcM@q`Moq>ז:k}ҩ_H ]sb:)O0q;r9z lW2*q;%nw!e?#i.4xaΟS q?+Ejr)s\Vs&:{`7 n5{tZzr6qwt ~H)N񜑟`ߙ 0Jt5o^aGlc8_-{Wm >'?k)ڽ/(%0p%Ӱ`[g?hxGw0xo) rme~޸(1v@|zq\+]B?-xNl9{R3ʎkw!R֋}~YYaf:|Ⱥܸ_:/b7],oJm^R-%Nw[;c!?^{fjZ|6eY"C_kD6n=ݳ9;o]'[o\ծf^?|So}r?Rb7{K;,b.7^H)Nh.<=E\\9eI1,ܵqs7nd1wc9{Q=_L̽C0' d1V Uݼc1"bsE Of!k'[_}{ _Xn_OaFW[}Nq!frI|Jd9|cs֟~=)TZIc磺RxFqm#f'Y7w!YP#fRl.'j ~N8su/':iڀ; Xj|ԘBعsA=|XP'k8֡gןya 7򂱔L7yv;K-)x;"cT`r-KzԖ) Bҵw‘%h09h'~^K[fc銉cr/K'}=ʵy4xCY)bQ:4W"J`g1mxLH~W=C-?Gl5)Ƙy7|-U>rW+7F~jao 40o1_hb92 COb]+ݑr_#RMX@L+ ⹩4l{fνsJroe"[D|h'ei^XWA0c(۵Q3K 9=:,lmEcbbj_FUHb^Ef =BWt?~IvI$n?;K:Azn_[kD]Yv疡=eSs~;/wJb<.Z#ʷQaw$iL,Br˶?xij%;!ܓoi H:hu똛g%_!Ūyz>1rLs$\93xtw ῷLj`r܃Il"K~hHf5,3y Zr Xr#-bo:i9/!b:Y_9¿~C/߂A)izşډ5;)Vc;'k5,ՁG6-U^a/]LQ\ǧ-5Am/IAʗI!_ych,ÁuOy'kbwx+>/đ ZIV d{?z|I ް;rQƙ{Ǚ4Qƿs2Jyll"o6{47;O};*ˍ*eŲȀ&XpʿL9Ǟ_د;ƱHrhc PE.p9.ҹy?5(JW+Cf# Wx8ޒ%bXoHr'K[ze_>?g*s3Nj5sWIJcpn]s$j}P~{(c d3NY 3:}SݿSlȲ杚Y5}:g% ';ijN-"uO:y J?u7ƾCizl}fH|YQ0)5ϸireT fK.; lܩ.RLC]s-a[zVIl^.9})qH 6cQbL_+r͸ x<7LlurE,š"r9&Ѝ,!QrΣtΣ9EL"Rn$(k](Dob' g"vͣt6BҁKΣ{dG!P$v3vy1rw;iQ/6M;jEw RX>Yo_E>wz?eR~$7ϫ(A\-Fory&Qfϕ ̟9<-Ŀ_[Z x2{.uH㗗Sb=/VX#NŹQ>iJkifC,s  |㉎J'jgG#BlzMai$gD{âE fK7>?%;ΜCvYs@J,ΟaLZ8SؙD ˶Q#2 3x7ߎ$z3T\76*Ο7CtnϗFx9n+BzL~Nk' ^R͵YKIDM[w jds&97x1ڴ/5:#C(Y$#^lj霿'*e߫Ɖ0u:%ga+:ڸ-gIl->:f\t{w|_a. D*wesuhXvm,؅\I c OJM&X~ND\lݰ=y7g>g"* E|wcmϙ.|N@E;dSNDvx9?Y? .R7=s/gB_.kZH)NˤܗozL77c,6ʔJNZ>tZ$c?Ԫ'6,Au5/1>͘v>}fI,w{HJ__fMƶY~bp}JAy7){a;nf |Ru&qO6._IyyH$ՠ oٵ: -.5ՔҮ$_Bn<?>EeZ|xns,|hŎd.Fct gXaO/fz-_#rAv,7܅\@{Nb&.C x8̕]&qsayqayuhKqdh1|p;׏g!iO  Q+K`!'_~:@zj[}do眃siczzao3%b7hoNYy~Ӽ&Ҵ/Eؾ xHR]g;~cmx\".Nry ,e#*`` ѻ6?y!W4qx/^QA}t%G\G?N n}&6?s(0?]ϬA]:.f8{d]X̔Is=ꔻPNE]LQ${5ut4܅΀)?HWW= Q9SxNxNd]#kΎxdyV✻XluPE]xq.,wXF2x0.|js/q]('.&5 eo[s9]6,w1 JyvGrsj2s`wÿsr9Zϡgct30~W}:qRNAH0;3d i 嶳VB^sN|73<3\+tsغ = y>hMwñNj;rby1)6}^V92~(0Ξc9ͧV5Ypg7j ?/=;Sކ=#ߴV91mPS8mQaqݜk;rrs]9k{DXSdd5'̵}r{Ø#`Ef[ͯ8,51 _SSl9}y ?~Yt>,Hpg9x$ v?yuG7;KrI@Q{ $}<ϕq 4O2U&j#uK >Qn8b(/Bn[c#5mciLx0^r!WoUh u)믌AgD/5VpXQ\8j[B.]#c$VSV/iωXpÂ?Ƅg~N<gF#qpprRD2=/Fk^#'YC bӾcHIqt-kdg!s.7 nF-*:n1 OSWֳ aw2++O?/YO*/1% o9 SSh_RgZӺ=JlJeq{T?Z7fNߚDrAݞ[zaO׸d!>Vz2%Hs@W_!?sX,W!?ȍp[_؄?8yYź=-ٔYru{x?#ѨA)ITq?|h{W"$?`vRc#uV:hx?[?.&Fo{yRFRCxoaA^{Q=k;\v:E./LVv\ña/: 5Aؼ $oB*~{p!m(wzqhm!8u'⢽MQdbpD1n>EH`mަkмQZs;+[Ȏ]HYBܶ v D\Y61׽ܪsX̭+b^s!c]se1W.܀* Osuc8R$>Oc (WXmRmؽ5n Rޟ!⮒ Q ێ冻Kqyf.{:zdoUg"">_Hd}7˳x*|󱶈aۑE[{Ji3|H],r`.R=7qcm,[iS*1q>] | _/Zŵ}2sMA;XpC(RJ߭,;J5|O,L\H8"eי*{/?nXZPuAaa ,-(-lXP҂KӆK JS,]ڴaiA{<}^L?}}xy8}TUj[DU֙aK O4O3ϡPgB> LLxrM#ξ&wALT3i@}u ~ӲM?VgoD.YgB` `DE_V=C@ܪ΄ i֙e3΄י(2E:U{t?vC3{tS?o:UmXgZg⧓CיL>c 7:YԵ:m:tL֙j3'1E}JhjLp '׆^x_:ډ::_L<-L爐:/ <7c$eZ LNcs1ei 8bsS:^D6$k::W o2֙5יПLh0֙;4C%u&_whk1uM}3Hcm[$wTnԙx~Vgb-GF֙Pk\GLތru$Ekzu0<-*V SK|#A}~KxKӉ\gVcC=--x~UqH]&\cđL9~ J;gu_ HA.XM\l$w^Kˀom qsnm,40 㛏>Ʈ0M8UaamMS+m zWͿspqW?D?.;r`Y#yUϩ8eF3)VNԙ?s*4>ޤdI]m3:Zo#Ng71W95L^sʾEL99zl3u6M~9v^ū2WwK}ﹼ "b # ҫ Za{ю#[1sUusy|?L窽Ʊa(֢G˟M@t/Hs8ܳ!sp7`^Zo(f|uF[?u@`ezE=n?cjo7\'p bz5q}EN@m 觇);e^[AySbٌH_ M\M@{E4Dy `^lcA*b\(SacjfHkw/+]jnB0j2afzԨ gΈ-r\^6?YAu9FVCӧ1)&iM|ۭ.bP69L_l**:Y&yhsDgiq~5:EX0:H yS(fD(_E+B~b*SA׵׆`#ڿaL|g_;?u)ue.?jSl#ɿ&ʿ IB7>>j쟞ܧƵhqkdD=6o4J_M^7.7}""ڹ86v.3v.皆k5^˳tD#r++M'0EF)b酋, #2ek!k4AKIC^ |FH_O_ n? }'D?7p[qNM@Ե/x}iL^<3i5^m}vEqV8'>K?5 g4&W~ds$C??hüzfhS҆waN'm)m/0+hDlSLLwݾ(O[m\büt7S q?a>Ow}XDFC4͟0/pGGẃmlvl Si,ߺw6m ebf&YkF"#Ǒ~c3q[Pn ~Hds#Щ^k}EqݯY,.PA=R!;8Z;$Q)E֥\-;,礅_2?"7*$NqL]mן7I3YyS+CCW[_h &ku ,NVp;c-5mGnHi;I\a{;rߑL}l293b/VTr/:X N|_y$<,gSM 'M$3|c:s|uNg >{#%|OF؇:)l|Ĺ+~G9G}B>HvQ5e&N?R_Zu3[)/T٭O)-1.tj3-nZ ïn!bWR77Z2c}b\cmS%"SrC} l91ŋg+󎐳1"ky?y$y.I6p#cfW27MPq\g7[dI <}bW=%Kz~qo"mMnr6}_ۯ똺b;6~8ۋ`۫si#daKUN tHЧ+:N&o~CZY#2]&sj'_9t~i~_~_LP6q}u~~ģ~eW1FB!L-2aw8WU1#;\{iiZB}L6td>%^]t~߃>{otӡ0{oo;s:S [q؃G}g_7WRw oAmsP~E+pc%}FzK*c Ooo~߾ ~_o7N}F4}u}4w1Ȕb7I -HqB0H?L xO=׿0}]s {4M~_j~pNO s+{?u$}}mj{osW%Vo`3/בe6}{YM5}W~>~){Doc<΄QN$~8}'|sb`&fc_~<.}B,`]oYb%??}[}"~8a71bLE7o{~3.SV|O|zgUqH$kvo)o ;?~ߛwĆ~߅'ƠikSdŦ$.Eں7mla!"n"o" ̬6ᮞx 迖q8+ kO& pDŽ ~߹3eR9&>~~87}s\Cj>:jüc2uFG_=HI_ ,m(gih3GG M.zx,4~U-?(Q70zxr6{/i AsL7H'0k>'_o`fg6_{NĶR{eɥB)Kޝd[ʞ׏ZRa򩏏8@֋3姳丽gN?vW%m~ ?&X#. _3eM pU!"IE]/ߕ*d}Ad?X~wZc'|q'3%>=jS&kIkyЄ#ZN=<]e8:LŎx~Hmwߋsɿ]>۵=#93$ir?n'[3ʛa#L x4=_V?FiGx;8r2%B$4wz~U5*jy߾,4h1$>qF;QƈW[2D">@2(у" q%r3o[?4Y8W;,bUDŽ̖p~kH LkzgIr o_z3׿N3YO2cƙ]ֽC޴~ڴح/aV9 2tW-TYjpL"gؿ?돪8Wr;B^}b.™ϕK+#;k8v5S@/3)x^ޟTi[`Z|r&vo"Kb>s2هIWVqNBO+R@{{eb:=X`kv;їm@Ag\֙^ 4Zv%(e/=u!+=.3W&&p9ƥkRgFx]zW(9|#n#s@S ^E\DmxjU$s@w#S>j8LJuWdZAmq>9ܸkI9Cwte[/ERhws?ImՍ ]>^wdM9Lt7ؿcz33Ӹ/ǬnGz9Ž{?<ݦ oGo$8sC3qz/6JM9,p&([lgLb뻧ƈ`ŏx;>\7Px24~~&ӼjO*f<RpQP(Y$~2~Vׇ{^!kirŜZ$/,iM$wQᄏ< ?ǟpov_Td)^? mIDO>Wb}Z"k+\|Z?ܧE}:m!,)X_]M?Xl'OwC?}QwV}a>AlGf3O̓OSNVor̀p'=x~VN I:q+i[t:YdtSs$-nI0Ak/;2\J`H :xo7T+KzN+X!4?}f O$|R:8˻4\ %|󴾎ʄE&{Js!@'=CPgJܐ6hd*S'^w3Ax0c y#cPb]*ސ6JΥ_TEΥ2Jgn/eteGإŘ4{e=h)'eһS?ᘚFߙ 魜ԿeY̝=~3 m+n&Z|2r׿Czz"#2ۊVS~% 0&&9w.o:iˋtSfˉF<:flc/DYRet.wݧ糝C%TuIqJg{ *ANtshJG.'[2sQ]A;34]^rb.)FH;tiˏ15u.o/2r2˞.αV;yY*i.δY.7V]K|giJsA)Ct'?=f.տ~ty.S"tty˰z}z3>s6(k}zQ/ YF=˪kp^;3\ݲ!nz=2C%uB[Ɖ"4dD#_E2~ӹY.hGA+>n:`LJF[VS,ӤWN\-L`OOG΢ii#>̶2Ň{Os#j͚HT~Ӽ7UY,'ɸgz8 } >ݿG[[vN7#ŢM{a *#w֚8]#.>XOU097Kr}fʗ=j747+/mh;ܥQ)qHOOqtc20Y @#ao@gZ5G1)Y<ǫz->.+aK\l_ԟn y^`@?q3ULnGH3s7N{>q)'^Δ | uS1Ir!+W:=%YyEN5LWdQ|+e6x+xE]o;:>![ZC |tx>1un+C[B'v)1k;a rqx/ [O _|a`HAt;)3kyəf]lBm3q?5Z5 cOQ߂Y:g2X=Z>yӺ&W)LJs:n:${.9'o9p=H> E׈NJzu-SqHGj O&I/]GDQXA0@1FcM3W0ꍳ'goiXAȇŎ)}"Hm.FiyjZ4'rƮA;xC6' 9$*dϳ7uWJ[g:Y^ i7GEjsvtASog&BSW`&񯿜#h*2VIZ3%944Կ /J ZN-Z?N>N_!wE>&W290Me0ǵp|߹YNZtی9=r\M0gr/S&m 5X•Y<>v|Kmswj9܏6LܤMD뚆*:z1#$fup>ع'bPs?vZ``IͺoF_Y`k,R'X`r؃(7{z7rngh%C,um7Ӥ08 /<7 arx/#Bv]k!mys_m@!d'_vYYcW_=Z?q6C#e]=q(gh1ZH~Z/3N跺{Bӳ9ܸWiG_1%Z6mnp'>nDkZ}."]GXq%7bo26";o pm_pK_n6{nsN8C3?Ђp}54Dz#r'"=:vUNzODbd~iQZ> OŘLvnmIw9Oͳy7Jr6ÄK$d@p$iIOw2V >?i|| &M2 i(ݻZ[ zQ9迉Dk4thw{+&dzX6!oWjd7@bPq&/L΃"'䂵Z] NCg2B.1j8b>3cq dv &]#oy//O+*Iݴ#u=%A~+l\]zh/|7SS/]e7woBMR ]$7aW /]*L/qfwc"&ě=(翶1vgh;(d꥛?mxj6+$Mt~fy 4w(+<]k|#ͽX~ֽ榓ʹҜ܋nnH }C\lң+F, ?δZ9ΘVOhcBEZF1CӜ`$+͙ǹi}FAsH?Iԑh u~0Җ/?_b lźT:|߹ ̔ipD׀u7r]oD찚T+p7r(k^hI5=zQ_g?6dOX-6)c69kX:W^ԷE88?>g |ǦɏBF4.MpWd%'BE{3j]6TǷo]MqhcqH(s#ɿ*”熏} :ՊޙF|T1M}l.ۊ .G%EO vp%GK>fq׮ w1\ p<؛jF|H|\ˈ眰A}*وL4?=c%1C}$@cqa b[a#]>Ļ7NUT42Z^KQ:(p7Sy=z)%U=^>2Cj>,g`S'j_X{'棌B;;BhGϕzKi.?(lJ*>3wC݈'"[ BC`.05؜f5z* ^pF žy|O& z ? G/w ީ(eS{Նt:A<οcS2x jlru>"%s>ЩugjOp g_EȏR{3|בTfʹ(C(=X)jEG[>E"dӃGjT%/8G<,GA)*ꨁ]9BQ}@Wec:⺮ z@?>w r0aA}nw~YMB1(#E%%8FlO傣n%xgIB|Q<c\?fg?({L)F yǿEVťg6^5w͸8 {z5o#Sy m/6ò٣3RK~ڻs軤'FZMwƙqOڿ۵!ߵ&.SN 5Yߗ^s>opj<w%"63ӻ仝仝nݮn׌@-Įq9м(/ yOL\B ~Pii5h ]Vj?w:/'J46&ׯkysd+m{ʞKm=X*u={8Sy͎tsѓI)in[Y<5H>[1oesgjKp≯g,O,l?<|hL|!Lhڌ9Ŀ _H>[gO<Ĕ!"0b ϯ]>f@+8U ̘Y!=C泹O a|+X!- Ndp^WWZyŢL6<>n&V^Y`t3WhDc!)vYyyHd>(coBP/o f t;->>UtJ׮P{k`f Tژ֓VПR[k?^Z{ &.-6}nw3ƨ>ʔm{tLo]ga*G1}}HOɹo tSfUg|7!Xm{J9W?_)ߜm7_,mA 0΂nCjQU{P#R.bWӑF5k4hI|po`b hZݖ[%l))_c`xf=:B=Mמ`LF*#OF$zŸcBm(ѾF|/Octf?iA|GB:?W ?A4tݦ$c|RdΧh*>1J='{d^? 9O$_#KyfikKG?:HNL6~6>g#/Q ҄- 䧨T)'&nkIMf[UN ~A}M9~z}HE7HW  k$Yy}9/ڔ_uoR5۪հ|/Glʩm0 rݷF$u[/pvh戨Fn jU!֍q$bR)'د{Ɨ'ź>5\g@=6[DVr=_IF`n3N z뺭nS\;}GAW2("b܅|x݄0yVvao.䶯AOJɽO\Mw,<wY3m<3a"a۞\xhwnpwNӻn]S]KMvZMhsGsiM|= .2[p؝ky;bw^HEHӻ+9؝Y n!bc%'=6Ɏo8!=d2f8ս|h哙dG3;| {!ֿdZA H텼6 xL!f=Meg2g,W0hK7!`'C~/G焀r(}ÏsRM<(S6g!u)(w?D 6i]e%M>Y1,}>Y.c>YO;Ql9c=SO-i7I?M\$\#;?2N㛶PK1gPqF7O󿿊)w|`6viqhoq;k'|97l4JshY,ޞ6BN_GҜ\i/\kHiQ|6S$LҜ6Bsy ˦C.5D Msv)'4gg25`S7쥅 [Is>`{OaW&i(53ұOwtI>?Ld1͟N(c}֝DX@| i?co$|B?0R&s&H3:pLD4l~[K=sY!SI3c%3O-b /7K8؈{?h-҈!oQ7Tpq)8>n*d}-g2^ơ&m6$bv} /]0d #Z=L9ӥ05L)\kq;,-cv2>kAv~mwjeLٹ-#Ӟ s^OoK:1@7炱G?j^- w$1)wwq`# ΃GWw8wX.<]O)@O| t\Ã'y@ ]oW2^%╇mR'xЃG$F So3zbwl#[,7)N-8;h?a׬Έ%wxF.75#4fFCkƮh/*5y*{2"Os9\N)ʗX=M)pݹ){i?kOX5Mڜ;pCE6p]=8#D.z|o8wZ|~dvs΢?,Gkm|&Հ/g=IaOY\5yR+mb =Iӱ+)MJ|a +]HL`ʇ9Lrns6N_2Ӄ|-U;Jւw/Z<>5Y*nG[-V$֯+R!l)NіrHb)3{^^RcP{]R]mF|5g/X%H@2́܀by|*ey3.1i &*W&˔'ƠLyAח zeV>289 \.SC}p|\~ZHh8ZU{h`+sWO}#K}s-J*nܸHwoaJS4e9_n!'go|RN{Ef$mo&넻XS9"b[O\Q%}:SFlϣn_)_DIap~BrL_F;n/1T#m9b~7cp/{yGi+;KŞ=Iz:rGGo 1/<MLr4|u*?gˈӆOD}8ש{m8?罎\J(|4_s-ކ:|m&9-J9's*ʤܿZ$=Fwva<]=F##@5T.q}Z}l4q։y܆Oh,m%y/v%v;kR 2.Ϲ6fΓQ9`JJ7ck}e+9)N=GdwR{׮N 4)u`ћv>2S>\fqLvV˚p1UmwKy[a\E? '1|IϼIe>3IS>0_`Ld26$c/[FIVvԿg[7eWab'Y1!l ״W¤B>!`}SE``퓬l/̰N!S G*>ɮ&=ֿ!/v`dgϔ=u佽#hA (?uVp;-:_=%O3hnSIQLy{kaFڻP6~b3hp$ܴL.݅DtNh;C}]<{ k]z޶\}ggNH;|qS5|૦wOɒ"n粑n+|1c ..Q2{\S_X_zO5 pG{S?4tȈI /cJnSHC23RSitHg'q^aNdꙻvuvų=Qj%Y~[qlm4p~n<4z5׉pܤp=ds''BBGV0e>yC,0ET֯zv|\؛?B92Sr_ ^Rºd](G61Es[{lɇ+&{ɢ_閭q @)z\O_E# 7[XgQ_M%f֯\o«{F”f]#r/xi@5InsoDuE-Ÿ י56s!kg5v<}al/FCy7.3p9cWoan$No֞ l$S"N쳵78Z5fG&kƿGk2.FeK]x 2aH`:sj=ns 7OGR I(| :G;2G&Ik+=~)d=bܿtM'ƿٿH׸PdNټ)|#"I>O7c-mo8eQ.$}zgIS uѸ3K% e3lُJ`O4: nsCrt,rN?"Uao-ѓDKWKEua&hq2f_߈6WQ~28yVz!Wk_yAc{FIzgMNia.+F mlKc[N"58-fX~Mr$s{b)vwwz<ew.o"LӰwNMV鍎Rsew8=<{>wEVx?_+ދܱ1 s8lmQ xҰ 9a'S^9A9Ys|K0sQq [_ 0w/ݿp=)i]V gsϑ3T! ~]XOzX|cJICZp'!=\iñ Z+o^(Jd/IDĎ4v.xu%=RKLYw@q}de&hij~`?oY+mQ8YjqYciYc&oy=h(/muT;2 ߧ1eBc)aZr{95.xcj IWktJW/Ej ewt%tiaK!"&?BUAW?*jdJWq]HW/[7tus"t0tuT9}q/j&(s8M!xJ5 :O⧀^j "ߩ? A=^_[Apn8?E䟝8G>?Sy,x/iu> 8/~Ǖ w9|τYeGu=O9}SƏ1"Η^ӊJZ:#_\gICuq~V`{׈*+}F:ȔVojV_7/xFI7?786 '~[7Z|aOM-Di!qc#}z+4B\{Jhwo4|'{X6o^[ jnz6$3x.kGb!"(&pgkW rwo8S =G5:7;}Ar@:ڊQF| e*qCK17.q׷s>fTA;#>'V3FA7 gO35:S8+(V5RO8<? vl&Tr&!jaG lbjs+βSxHyI.A'gځNNKiB'=`g~|S5f9I_!{>Wg$ioD%?L݋ӭ'ގz 4!%tpwJ?>Mjo3Zka 8w_NeHaZxG*"hGHMixDB]1'z=fS^ܛ> iCɔ cw5Lyg36_8|6yv{{4328qWHi2>v}MK3Z  ]{ފ<;9\ cF܆xq/r16#w܆xyʛ16d1"#!x+[6`\Kd܆;r/6FY)Vu6,~MPyq K{2'%Z"aS\=}qsZH=O*|Lqfp}5qf)g-ʿ8Zg3ֵV.7cՑ~[H%qyN*3ƪd*/8͸0eIYƪ<`\>eim2V%z8yUsUY&|? o^|kǗ^|Kםrn{(N fR)1!{J{[:=9׮dz" ObN{n&8s1D~ט Zh1p BH[DȜ[#gPZqքm(xptVHTIg}f1eb{Y~o"}:k]-/qƊY)G,( qVH v)3߭e+-ghHfW9KY2Y1Zۋ!c xa58?t4~vA)O3Da@b,8}[12H}赭jd>E-9K'IYFrQ=-Σf格GMHYJ3,}ӂzCޣ,m ΜsB҉ <KHh3X1ץYV::~br-o ߹=0ˀT|۠'Ås>hՁ'Q̾S./:M}Ӥ\|-wq nD\|aLrqZ,з\yk3r{'SӦ8]B6+DD-rm=^w&s=4״:O9:$x[P/M : }0~s;x &%"Ⱦ5 BJdpZU4|ݞ0xtG$¼OcM)xצϔjyu71/tgBǞHgʜ\/싴p.p{CE\5wn6p8+/1cLUucbL k(kM$fjwX#$z.2%e>\e"FX%&\ e Q_>@!+ \'!nCrӋ'6?KLkA.iFIuwwLY<9Mjjhp\ yқD_ܗ6}g}qh A@lMnm[ϊF|b#Vdsl"Z%fSr?}|Ah|`#ǎ0,+>,_}}gu&bAϡXC:J5yz1wŞU.ӟӯ}_qlr.\x 7w'gx%=VǢ6I"w'&)ӃɻԳ)$b eQ>6^0<_` Gz>i"FB~FMj1H|q~|Ü7Ug͆s$} E3>;|4z3 by5>3.g k^Y|1x0՝3ꆻ9X;b=NG'ɱ #C }o)LrGEYe3hZꦥ&P`hW‚7j-nBI+&nAieiiAν$wo+'[` ~` |4J8= `H]c-A`w_#hM+x lAo BMfcm:$a}&_/X+-}߯?m`GJصmeS)h?~Z(ڧM:%唗*۪Wԕ޿=yKy{Nsyo_y{UK9j!)ww颲şyX p eǤf@`.r 2 ~ ~ ~ ~/W:5/mQsT(}^/ȸ< 'r㽷cM8+ųrΗ>*u{ ПgPSSz*$Е[)+kHV=U=K3>WS'5`>^ᭉr ޭg!&>G#k ->Ԫf-0⿷3τVZ,0⥆WօkA\SVԂztYo/V7Jw.|y6?9)8ݓ'#{ykt'3JwqHnjtw${~n}WmWZnWdT}):d{ωt8y\B3t4N/!:EBuZ& ^;9N>Q}W8|{"+aݥ|Hv~r8ybΎ]d-\_W_LU5&l'ׅ f6bAb?S<%_l`DsK\{gG=Dܫ%j?;"ϋ^cws817栋ikniq3?^V |'5'sqNg#̓y L^'*D8qGquXq_늑pn; pFc1SjSIଅ_hA8G 2g~k$©@8.`d"g8wפcCRwY?y ݠ6 '!h Mr*|Lvyx=Sc7F,uzN֛Í1ju'7:s;k r>{6Z1 s s9q^#qFs?QA慶Jr=g/,OVx#Ϋҟzy[k B;G% ˝x='ya~uxq^uSr^r^#,s)<A6ej^S⼆旄1덽s9[㼰FZxW B2Rx 6?aEy%q^X5Dm慶HB%'a/n{3fpϵOg.b\xz*wq9[#}Hqg? <Ǣ8|D<@ؓi=I^~,zsy#?Du9 lMOPե> m>^o=㻟ph6G3l]~LVw{u7;U8X~wyTQw3K9,k įPoB_1N~땞0꿢ʷi?AMO ʷ/3]D2xNǝ>ϡ+mΗo&[uj_#?IE\,!o S3&/+g1\k‹5]$u8d.g(jdRk}+&H?CMS[)tz{»\;ĸ*гyUl^ЫnOܛ{Mys'e0n&$EuE3:TCT >h=1Êݹ[nuקʉz{߸ :S͞);bݪKg2(cĄ9x*>z\i3aftIr/]=SWy$G\5?yFU޿H_E~8LCěιg .sD{X>`: kgyF?ᅺ nK;ӨΔd+Rr(kE<ޙgKEohtK3]NL۽브OZOoyc!=A39`N%oS¼LC]xF6eoK %O'aľg|~GhlWi$/A%&\?<=ԞFGTykK1?ی,yH#xQyɸ?l^"icy]9#]^RhA;t-Py63<&ޕ&h(6m;&`n 8hsM!e/[b3 >0&F<- 2QwO. q?7.s yF>魹"R82ygHKf-(nY~#6rNsO{_ugn}1\f'I: jԫZia+㯯; Ź9#$kK{ɻoNwȻK{&xweytȳ?9"oլr;.-|+=>/o_YXc#m&Joyyn7)9[`:C7<wEoP9Ã8 P5/`ؚмG'u.;>C &/0 `D':<_L!_p6`27\LC2w'dvn<_qߥ?"7¾\ѯ;]( }Bu:'ݦ` y>~~xόVGfɥa*$Z ^_pyVU{P @z'N IMOk@rg|Kw kNhy»Kl[7| _pĢv_hukk[cC[5[-zP]7L][W=F{ m؋b{[֑wQy;w^;ᝓjr0̅ӳtqf~.e[,e*c7۵ f/:"7{l7'r6pcrv%7g.Ek#+:&֙bG&gH:Y?yv$ܜGt@W;W?0mt3<6!LInopc+36)8`} vL#$"7v_ x vqgzW˱u/Wd:ؗ?ʳM.1+C6=Ka7 riJnxV> Om .7k{r_romz~f9fx)%^n,3B|U%1Ho60π p +幨*O-z|I0NCȁV*O knt~G?nG~_$8sNC_$+_'~5/Ww$=U,gB[nU1SuwA"-U W|E0qqWI/B#|n3 _ 4l1Se.3LכIv6Զ>5Dߒ֤MY샗'_@O TRsQv;y_ pFj8?qfEsbQ#?sM<ȋp Vp'nƒldK=z[sX~\z~q&τj;ǁkόƞy5I|?+~z}4̈I;njG%Rm6498~zK,k5N ㌷2x3 ~<~zK<! :1WG2O/s X&;QqNTs_P7D_C/a6={gj[))p/ј,cEc'VڟdL1?jp扤9OWz$׈H%^@Vy:E? _oo߹@ü5dH:{EK;1x2H'C1/S{o;8O7sNC?cGX9^ZY1E}C2֌Em,솴Tx^&Dɘd贘b0a3-&=yoMH3M<;RΉup42F/<},A=8Y$7nUG M#YD%]/a~#z3w/Q'H*bxIYtfw.nG4#>DZݺoT'z.dz8N/oq҈C@|x)aϛ1~BD O(,O(lV0O5aڲOHL-/kEY4XcÆ ]9x"8$g9AuT%3% yLC eO }`-l#ݍ!˝D?6ˡ@咧?i&c=Z5N&Nh?d<3. n4/%8}?G;8}@Gr?δ^W͓S,zsQc ;^Kbߵ6g*C</~ohp緑>7p \?\m$Y[sua'8He6ObSlp2?],)`'8$2sh)GPt}?[ڜ44/cu32/QX^#=5igh+FH#/Wh:%~'.DtJ_{c;u*o{=NC_{O2 ?'.NtJ_{w'dž/9ο?z[Uc:?8̃}:\^cC'xr~3KOC(E<1gq^ U]|uUv$s) .x.F_݄DKja%\uɵ/S5`θIL;UMh_5\^-d~6q{˚,×"xQ>|sB2TtY zJ0ELn!=l!u Il=bth6ͷi߬#kCA)fEimwp";/w;\4A'9=>Cʠ;;I[6):@M|}_0l 'l__'_c>NNZtAj{r!֣zi#KOGGpjJ<]^xs-<*ޗZy/羔cKJx6bRT3՗觉siz?^-> ùOƹ̵֪Y Bu*7+-F&D6y<[IiQ0NCa#*u~av2Ż&vƿ2D,8EX(☤gVsYd=59\ݘ#CERfz)GW~k~G3фỴwz@{%L;^OX5"0 $Kv(l9Ŷfv&Ɍ+/WO;y U+^;Sz9sy ?0 )1xs‡x(;S'q' >ݗc׾WS#MX3HHƐ>wau]̴̜׍齝 M8Cs{TJ 9}3jib@ 4XgR'!/o|?ؗtuUƿ,dHrLw| 5&0װ(R2ѿ,ýp)w9|ZjlkAkGh_3lI_/ւR.=d/ o ҰJJKIF_, ܟ<ϵn2ˁgiǙoV;d:rWUh>@S0f#W1y3q8cEo!gJhalN1K\6 %wowd p[Kae0o?gƙ@hv|V2] i_ 1Qv\6obǣML}iw>>? oF[2 qHs[^G&oPmZeeƴEѮlU1j=?R-ͦ^pzN2zHKXi=vP{ [cՖi\F2u2Y R5#a=Mk!nF[JBl)s'm)YKp[g Zwl)ܽ9̬d}es׿`sȶsA]ƃn0&FWu*A;8)fs2i~Կt`׈k9zju/ 0ǖU*@{k^&Mә5g G혩tr &e{_$ߔ/iO'V? -syz2?k@rsT#zg)!O:k`#.mmc&|`1B߇9/A󱇃FC853I>?&9glO0l+tw b#[!U՗twg/kѦu&?Ol& %,ʉS{ *$)WW8hl6\_!ɴZiHq};k"\%܇jw~LӾ L2G>tWp=ܳ*kljibG҄h›綞mj=G+GLɴl120E補@y tӫc1?{:+t9eyx)k#EUz:,e1ToRB_;lξ=_bcxkjKYj?J =No?qu (y_sGJ>2W"vFln7ie9aC.$p+|~;\"sk0b^g)mI4]9xLGm73R/vΈ(f"Ӷ-88X±lnnDŽ߿H /  C\,y0tiN1 y%d_% M={38 ɞ ,nٸi+|HlAΞ F|{!#uӐt{ЭnGgAxcn $eMa6LT;ky¹lyN'=>yJ-vu~1zlI5yLZk]uTvg] nq~ Sk_GqMwaږ5qM=5-1IW<1 {s^ b)k|u ?ckqc܂pm俎T|)| Od."dc[׵ ?0gsY w9LK~;o˜ɴ+IX^u3c/a p {|Sz=Wkks;z|FP )Lܠ识i}"˜3lZDVC_To.l3ޝпAdywR4yw(Mzml;»3M璦Xށeޑv$<35.͸@y);}\Oq_s؀&m8Q,eOJ=F-p/zs&>o[}?iAZO}t,m؉NW</'3n9i 狅&>1'"ߜi;m=;ҡzWsqXMSgwb$kzW\p,xu!sIPݽA;:cG;Q< BH<72濡ii75}CO9L?=0dI>[Sn|^@xp9|FܹOවN>xF/Kq9N/7jrδX Hw>HCckM7^]@-z;^w>`(|tґYoJʪ#C@7K>k:󤎴 93&>?HyЏF`;61)eI^EZrקD^1\|q{ ֨j;)|k3Il_;S{{*Yy^79mmF} Ԏ4t?p-}{eǘuFc? $ܗ1KVO%a<b>I|{\2)> 1Ӽ_ӗN$| 5z^W*[ôFPpfP)̽ZS^~[q5P8߰>}h3cs_3_&@E;^o=En/b53z/Dj'p^ {'pcMDr9X޺:kxM0^BEj70_O!6˖3(vo~7;k6|g7ڟEn/{4-{heLp`^!^v]g7t`I9f#yo>Ӄ~^&dҠ'd-9!kqhzbl@7hF3mBgA"b=m3p#<p{:3E: Wvk2ҙ'zƨ{RumʠHuO%u={W3gwOd(ٸY:1M#u'jj'fm3;w+y>t a/i]փfֶj;c;mċp֜ .:m|Lo2C/m(9k}qZ8˵W8q8V9Š8?NxIv;QDž:&~Q?\~2g7.}Tkv19kbQоFYj o3sDwjxE9hgǧN<*;e f)ȝX(n3^מ.>8>\e/|\~qY!>[{qϮ?1c%PxV͕]v\wz)Z_6Ú?Q\m\~ѴBbGlWJLxwM$}|}}{n=cvާ3^/dPX-N!ΏSMgW?fr4iGo LiNOF{E^7!qڜ,-̲?K,7ML;l=KER[:K;Yyk7Oo|-]Z F螬x9FxwXx;7)>c7;o|ƾW=l2`W[yc5ƈ7.7 Vh#o|.>8oli $W/G>g{Չs㍻捣|I+oLp)quy%Ԡx:__-OׯBƛw7i'bVRuz>ʟ mTW)YB47]/T;Nڌ]VSoG:E~{>ۉ#jч^_-F|"`=F76h[.&\_LqD92y܋cjwGM2KpN=;+|FElC%mpȺx~vpBo.xA)U8bnX xR߱X)|1Q>jh_}wU^[\ZT5EWa3jehseiJ3.VwN)ujE3,1Sp7o啄Rq _Ǵi~5~6(D|Qr3ȡ7Mf"~ 7S12&CyɺתӎǍ8g;3wQnk}`oRA9q:>%Ou< Vy;́tk$s俅?~?0n4ڀ5~}p2t'QO֓j]O[jZG[>ǧ䠶UT; 8n͸@+S"w?9:~"{vǍ%"/|2 _{}iWuQ|eCqZ{xG?.7 pp= I 4ܾơO9N5?+'Yw QOk^뀏?0cpӪ[-_Z;h2"\k70`OLji~p|p̪hq[a?(|?E9ᮨ2.ҌB䄟*ⵅx!n/o@kS%XrlÁ5C(K,{? L+)g>V2TW8'ߚ_So觤Oi;zDn97V\?o$wh_p~k1GM;g833-u"^y',usR ]s7GsDe?@1'~^Қ8wOץ<;|ԩ^W)Tu\3xo~wYw@<_/_reFóMsag3(>DRQih#b玐sKK΁ggW_HlW{fFoUm?=ڏh_4ZV뚖1'^iuqM_;6\ޖrMKWz6~`!_F;XΓw:6RҶN6yׁ:.+HE_VG^I@2ek)ioI{c=00L[J_J%~V00;濸W(]Pz ^w!"o.w:xʗ+ )*.iw*Vw Q΍Uw֬ΊhEԙȒ̽d*sx]DO6"Ƨ8RDw %3 }"Q<ȓhBr aHxuhZnLN@shx_s"z%uʻ-s`pnKg9" kX,I ?_My\ds=i/ }.>#ok  v$7h_ c|<7R}r!==2y\h3/׿H[zn/a>8ypnsf ߜ&ԢQcU" M:F2v+4iS|,t$8^}޴3<k!/6r]s^<yl89pιgKOEd0FL|@lK:~ȶa9!JKn}/ӤL1F*s'*C;6mk}ϱgv]@_`u5iOʦ>7= d>65Eܴ<.gD.-=wS"kq5?[}χEO[e !Ubl%o[4Sp{$x׫zA /V.#|NɆ%=5Gt?<~^C?+?>菙 7EZƽ&e i|,8|WTn$cᨽQϥ1"p.9a98=\Ok7 {yy^"c]^g$y6Ozꟿ _\9XO%jy]Y~ם'oxp+MF?)5(M*DB_K2mhGq#VcÈ2uu;. }\a#>)k8vY!qBc?{=-Oο=7\}BWa{8PD2(3*{qă&|)Oo^XBWRHoj=M1k)=)Jڨ {"l cH{3鉡czG{Z½ߧ]d/_CW\lj8R|^vùL_ىq5l"=2EDܑd/}->> vxieCkune2F%rYC#iͻ6 Xdg{`,jX wQm9-RV-{4l<]w_<+@Ud6[{ag5,ѿpzvUHN< o? MMR Wٵ57痗oOˏZib2m^&^1j[iB R½x3JZii] zvsן_x2\c9+uJ/ki;H&~^ȴ'΍&\fOZidim]67JKL~+M& ϜVE?gW !i"HKVL+ZlҶO&~^GZgi"ٞ&DhٍƵ]x fSyccmLhX/dJ~HH)n@Jbg_x`E?Iֽim_,2ֿ>$/,/& &MxҚm Dj+M2ȿ]VXd}@?D1x|ԔJ}czIK[):z|ư y1uA?OWi:(9lԧ?qvbtix"0]2E"ot&_y7 ncII[[uJu:ey xwN!AwX_oU}O14| &} n:7uhqv@ҝ? ~nfؿtKyz ebZ/'}Nܞ=VoizsTNC c%-||c Ӄ>>Yq\~Fc䜜o%:p?0 8h(O8/:3\%Fhdi] _Șe%UٷB/'}Hc>tZGCIwgQ߂ܫwOSZdHM z ȻvZy@_e/S>;ܢdDzk[ȴikȚQ{ٸFiDӚ}>Kǰ*`^5+\F˽{,]f-kݻG c6Owlw3ji;oػ?d;qr> w>uB?A*ƽd\O&iϠ/<[1 _X_4˸ %fUiS7|?<ζ2v|a}3X7~)b,wxºI IXOaÞp-}=hMus:- AbQ=$P@ޣ35wMXgR'Ɖ&DQߎkz puM;=G&y^6YY[e,E9w&~t.VaM> u¸ƨ?>hjڮ3"NnGcn1"i m;_o.8p(Y:&T-uY~ ʠJ#w1Mdɽ iomDu˴)gų?=/9Xhֶ}9Cc)6;Iz9#m# @gȜ;eb9@7/9YZ+\<_gn)0[s[rVPIKqshyuz o ȐByIk,5v8\Sɿ?[K'Nz=LJLnQozނ4&0ᩛH#_x Ju._ ɛ>ob>7Ѧ{(矩t4.'=`QrCo&4-!&-z|y ٭/Luĕܖ0WLi:Wt^x֑?a:W"UJ=.䙚|Lyՙ| 'ԙ(m75x0ݹ?O%-t([x;[db6}`P3j^ZCeIk ~l @Sq6\excustc619~ߏVLq[83CKcjSeL{3-J\M3ڬ&s0ΊX7u ܾ7%\U$g%g<8[siIkL߉qHe"O&ܒ pW%qYc8C:arF¦ GiQ1a=gD~p?]0Jǎ3큨t1kKʬtǖ0 5R}6wc)/x|Q=aqP 3飖P0v aEJqRN$W~_OG7g(h }L?Ez>Jp3? pdž>&^NeڽC*"珵 p>_ޭa:zb~|'Ғ7Kқ#*+u6֟K?X針:kswDyQC\ܦzFr[NUpX~.'}%D8|=r?rzL/k̓uNu>71ttܧt'Ӳ,9mҊ|x џ7oyqi)L+jay=LN/g;3xc@Og,xpd冚VuF0eߡ TZ >>:Pݭ/&G=>0]j#>F>fWT];Y _*=1Ls: b9!Vu|Eg);GZw1=x?$/$>St5uIT̑=*.B#PEKL56DOb\hȁuY ^G!UxV%}}Px~z]>c^3gz{|m=eZ16ysC J;K d!u\ʹ,I&Y\b/~|ǀʸsCL֣?8qcڝӭ+3g9xq7waFw@|mI$e$T[B֗*Z*I)Da^c=:ݾz.o]6CpI7;$8-yR]<_RH$Gu0XG*'yNXҁah\ {ǫEN7Q| ]) ?=w^|`$~gL.!WvhPC;Gb<܇Dj~FSkΌqmE Y:-i~o_ cE[&OFU*>kS/5vs*LpZ*{טSYfE2Na4H|  ?m 1j%HĢ/aGM66\:WkQlcNcuV*~ gZ:͐{vq^$ExWdOy[ߚ)jIՈV8A9Lrnf׈QQ 7H׶6rh4\ݔ]aiˑ1B &1{k_+?.uZA-RvO:%u1SpϹm3>O 2/C@!ΒgF٬׈xcꞒlޑػvNy}QXS3φD7ԟtv5y:Vmv)_iDڂ5?oltѓ1^,  }1YiJBS6%ܳxq&:NE/pcQ~Xб?IǍ+5W t\5i478$w9 64C\k0ɷS#qk-Gfcl~\!e_mS2x;b;0EdPfˆ?O^G5'DOMm/6GWvJZK6J\g!Bwp%>FR4oR,9$FKם; Xh^2Es`O_aZ ]' HC V؋0GDQE]#^Rv~sܤ:a&v6Z3-yuw sдV*@=ts\]3 gZORq=ۓvKu=L5KݴaWJy8K:yTkh^5nk07?M?dݬkLIJIe0?δ5aG%1oJ:?sT+i[ThGqÊag5_h7pغƱk|?ًΎoޔ3z֎4֎墿C'阏{#soDp݌>זDyne{v^P|sw7OG ?mmO3MIݥ< cHg/3>NQX+_:&^O'wa~{edZdާx⼁jx݌{_1ź,U{Xƽh {^7SvydZ޿?g}3އqV|2>o>4z0\=kpL%/ܰL %Gύg]O'c/fZ?7?M"cB ×_|YZ|yּ Gb7j!f|yySw)EźQs˵p6WB俻_'zPv4H7LeӤ;"\5.7QVꇋlbl0'Ʌ/lO'R?H'C'Ӯ7u4Ew =.)#kk*$krԘ´&YהjE2IroLs/!XU'N ӆo5(&;?:yv |DOk]L\k\%Lیk-"&Z8k홊OdzKRW|6֜b_.SkSgϕ?*e+ Y;Yy9B8y~.D5ukzX_}KEϸGϨ5v40- l1ғ)VZ:3EҦhEKW 7ҸI.O2鞛"ii`}pZk%6R7⧸JK  ky*9\i㊖JZ]ù zn?[ѕU q٬q=$}y[ѕJaI[kt`so0ߑj>!|KW,st ;GtcQɴ&+}]ǸSHs ʖrk-\6"ǥ>b23yynt8\^w21e73ǭaV7N=k^3&=k ?ug7q 2\0j|c|d|Kmޚ7va%t:NeہX,>RZRRZZXRi$^Xحaaaaiaiii?-;,)(NJ/NKKMJKKL KMJKMKK <> )x_gwf;;;3;sFgӜLߎ׺)<]`Ew SZG".r&(7Y;Qbv2S*xC|}wD~gd5p^J.O?S]莠tB<_ATc{s`IoSg4ݠ?zr|Ѽf0Fkm$(ubU_ ~}nq'`-=1wm ɘ{m;M%!<=|!ǮUrâtO"O[vK?$f3y ]-wҵ$⼽pYʞ)"TJ?OA?)l1e.s v9; Veu|?Y}=~St}r(>ݎ'f?+?ٺcQ 36'? /@cog~ulkOg +\ w!-?GXA`X<{8L quWYh{f@}ssdԣžs;5P՞tN5Lj{C:v-޲Ow},z/ӵqd>Y%]VRQ/tggz7a^w,[BnQs]|]3 F,2Xof7̅:ؽ:~.pudx 8bjHHB:~nW*x ^?ilʲ׃ջ p^OQ jٛ_ܝݼVFb^|C.`sZ[0jƼ)t  %'qC(4F˷㟃yNO"եqwmI>{GY4bK` qEYC8_L"M@:!cbŞLXHkc(m3e0/1p ,tNGx>J渏ϻS%]oBMmC {wd9C!!a!ޛf1.K"o^fwU tUkj?ú:IELl_YDyHxf=.1p5Ӽ mpt>1#&{ T{-;StμnP!ZOubv~_fCmGd b>v m|$ek9^{mXuGZ|/E(ŸK"lN?COyMdd-;/7,je U~ 7v׫WĨνvO4:x{mj.fc,hj3W(;kmXj4ƅY ؾƶgpYD̆!D8x;E75nLf,=fopA7Ogc2llzn;\]-tA\};RaA2Y4*pJoNQ@%)c@.0sײɨ>ѫ~ bv۬(G mm~#bןt ʗuAR ` BU ]Ӽ.y]Pz-]@@ˎF:,8Yon Nh Ϡ?';DtO*+KY?NZ_ּNB#~q E:!L/އ25ot{꣚ bW+Tgz&QsVH̺T;v N82넌h:;+f߿w}wO/($]Yokh?{ԛJ/hϩk {xm[h^/ǃtLi+ҩPC-[^:{oVO/e|MV:|Egѻ&ˊyYO{; ʀs%Eh}o |{kY>o{ &s==F;8 }ާ2fNwy&|&c&X[s&=!7Pٔw !o^x8)e~?}nyrôo&e.>vļxP=ϊ 9ө]yҎ{Y[#tiDT#݇Js7e{~F)L/Tѿv &)kɱ_3{_ߓGֻ?#FiԴ1]֕xNYG̸be9yytʍcG?ĕP TG{7hC#,K`6P3<PyMFp~'GdݑtIF$zEӧ(݄t6޿F6H0 13c7?nF"83Ak8fXHeX`>d?ùu|_w'Kyy}UISs~9@/cnw_KϻՖj5Swa;=/BGEBsz&^v)uo@s99ƽK\;C}Z0wDvKw4F,9\*3QyyzV}i.7g&e^=pJ=1i 2?}O~*@ >#hqWahQ? ߎٵ-.8l>?QLCE bQ#P19jn%nn幍ψ]{"m_Eb!}J1NJMF4Q9A^!7wB'+h? ls.7m}z7U2~;m%c:&~UhRv|[Ě}S㫺z3~},u@sM akPgnp~Ԩ"B72d6l{p6Lh~#S8~kcd's4vkf1|z:6Fymb\ǰ12~5(ݞ:~O*u.{nqO.eͯ*UU2~3B:+[_88~tݗ.wܘ7_1qB)ƞb59s c~#G8wl 17?+MtK;v ;Fo.Z߆8]exgrfF;w{_/;wMˉ7,Yؿ_*CؿQwbS w{[E|.b~`>_#;ڿ{_uWw{b{hD7]=Kjn/Âؿ=ٌ6'8~O&K~?SwYj -el; }0*ηw&٫kl_M]} \Dwf}w8>xlk}k`W7#2y|F?Li~ܷy|T|C x~sg<}JSwlluxTɱ}0M>_o2.AoΰF}a'ua/&5g>b x3*;fjd j5e>`ˮsk~?oĎD"bO.쉋]%IDߊC7 K6#&ӿe37& phGͮH01ћ zAXg"ㅃ"7PXZo] Lݛ{%}w Fw-N<݋GGu3+=~c ߩ oO91p_xRD]ԛ1na.$w|[|0gq.EA>-U=t9~N^XQe[pm]^ڡ^_/ ظWtz}fE.@Ecz}F.mC냜%wLhz}v[z^_^a!ANE_KOpڧ.OۏoV7#]rHJwf @t{+rE(JPB^{G/떽/qþ Wپ" `ueڀ ,]2ݽ:#utgnV5.u(FAx\)eH_gv&oǝ' E;]ȕq;ޢ'Vws+B{R{CٖySہ2?CyOZOwŌf竑:?2d~:_}j/mV [)]]2~Tb=|۩g 2?1;ƿy.O >)iV&eO'?W?P㟐\x9[fsJOrmhOb~i cB6I^^MO 9+EmRn9[(?.J)Dklt&IYT:5L5Zyty$fR]*qhzF]FC(]ߟ*qhQg{mc5zQ&oٿ_.ˉF8U?hc?F'qzs_x>z,9c1 n0XF} >ɳY5l fdop7j50]rv }J[؏G=ʛ?w mX]kg0 A֯ _ۢ\gtC&ItRopk +;>N;[6'?[soGZ_C5>ϡo(7"!Jپ5o_}ޡ*(tg=_:,8I͏{!m9/m^ uu9X]{?L<|nLu_G7~YNQ'B߾gs{^|.DwW"lqh$pؐWY a{Xߡ@'~opu[  k=^| ͳ̄뿅 s|M {1 >褯P }{ktk[S#|=1髟۔GEk[J;bm2ږ徶v֖gi`^ c8 {%>I׶fwoF+ƠҲ%-:re81Lc._ǧ,ȿvuÑuqz>[d3x5wC :@j=w?+|ȁr~5ݛ5'Z7b%!XDP4iUwH%[i&ǖ<ܢϠi]$覉7st?n _SdUtJGA,r0:eI-#zmo1Cn.-t3W=?enpvV_#Wwm ۪@w57˖X4<|n.t5 b<pwasyQ=ܡ;a^=l~y[j:/^1*ļvWNcF9y]ᣟ'[aDZ?mzzCj ӧ#}McNbYߝLWۛ~7w*5w[gEv-Urm)P{|c1|xͪHߥX 1?iiVzdқ0qM>7Ok]{N]ԛ\.fZAwVp /c_ۂc7q.nx] 5\iظ+G"s šE+x[c<3z:uvŊ*+XT97,GvEguwxC&qZr!b?$o%BЅRDE9϶2X{sv}[X5ˢ~ˢ :G#-hջ(tkߙc.cQO4/zgvc%.h%2WCPA~e$)=u1nZgq9uGo;?c'[k+7Icp*le{xa%?kN kH\w_Gv>,P#y:kL\m1֊NLt^tFM"c:w/@g> Gb ꤤfR?;s$vg6vx}H>OƎn/Gm6_H|.\ܑ"Nj1OW7upƶ܄m bF['>Cpda{J9K_47˜=RYgz/j_s[7w Wz4{WFbD X2p_(L̥#^1e :] @Ǡt <(HYK;ϒ~J}z ImםcZI[as+΋Zy\ns'KgzGVzAoFȑ1,撸3m\G3"hoՍu8# ":/ lQ_T2,>o}MuETT3q{$9T`ӑn6Z9"5G $% FdE=BFtrq΄DNg>^\I(ΙG_JӽoDr W7Iϩ=s 3-ݿT%EΔF/L>)^Oұzћ7uj"L,e:q{s}6~-W6A}xؚ|kK]U$[G')=) '~˵c  )ZCLjtQ:S,>)DVQxm|QbQZ{XL;u,9Ke{(+Ơ?Ͽa#݃bOj55txZc?7P6|*^=>g@ڟ`&𮤙^ξr]k#'qM 1''B5T|;@JV™z ~_}=τlcaTs~|?&{oz%QY:~.eut|O_q/~k0K)+OWzoTrrj<99^3 ;.]R k=1^;WۢM:? |A^uBIfEd 8mA,dw7 VЀҽfMZf;85(屐] 6xSAiBCmde}l(q!6Dt Ar^ \[vncTNԿ۾Nrv {9u1W)0j[dv :o`oQj?{}?U<ةe+tuͫ1@̗ߖWxCo4꘳"]C,D?ܼszbp̝F)13?(̲sZvslC?3d]>-?P Ofp}ݒg8cnLsȗ1c-1WR9Y3KǜEaHJwfoMИG"yu޲Ot8s8_#[bPd.f1ss˘ލcnI._['1^`n~ -ܳ1:Șsx] f"N:,,3{1J}(z}h̽c.&[qĜTǜ6Vߠs/o]=-0|ʘ붜/V+Sl _:cBT녱ξʽk[Y1D\s]CYG}(tYtKS(ݒt P\1;'[6j1W\VⱭd]DbRl/9\DD_먞KU~9e}|>^bz9|AJC{$G۾5=?!_sLm#Bt8ſWW-5GՅΫxsflߎaIo.%yApV]V:Kk 3έ&Ƴ->sꘛJ"z=p؍ο7똛]$cX\ps˘k1W8K\syv=c/8fl3ξ׶.f;k:ukubcndyj ,oGcVl K̿0Gyy|֡Ayۗ OݿLLMG y?;?1]ug1h~F gψc{:{`OvA1Ԑ!.w$'7FL 欹H@˲څqָnktc)!؉B&[q\DaY7 )WGr{ ?N]W+,єno [Wƣ{%<.N$]l %Sn-Y75Oǫ zyp= 蹾ʽS{Ζcy $ໆ^ZohZ1o?g]GS0zjn'J7 Gz=EO/U~8P,L<錅u,<*E߅r H#t/cb9@O ԱP(p4?Bj aaZ'-tұ@u$A|r~Y^c0L`a 4eXx댅t,LVlqĜRcY܌Ku,Xt^~\c!@ 0(XٺXx Q:he':vG O4PP|P z'r^!{6?H^>_+dzlD):}6kދbbY_܊,ykNjwIu`eS.G}?vݦQgqAe EAס7T1wwYwmzŻ9p-a}6 ?AJ>A9Îbvdkf썷zTޛ&gcS;[mQwԲH';'Ԓ5Siݔyu6a> svg؇Cڇa9!7%&ŗ]r_xjG5QlOw1?\|S?Ҵ݈KøɂٻyC!o9UZV%|&kݵX/_E?/OwVr'Ԕ0}ϻ$s2OQɘXxNuGvlGKt~?3H_Ge~NO%xJ:\?52vwh֮B1Y%Grd S]<AoW:?'c+v8r7,'#O~%x^JFo|ߛqG Pףc{91Txm-V'xY=js9oslz+I''780<<mX\12kWX@7Y&QCЅ/KS)o!=):m=h+5g1qͩhGV zA ]J1 ؚYo!Ȱd_f"!f~-5{ߘ2VaWn5|O5-SPolG\ֿ 7-)bm#$Z]FɔӞhCnopL)_ose0111kkƮ|޿6R݂ 4W TgY9c7Sjwl\Kw\[ܮtvNP,Ը]3^uf0<;<> _;ғ<q=`_3g'u*5a@{o];W^?E_{shM}Osm4Ŀ]9)_jĿWgsxsVHk#LJ!6[#ηQe>F}W}%͎DZ@^H%"/d=WKu Y? y!Pc"?}g~_cۄfl]|*1U$jb0+Tן@M1o|* aR'lYjP|ޜS }e|'t|2_:8;C&Z:pc86 1BqĿ wٽd8#}\.G=tYt~n!t*Bn{Je{7u[GjiF븳pCJwdewx^ļ^ǝ:(/SpEÝgLbd-jAwHm"cXEQ^&(#4'|.7y2+S`v|}'+Ku6=o1t Gj$8^R3_Pݕa3_Vē(xO^gA1~O.3o?L3{[g}8/fǿp L;]zo1cOCQۣvCdetf41)=/Ej#_޳e?"ŭmgIJM@M~5EM~w ^甞Cb?vNg.Wg}w&&mp*=Q<d_ ;X1 @La Quo/gX yN$.kS\o_8?Z1H^G{{_ߦOgBxykoIm/?S"|xNAAOsBm>0q~[e<?҇{;]G#sYtS]z.# xdS.쭝{xK[q'9Vrn c !c7v~o$lm|՟?mz_A=:e/@}/'|>yl9;7vjƆ)%m?CvPVKLZ?sZ!֝#2[n!)4hgrbުP> j:jAcc|sVWϝ"|UdT _WEC%On2{J?V.??z12%ߟAPǕ-їިA1N<}iU90FG|mR՟ &d>r䵙csN)20vU0cD_a ԳqAg>Poc1|q*7llS$@;Ɲ)oJyP$2]uԨ<&L8ζxF):H^:xl~SydŗuFVj<: ӵjTϥ>Q՟'@93SsX"dZO>@> m`YN+<jX2:߫ t.dc><߉b[c#j(AO!Gko)S~q3)k,~%Wo&͇yGUt2"xGAxz?F)_`IἭ қ~'MpyMtQzaB{8芾 ՟DS濫}(5(֓[aAavmB7e12۲d?^'djE2ݺ 2;ev,6lb]5"V\~zs>er9/U ߰⊬R7U=Zu9W;6S*## jO*4%=?Rҵ*?gb| 6NI6FIjO<cG36YV~fRzn.ѻU[q.4č)w ]Oe믋*7E]5ﶱϥp"J=<,i\b].`)?W0ՠ$90,~G15qZ֗NpǡX a Xz}6/+?+r5ȱ!]`pus+r]/sz` Gyew{b*ҕ6s>+| W/ {(ZtYؠ,r dz1;2#FmfXgc_V}uA/U.@5ƣtll_ciӹ"Ƴ+ȼ*>_y HuSh*eusk)] { T֧R}BYoN,,˛uY+512YN:(xu.K.eć^N̞պ,tAPíj*]+βi.+eYj; J5h.+]&;ҝ/DgPfd9[էdy gYHeyWqļBHyNR?>ġvGN$c_/,貼Ճ j#%yo(yPQsU<d"`z[5W3/‹p~y#,hJ>Q%doxqYsNzG7@pL>8Ǜ([毦D7?x1p-ؒ+#x=c:. {|T/[+1s#3c!6"fG]˿νӦW6B>O;b OivDivFXXzV<jp񯋙cTK6G'dQ?ݷvt!n׿?r2n_֭~+V+ʈytd&; 莵cX}Aͪw/nupܺֈDR ^xhc~VE/bWmsÓlQeS/J-ԇ)S3ܢrVr/WF?"W"I1q+W$_`k?(>K2j\\c'QsnTJ(e|*s _?BE,7Z5J/1۟G기*+n;BE.b Y鄋e3w&E?cY\ġZ9,#f?j \\ԑʐ|w SeޖN!Ej[RAT?١XڍUcQ~j[\Sr [E.8 nIb^@?_娖3.㢳 _X-*EFz 5*E&踸J3 '_pE< 㸸@2\Ģz0O8,ר]y+\Q(߫#\P\_T1>}n.bSqѻ]X6qSхX]'(N:.tU ח.&O9otuqѹ5ɲ[M(:-A> rqqu#zt]޼71; EDS?7/o^:ydJ7/٨AEzP?oOw]Bw;oE(o\x/Q_@W]^TBžſ_U[w;Oز}թW޾q>KW<峻r ||';_VI1?W:9/ n?) F Ǣt; ^rQc'v@=5sR7FIyTyg!Rs0>}wyqssrdJ?\E7r7t\#d ;FE.n3E 1~9ZȖ}E|讲P:.ΓewQ?3ǵ 1θbv2o/$fvR g8wCv2.^Nt.b8sE:1NAv \#ܡ[HYv/QC'M \P;Z=θk}St!+wtqJCMkK.ȣ,u#f5幋s?<Ңd wQtYvQb&Ö"x]Zel,K鲌(e]ČeyQgYm2]]ѯS)E,tAOO*l][Wm3em.K3CYČX2VWT/~.K.=K]_/^A5F {QΗ9ToG UAΗs +QAԱ≗y}F Je^"+]k5(ݞ:Vt+(Ǯfc%uFzC`Y/Dӓd oϐe:?w]*0$ftAC<ߎguxx e>wWqz;LSg..\-Eݬjm^b<?u8d;2<d{m08F_BEy\Eʩ& p:vb< 'xh;,e\2n[x,i8PףؾQCx. 2?t:T]8Ihg'N\ǝlxlrmjQ@m]kk%!J 06+`zZ=JrkLS^#x=V#uj{bP̭?;64^Sy˦x?TxA^/;ؒV+=NgV(O&1&%) ?Xg}(igN~*l1?S-*Iz.fjRjyhxx Pb֟"]żC>˜xoT?Bq~`NݡFw*1f1WםMևxDxk]InWFR7)e"QdaE#e,NI#9ÛF%?zz.gwExzǷh#aTn) \w~@qrۑPJ;|\>/A~{":/x|dWyw1@̝"W18? ٬`>ւ8WB!@0٥?coYqsmX+!wײڥ~3j։f9xL>Ewd_cbjC9~}E–oH{'5ɽ[kB'}[k {eR#1P+7zi?cyt>iw])WO9 ^C}]%cYu$ccAmw6zu %(a?QRچ=71ܬ}C`^"(~Ӧ+Sgz&~+~0bJ`d_x[no)wݭIJ?'Gsv3|<KW-L"f+X?`ןNKXOD?Y@腱r7m} "u&|8,kANj]Nt :<#59ijlrW-9 pz$Ry9Tzt␢ /*~iqaEy"Ʈznݲ3E) ?vni]\%u\|B}euߊSJ}7 {Kc:.v(Nؙ[E^"+NqaE\\Ro'\#?@/.鸨'.w48X+~^:_e-ŗA|coqQ{)ot\PtaVTj{ˈQUE."n&; pQCBy/;,HJ,{ʉQuPJ̓."Dqp\P5 +Z+u\lWtሃ(_+͂u\Xt.FoJzwI~$buqQ#&鸨ȑe?Wj\(? J_⤯Fݾ|]xw1*Nد傷Jt\l'nzb;<.1$bS3n|;B'*&ƶ:.)5: wűqA<_-˹qСNJ.8٫ DGQ/e\ O..@ߣgP݋/r>rV,)ءK!l"\UvlaOG뿠[]xg 1:RхDC-9;wC]E't=9w[Z̎-_/z^DB=;(By3"?|^wl ԰2ѹ';r).M^`W'F-?tn5Uk8z^bugyd⹜`Y9wwZb|x#E<Ǘu )4Jg۹z䎱w j&n'\WBlr5ay:݊< ~oᲺo&q^=Lޙǭ6la<_e+E6S擐K0tzOҿ7XyV?UYrX36dz<ϰ{vzIU+t?X*.+y|blZ]U1S]cՏ@[WOmzjo~?QPzK<OtQv]IV:egxg\)qQX-oq9R]w.^ڿ⟕m}ur 3A:?tA(?5m(單βܵW;{dYڞܮ_*|g|DwܮjFww:-Alŝź,ɲ$a],2suYZt,!.OQź,tA`DWUe9Q֕ O\B>Qp?o(]( ߭UYNe5{@PYn /R]:Y$cCc%A[5 t.bXoUeeVkƀ,?p=gT-ez,ZʳrR +\J]]T0u1Z2@d6ތ,m]YuevqQU]{٧Ĵ4oRZR⥴ !6$&((&*($%(,-n=s־ ?)s{g'b}}X)+YUK.xLƉX:R,>.rbYQem'mY,Gaed'\IXsPb[G]vr?xeF X~xZe~},!X&e]2+J@Kc9MIJ8rOSD,&X+JAˏϳX6jHTYâK]es 0skwݫ;gb?|Llmfk t1?f)g'=%`?oS_p?] JJv)j/޷o3v̀f*uU|4+oY, zUYCT v)~=le;{dk;{~z?P{YJ ?~6wqkqEs1wg`=pcg=1޼e}R,'j~&̇7oUh{f-K-f$o#ƛ.,/xۀ"U#]lY6 Mr}W?CnNgf; {}7Ÿ}߽Q~xeZ|D-MpQZw7`gkڐE-Ƣ=-jpZՉXyqFƨ&VҼkiv@Kqg0ƃZh~AsDPKF8Ac']Kc*$AY-MMYHlk A2x;X9IRc]mc?,Rx}HޗŮV%ekiPlaǩ7vS/b}_%l+WHGBJKwW^JV>,v}+bNbKsCXnMϹT>[XY-?qGp_ȾA&?x߅ws_q}I,v7#>J7=J#B}߻@mfh, q]_Eghgl9)b@kY6C+>vVX>C]@ '1zuXYyF|d)_kϘj[}g3&;NOfcr,D,W`^)XyueAwmcD,U@ګ&bKNPnS+XJ+b9o5X.bsVVDX1,by,bK<?J.WeReܻY{| VIՇK7ʷwAߺםWh=F{ smK[ud61zY; <)rg!2;~>U;=^, EWfb}39"/װ>"/Tr3+ab7jM+q\n8klNwr>~^=_ra8.[qXR+ʌ"]`}7X,fɱ\D X(bbZ*b+S%"˝#!`WD1+#L|%g\g61+y,sekr]b1=2t,i%XI,|nP8# ٘jTuO"}t/qXHI {c sb?߱kJv!D!"aۅEXyߒ{JȋZ*'vKy׿d@ Fվ(/Rt^,$" aXIHy17Ů ̿zs^]<槵vەY0R|dF'wychMp΋'YHBϳ`]l&ʋ?1"/v)/:7[1 O6^52R M7%M@] nhl͎&4`׼c`MP_}g2T:dD{Xvj?e{{QSd?' 0]>K6=LSR`ˆ{Lm߱r ;}';!NM=i6='{F'Nj[ym.7_8s>y,/&`q|Ƿmr>{8Ob} ;E|M|oĿݢ?q=% -_~CIQmy'=/JcY#Og_ O&gH$r4W?^vΝ97\j Qop [,'1"/bYN$[ ϗpITgp-d G!/be1 ^<7Y ^"/bݯ b:y+yy"ųN"o량op xd0ŋ.&PM2^DQ} f!̺("4)r}C|Lb _ bߡ0EYk  'yY>"/Xx2+oӸX&1WE7ˋ//h_xO{5^D5b6bs'D @k_ u^[ku8!})/&r@D_\,,9"/&.v)/ߤzCF)Nbr,`e"%>'pߍ@nLYl<]F}5/_F4JK椇tzi,?nJ^˧8-x~jW1MtإXn_k}< AƬzzƞoMWUCV&HOr|]7KaMMN/co$?HN : ?]QĮ]ʟ?D@C:i܉d,wݸ,v`e|ȝ1,vA|?x`j!rNjx'¦vʸoߓ?A|{ٮ"/udߝ#v.E.2-FX>5Ke~˱X,6ce87 h̨?Z.r8X_P,r,SD,$X)X~yb-LOL?M/]Zbzk/ 1FXNqA"Y,1KD,va3CD,U@Wm{bw.rnVJMbZ"w7],b(.X _L;%bwĊ.r5:mE+X;.}h'sX̡X,Kc;L翸x=at19/> X>A|_c؝J64?ʅ,.+TN8'Y9*ׯ.S#}$HW̯wh>'׿ٸ(;ɤ:O?pbwp7VoyͽV_RGp$s$kgsT"gG546߸^WAR#lASJWɘlgGQ9h2X^|+|+&r,:%9}>{p,+Fs^H yy-o2u؉}ءߖcɟI^_OO# $bp$H./ W?^hnppIIf#$? ?BIf볯[N<\"bX1[-%A.g'ÊY^Ԓ"r?8^>{]ƋaF~"zȋ{'Ր"/"8+?^L}vI{r3y{6߸^ЗA,GE*W=B/OgWk6j)D`bȋpϗb%Ta (?g곋sCx(EP.~V Ig, 3@'VhbW2@'8fx1Ed΋"/b6V戼i1#g곋Mp2pD}9XG bK@D8žĮD^G\k5^z0SŃW7ݧX 迬a=܂+"ZMCr^@^n.~k4 Ӂ+Z;ͽGJ_9W:E/rw#XF8abwV Kb\hK.W%v"uKZRRRo,](SXI|40rn _B4_JIc:vxyR|T5b[;g-_IFӬQ]e;[.|r2 Grg NxԏŮ"+w/a ?}}7Z<=^;Wfy10C*yq_[ xljP^|HƊpإH+/l +طkX-O y? Zv x1Iz~m#-g Qg},/bDKy1F/ctTEo# {9J>! ,v3m$ u^>S/șOʋR7me}+=A||M27meyQ+7]ʋ$@&vQ^ ۬"h xEXIN+s^_^b;5X='b0 KtF䉼P^3yKy?#1:W>X=DZؽ+D^p> xAh}:=^;’2_qp*HE*:_$_ASA'xja+ʋ:/F `+O;`0~bOkmο %oo{il!Gp/Ŀ{0Lu$}[oI?Kݹ[Į$ݟǃw4w 0D֏Ů(+%o.忧p[ڧOcιǟAN~P+X\x, lRx]ʟX/#Zv6k`{ʝtܖ#ƕ2Y`9;7#<z1Zax1In1\-<:i0#X)B J^V-at!\i,7)b\i?WKAN= ?翋qeK WJw r*ѿKf_Go/ѿ{;N.ؕ{rh|OR{;@},vkgcDރӿG k=Zۓ#ѿCk$wN><$=g8+ѿp@;&w"ok(%wOo5Xi+ѿ{s@PԿ9l,&muV<%=opOW{wN ~?}$OF,vJn̿ `_ OOݜzyWq0;+WKvb`i_ӫO]/bW2+7t<6| O2x-:/zJ柢,vrdinx^ ,;8?E\,\E23 #@SՋĮdign8݇wroFZ [|$O=X^$?޼ £[ƺ9{"ƒ+b?@db#YĮdi'nX6ċ xa6r)} .XyёxG2T9/yq}b).oMB xl?VLgD^8R^o%^Ƌ˻/ӵT,vKO%?YǡmyZfV9/H_\,\eIˋA$L_l'yqӕfl9J_z~ΒץLWj0j:p0BR&ɶZ{NΝ7y/ _>G|修b!/I_*$ud_kptJy,%e{XE{Np?x/r b_6?#ݙGxA΋"/.r00F4hQ@۽Hj"#-yKy1 G~E:/nHyq!nqF+E^\iFy`=^t"/bK]8!.o"/T/%KE^8R^oW~1:֤cy[WȋBY-oI'yu/}ǭu&EE%b,5qbWjFogW_݈꿚 uI_-LĨI< [an:;]++0:/]$?/$v%8WvrAeFnD4Xuc΋Y"1SR80؂lF`7_|_zs0CB\,n΅uT_bWB^pPw=g`ٱBeۋ"_`ѹK `jT90bt.2 -lK Nt̞%"X4%=CAdo%.? v07g ^=I?Iހo{Ře:wy?E=+Y=I `{r2D}wz\@?ﻹaĮdenO п];s }ko`tzȝrYC}FpLxq=vJȋ_&!%"/Yh]9Hwv|=}4Kocyq-c8Վ.i Fyq).k|gEr^XE^ b}{a&FE^mv . ]` S."CNh8X^7ȋγ=?"/b7̿Tyec{hN s?qpv4F?; .6}D^8R^Ѩ۽ =;qX^յ)Ǐ"/.L`Ԭx @?x6H tȋ\,|n8F'*/][fSn{C^$aKͿxX^xvy|@U,v*y7~ Gt9/}sIrm7tIE# gaM\,_"/T=2F?4pإ_ np]'OEc:Tſ"/M?C|yq#_tW蟣"/bt/(Bk5ϔct ]ʋ~9xQ-+hB{ "/[bx/y;ŋ6?~n@ q.$?q6]U}YhFIܖ캲[?Òo#,vSwctTwNG{Z{?<3_rF$; fIb=4~_}]W!wH2:T$dB8io?U_ja7{䈵?:/q1F  o_J?3["]WƖ])/qJ g{j)F%?~4}OP8wZ{Oyd\,|C_X[U_?}mJ8O!I/\S@`:$dWY,LkSכgׯ)]SכUR{ʈ=8 ex@i\4!K?c.ێqx$Q,p,Ɠ}`aq06vé]G"ִ`bإs:; Ihۍ vg`Bv܏ugSo ^:!hPx q*=`O/_dPE?C .&?"jw&kO#$=?9=<p<τS,rAwƕSg3v?|4\12V|j=yulfy<-8X'?z??l>Fο_Hs>+eƝz.ӹnݣ?i~s-?j󦺻?Ԟ|Ũ^?JjXr??t߳?Ta?@'%5,v1'FNMPefC/,n|ĨVp?T&!I1+8JC?ijw8+qq/XϽD$?zMC\[ s/;9LKT=^\TdGU8ˋ]^{•12U8];UI|:>0cxc^dG\,Hc\,N>.}Dx]a<JTfG ܝZ]^C ?*NK?~BJTp*%?ba{A2›؋ĮdǗv rס?>4x)}7:,nl'*$?|?0cOEX$c1P:k@$o$v%\-}Jk n_?y$k=W=wZxZOr^|%bݒW =A$4]Wj_G]mƖ!`>rP.Q_Wב_fkf|jʹXNIW׷Wy{$U忮o]`~Ρ/%,v`T.Us/俾i!#S?w7_? X8MK_bw$9B{؅(jxWV$?ޛb7 %?s=}G7K_]>;{?ɹ7'|Zۜ5ҴoSL– 8IGWe\< ={unQ54.ȴaX]a<τ {;&'wOnO<у)̯{ -~MCZ"'0"Elxl)a-oPk6;; 3v3Xg9,%bT&) ɬW%=$GοeroM{?91X֜|; '? ϻcޡN?$O ? rFGR7XX݋"{0XejFBR "b1`)0#X~)bu%J??f?Q3п~!J?-AĮc5{|',˭F,cDyXӆ`ƉX~byIS}jצE= &"?XX}X,w}g w "w$J:^vm=DsXb𐾋 }*dϡS"~?EphY?kvu?H[Y!K{'?p&v%=l]ꟊBn1^I,v1"fsoPn0ZfY9/$ϢɬoKR?_\R, 'v%]l꟟VT,g },nf;"Is'GMY pAO7 hvWF%':%M.?bWRpdp KR^|߼i㚟C7MQ'>.oBc͛&}s/sIQ`l;Ǽ+s@+Gl;׃{$oTݩ`T(Dg-Q5@ ٴlOM1 {b>_ &Ŗ "=kye )֬ |D,cY?'#ԓ/6 }|vC󇬿ٽgIUDyrL6lxr`'bY|z[T9=# /_&ϱўb;}px 2V}CUm(ĎF;i9F׀B6c6v:??M9A n\ոnǠk\`KJ,CAW%5نh¼016>|Ro-=|{|v /g; F^@{UP][|vA?Ev)vp]al>s'9"y3oF%r/Ci_+/~.?΅]39+bۋHX>zOK.eLX:R,On^B.{Yc$gXvPrmmJoo3Կ?B5~Կfg\8Scv:Œu,s2N;}wcQIJbs)ŲJ??v YbWK ??zE^ќƵ.&=N_z[?t̴pgdxQba1g]Ms./h P}b`3Ȯrǚ܋WwnwC q_ vV\Qa188L^4oƯU)y;O)+Xn:Ѫ&;ڰU@΀w|w=^TyQR) 7&[Wo}Pm^] gd?fˋ ЋQHŊ$^zTEYooľ l9=^T8òHEfַGof\(["B xsF+D^8R^_}KE=t^(b$%p+^:/5ߔNj=NcE+D^,b^ymyI$vWpإ迶_}Ƌen΋͑"/b;%-+y_b п u^[keNj]]h\,^"/^b᥺ooPZgwr_:G.ap"B?{e&6;̉7E^2ŮL2E^gg^C`[ ? ؇[5_NjbƉx]1z\E )"/T]8_Sq{xqO/4t^y ]h^Nybl>ݪiҢ?qOI^gV7{$9Ym⡕q{'M–ϕk2e##KL($Ԏ_-!/k_Uϵ04n Llݞ6M-N|3Y;Gk ll?WAŧs FK`$ u\<=ޢ_f;<`Dָu$Į҂]ʭUD3]L톤nTR]3JZkvA/G`&?AUز(:^_f^@(;/wח9mEjܪXһBeץX|) }G'3P;ݪ߄m$V~~׶џa'|qsjmaSi (_inGlyl:{lόؾckm$3k?"Y=ո_IFG~>c0~ ^3א8[/۝_9t#oѢhӂ_T.[]O?$_]zp).ԭ$W&b`;)ۋX֏Ų? E,Une":0 ,%ubn˴xy-\uŲ?HT{n.Ųx=-X,KXLf.4IJN X7JS]IJU^Z {|#g,:XvװWbyQ嫘s?a}oK] |r^XKE"),1wT2g Kծ ,j7]$bKl8;,;XL0~SrV߬?-~sc5s0J~rVt&-9LrV%rfΟmɒh?/L\m}]eW_ew\55r+ΖK:wO:w\b$q"wbs/j?@8m~ZkNj-Nb*s!D^d'_7Hj /ab/=/v`41RE%cyȥzN YIs b_k /I Y߮ ()Q\ rP^(N"/v)/>ok*]EF/4b3љuXj;=F/HKG^:/5]Ŧ]r^,oy1hFGbGuYjr"/v)/*u=GŬjcy&cRsY<]E^,9/}g5R{gg$ĿY*@[?T^3ճǵ3՞= Nz3ω̳fsa⳰(C&YPzgως.}7+7Y.ȝ(G{fV,TŒ vuOۋIjAU< ľ`ngp9/^>,b!7gJO 9.Wy1Ë0!?-Oi '7inic_KD^SŢDOObLI`&XMS|W=J@/b4l YLB"럠]ʋ^Zp#H 2ɽeHP˿`翈sW,Ň2sW%vK,%|+/TO,й¼StO^mN2z- 2hOStO^`uM+0z)kz ծk $vyKۀ#îpAO1٬)hz 'Sԝ''׻؞߮O/]OQw>]:^b>@z.9^)O5=œrU=z?)#S;뚞b^]O)kz hsZGS=E{)()֝uMO1hpKOA׫^9> JX/Νhr'}|__:s1g`n ߪ JܜCp+}b?KEzR|R9=vs6ЅJgq>sg.J3i%>>E%@6ƬIޘ--mxPcohRȋYب?ӊD^v/~K#v E^8R^?i.<_a5^<6X^{$x4 >V)bfpM￀>ST/V:OZ*"6t%Fy1ڠ6 .N vpإx ?/]kƋcy*;BȋP_7Ht_/k5VNjN=?[<_0y  7)sD^vu-b/l)ŗì5-"# &ɱ'bp_S=&bb KT{)tإX Osgr`9:by XNbY(bյu?OQK]e!Z",rY;9J?X,ڋQ$3IgbE)ؕrZGEhp'˙Cܻ&J? ܻ I eu'|]I'?/h2RE|nE,'\`i#f+h[|ǎY?,ĵc_ #> ]p'92],o$c&{^Iw2_0pb-yl|E3cD,1[&bKD^B/X.8/rJK, (k3Q}>B 9pm4^k%0ZhsA9⧤?^WVaGOHxђG W?-`{%0I#dӮ?b?OhF?ո3pqIY,v_a%*PHhqQxJj錄-NRUvc՗xf|y{\zQD.\`hDȥ \o?=sIݣκn=К̑3g#C$e#?r5 ?}SX5vϟ$[3,B$?Oo͟ye756~D3tMg}ًѰSO\+1)z[`>tWq_!lA1}~$\iσQ^"Gbto%sxq q*@Nl'|&AY>Q0?7 o lڵ1©.ڥg {W<+ؙ}gY=Y>QPȇ 0(VyLk]c{,'!wxM~Jc]A㿸snsg>y _9,|h߃ ҟ}'r h`g+O9%_ùǮyΝB ͫ~*}ԠO9z/MG>9Q Q<\/Կ/ޅww(b㚀 {lɭJ(@r~8Giߝl,gpHyxW8yڗ4]n~'#-?=&+e$ ֺJ@x8I8OқUݕ" q.0p.T=Y#Y].Lk>t=ƞ+q{XC,|? ;0BT.v4b#rR;Oe%FwJ?| ܑ*N u;,9јbY1;rD,CwX"]P!vX:R,Suϴv3XNu`t,FƈXǝS[MbڵaYsM"dX&XvgeYaE"7X>J|?qBsea4@K ?eez)r,q?W صe"!\-E@jWI5XK] g,OMcye,;Gb b9,r$bKabcx ۏr,G˅_Ĩ\.04|jh07`t^K] ?wAq*cs/S:wP,ⷣ$/׿T|g4_RsfV{M_軆ji|y0F~:ѼE]'M.M\g=|1DrSK> {|4s@l՜kG7Oh=ϖI>Wvg+#yk*a -4#MLW n=vle|[ݐT[~Fst +w[SSbZ_6wHAގ@3Z_7~w/1#uĖ?#Pφ> 5񳵚[19`ĭ.4Ykfm`og<ʵ#n"d~Ca 6bmF}"E| o̜Nk5}Z`я͐^_7b}{7c]kXfG#)m&v.t 2^La/n2j1ţ!:/N=bWE^ r>\}s^g&{uW)Soַ$Ɖ^j/Į ]ʋĽe.bx됱syѳ3F}D^|'ŋC6?5St%|ݟ@IſI%wpoÅΡQ<r _ =%o"=zbzJ .= 0k&h9{P㶏1/K.z Fu^0iyqb/zq ^{C.p m.0?_h\=zW5d{ jJڹ6k5G=>n pmϵ:`>iu0/9T潽VZ_`|9F/eckݛn9nj+?B(No~ njnU,'}?w ?bc[>͵ϗZP8מ_Ҿ|Bw{LNw_">S@4Ʃ[nZW~?ݲ3?+Z a/|{!'z_v~G1&OPIkoL$~\o xÿ:U7rlxǑwޝнtbs=/S~{H>+ݗ=Mfa>w-٣Yθá :1tv_*6y~NgYtocOm;d@GttbRx[K t1}?vn'NU&=1A3XѶ|G[BN`y#Y*Uٟ9RG?Y:TpjAݎxXI˂]4jNRs4Z\ fhziF4O#Ċ['??wsoYj<{0s.7%xhyͼ Wqۥ2:/. cm52LO~wmwCGY|sB7^n|l=s #(wAWgScXDA=i{x}/F^Zb$NslAA NR}G')-Nz@MG '{ ׿?q=ƀ n9 Y!aοO3{_߁o-MmMHu$oI My\ksSK3wq[T/Gγ?Zh{Oٿg=VGҿG>|8Q_zGmQXk{7 k]NV\}VdY_lϝѵG^GCY}_/+ԋ0ԿG}_{Q,G;Q"tu^2'gϿd5X}Z??Ͽk$kDNX-fi$>+"=8D_jr`tM.r"/,%F Wɱ'b9rM6FmE,X>>ERkrm'bK|o<"rT˛;Xb: #O~;.쿻MMGV+9bR,'~Wb9ɻwUX,1j#u a|ֈXv&-%Ao_MUk2^)"J2R:(b&Z1':Kq'X_SXC:.}׸u  &jf4u wE9-\;֛B4B8V@稅-ȣ[ 뵰ͧZ_﷒ߡײ_@e=sZ7/-[cVq$6c˟7 UCu .GՆEUusP0  k`iijAAjIiIiabaiaBiIijbab $&%_%)sΞ9k L\zZ3^{d1ԧriC7bQy Is i<CT|%mU&y 鬭Kr%V\{P Rڛy \0皑KQ GWcCsvد2ZB>QuaGuHQB}:ߞ9Vd9 3;-c;8QBf98J@,Ua36WTVko0]30;_ku-Ys?녞lC= N[gJ9 ]0$0ý_Foj0t^0~Np09 &`v>oZa9JMlSvNv?.a9 `{6/Dk_JԓE e׍IF];4ԯ#3O| ^ZIqY<{-ۨ{ijݭ.z%rj~]??!w!Jx*w.QsP-w>?p疉&w|ķ,vDDN~;QR>j@QsowO(/]#S3D^Kgu{%Os?rd1zwiBdI#wGKWy?x 1o>z+cE^`{y>Qy7/5/@=.XE^I`uG%s\Ŀ$bX+w/Uh#ތ}/nB#,D^b7uQHzގm7[ydxqS)/ D^qD=\(oE[NJ"^4NyKyѷ; ^;m?_ϻ0E^bbQE^bͿm5/@ɋ)b=Eliȋ_8[LCog {$K{\IF_xo_^h޽"/j}X !/g߷!F9j+ r^_AK"/Ns"^"/r)/Z/u n4Pϝy {g BKk^|l巄xƋn٤9#4-?tyEy΁\N.p'wswܿrR+(byXWXrQszR)b8MlKInlby]˿XKa|v#Q5墚gc@K\eAHn]մY gok;Dul?rzg`,?~ӕsfxՄOnB+?PAWs-wrN7k;v3sO<~hd{f Qk$qHGw 8hzo/R% VaWyrVh+BAO^"/r)/n4_qDEbTȋ: Daȋ\ײ ߼EʻyqȋnuWrC MRRE_ZrՃ\I1YR_"O;m7k_WO5y{ȋ,vȋ,v>7wWdȋݜ-|/QHlaH7ݍ,/bj$7z3 &Ѯ~3noʼn"/*Y@GI\ufyM^񢣼Sȋ]-Bݒ:OeJ?vǜ'RRQ |Ofb7k?W~Y"/d{hyq#]W3G9gR>W=^.򢂳OX+@/-TvR.ًD\S.ŵsn"ۨ"ӻű"/SX"wB2 Q?"V޹3^tׄG7s㠛 g eK{D-?!|; eċ&/LyQ6DWŮ3 |촕_3^\.Vg~R$jYȋ8[x9D ].oY \ʋwgT:ɻܸ'QQno9_*_7Ϭf% ?G񧝼vR=%ڕA}\ϠNH_%OvF! W2dS$"'apg7gwN1KwѮ|ۑQ.rGVv<]= _yQ+}6 W c7ᬟcTw+p+;G}e%f>zP*nd9PW56*nD~[y{_~Wq#1D!: 8ȕ~_;H,eb_r@VbpQ%ܛ=5Vf!D/+ﳡqpPn8[x9I_:bx=ȕ8euWݰQͽ.EwK_>{jI!g u!W%g /A%:[$Ju Rɻ>0^_=O:zڀ_'~?]Ǹ_6j? ʦD|EX!GjP 7WS.o ; ҇(Ki⦩[bEU$,n*r{1ߖڮ|ݮ xaqn#qdq975$7cH,ȕ?.4X/-}/\by4n?.+`le?(\AdS.ǜQVc.._a/ǥc3Z23l>ҐJ~)\?Vǒ|/<]X,Β%X,A2x3>_H;R, HnK%sf7xyr,?΂{u-wXo7Jr?+mi_} G+3:zAiY 7b濖Uut6b2{[^{k\@5weuElίz(?Uϻ&Rl{?ι;?{PVװ8~.TQϛoeǺP6n~ _N^ntL,i M곥3Y腉I3,MIY|kwtH7X', -m! v&/XO.b pXr"-lNŚ-om H8oMNj ˋADl"YV_8u?Y֟>h@|[gؿՒ7_=sUnogϷU}oO쿦s?Soۧw'uU柍2u.ϷOC/㿧Svl$25JOJGʅߧ_!{SF?;_8ߕ^9I$#](71/-k&3η3[;Jݬ.&}"jdU>;J=miďW._I_}ZYj=J=a***֏~\fK_g_'bܖ_Izyr,7J_-fA%UXf/+̿ZͿ5J_9R,CoE1j7_?Zg!a{z_*k9+_ͻÀ8Ѹ;ϗŻCf7V[A"pwH-"th&]S.1sUYaywkYrʻ9|Άj[5sȝφEͼ@qw(ُxƋr^ly/[ %1"/V'q ].E OS.őMYxWX\]^0y\Ţ"V~ bU0a5/@ɋ6{];xq(^΋E^.*Ӊn(uc ]Ƌ]ܛʉ^S.Ej$7e^(mroy 7ynȋXD^dc!TU5/@]6{mgu˵FEg "/Vp\ċ^ \ʋ_29nQY ^dySM^ybwc%Q3D^բ/ oݩ>s?tZAT g"nީngT ;ONZR?]R1 ϗkgBD](UFe`r&wVIuAw%_'T)^==7-zJd?9SD] ]swӈe";X)}gu&]Qfߙ+l=7^΋Y"/duw[CL^Oel2^d%r#bHD}{ȋl;ݏfk^|^d9ƅIy-v#QK}3Iy)+!NAZ'9rjW[wII-eߩՈ/] -}\'WRf8-?_%ͤr\?S j;ozw/ X.Mmdר]Oǻ9A+٬Noufu-FsEAn?r(F?+5+S7v3y1-cXZ-&+"Obn+[؍3[s=]"(x+RY| rȋVmYnyE+>yy \ʋm~]QXQJԮ]d p~֮lG94olji< %S%__ggE!J9xve'_AmkM}ۋ>V/|UF/v|k_Ϟo/[A>'q٬E-H>-`_9߂Bwt-1Bf;oI1 vIl"n3cojȋ"94oyB*yS$6g7#@b_HexQq//QYg[Pa"/ck "/ٞO&O!^|f83^l "5N)n`/yt+dߙ&BkhrD^8R^| wbbrwyQfz_Ť,vu|3Y6go/@~%/6O"/l?:i mg eD^r/rrr)/ P|vX ^<ӻ4϶g;7@D%4xM^L7DyƋ\_RliD}%p }kȋ09rwX.MIDk"֛Q{v+Ϝe;Q"/^j77_ o#I6!E^<¿:1Yū-G\yTn+()b=Z/~Y˃&/NpŮ;Q"b( >g7__$uy1gX-<I.לTq$ )b])B7xO1 ^?]^|3D^bwڏzxyX? ?n/6{J<')ًoeE)M"/:޿o,b z&Oyxf'Ybwt$bZOPl>䛼ijLgEsؿ$o*g>Co`~  kWֻÿ(^ٿ?HK[,nU/Fb^*dyRpIo@r "OXt~]gtSpGX.2Rqo 3V1,Q#CD,΂OLXr~B>^+bK?淀$Z VKS%񏱎G1Bbb'x0!"n zO ߌEW{Ƌer^L\ bX~y2D^r/O D^8R^|0 /" bbXwy%"KaE^ Dr yV!YD*Dr y%K,\G_ܞ,9{?~y?t"_ G1Kב\(u/9/fPO3og|yEߟUX?V@AŽ*VHBĽ5T|yK޼zSnL-f .w2P.XGz[sŮQFyx<<V ?'?.lXteu+AMy1.Bxa?rE^8R^,qs ^ <]^,DkE^a#X]䛼S{Ƌ.ܣ[au+ !(%p! ] ?EEi-m%)"?|y{ˋ(GvTȋ7ؕ45ȋؽ?E/@$c~b#OlaIw"bg @o׋"^'E^8R^/vSUEZ{y['"+t}xM^Lg{Opp; ]-ެ&%Z|fcKI߄T=__e$̸ q̈Xp+$balg z?3sk97:dk?lhۅ CgZ.d[l~?3nzَqg*ˍNx< um>nPBfr8wnmS.P|_7S7FCE,MbܞC;D,za'ϣq"\>NtʥX&viK_w|Xэr(-bLBQ"wtc[?r)3??HSr,#D,rw~DΞ@GjD,u[WX:R,g$W8;<2Eޜme,}w9; aI{G{8;X.2տ?׿Ǜ5.(b;rKQdXf' A"\ mrX:R,_Cx,SE,{.Gʱ$"NX7? tz jun.'m',b*? m/o΀,cyeTC^M"a[`:>BRkؔ rsE,r)Qn ݷTż/<[ǰ}A|?oG-ϣuL,ef3DpK.3^"GWs v(Gߐ "/ts \ʋ¿eXKC ^\ǻRmoȋ:%Չ"/X!W0? 䛼XkLS\u yщz'g BwI:{))(ʋw;-,v "j'~xs<] s'?䛼(ٟ/w1Wⶾ"/l DϿnla4/>l}2xvaOo?~ CWzk&/D^t8bH+f{x]6{T9YMM/SppʤIP tBc{gk0-{QC~-|5hghU,u.ies'^Hh r;T[A|YҒroo Vt$~:>咤`S~~Ns3|=E]hsrA"]5|yy%Czvlj< ٿhv6M۟Dop1IGAK. RZ/i/'ʀ}<i@s.cR H^n%jϖzO""/r> %.OKV}:˹iG曼|vD'ٛ9 u|[ŢQ/%rމc5cvg8*75/KvD_"o78;<"cNk-Zlj`ge5T.C2\ܗ>ƾL>ؗOUo]|Cha_L9e͜ތLhM-3VIi~o$ѽ~o~~KlMߞ{oq{iڛ{M o!7~ $ N'ÞtNu ݄oey_rҴ^DU$#x<=w[%#\Lbu% ?c, u }2~0;ܐfꟻF$̽ATKx~ ?˱O -Muڢd7~ ^8F Z#VK #P圑syrf-if;AI 7mwW Nyl_JAy9_D0/kv|64[+_jrV\P՜Ԧ]hmtnVQK(庋Ha7WI-bo\$"6fQ%?N?Lwrh$x$tm&x هxEWv\[*%?Vs.LC$?Nk7.y3"(˳,o, ʹ "ag|M. rD,r)CPkn .##X^!w{ׇd%p4dٚ9'Ad%{Q{Ij#jaڬyy4ي(6ˏy4?yޝ=.gyx?Wݙ])_"| UU"thDiK3Jlkwd{;#L\&q:nV QH_jÐ<@~cf3^ OF%?#њ?;J_Y"9(%/Zs/^(br?hmE^OaKZG?D^p3AW b^σM}.]-S?33妍| 9bbph/ syjq/_J jVPu^srjr^EWT{8q/>.1(ܱr=?1ul?^Lw:xV 'Y.l?ߍ'Y^$ā\Ig+nz9*.*4xq[)/8fX'"X^OD^\(f Ao/"^|i6]=r^Ny[۫`OT8-v"/tȇX()"2^eExCQaA"/~b7}Q~[,z(SǶC\><g 8g B-4V."~ȝ )Nz)*EQ63xq[)/G@ǺؽE"/zG E~Gg)eȋ-|9(rE^~\ċA0NP/*խ|Ѯ4AiCr4V95/@ɋ6{ߋMyE0g 判Yގ_>܏_Lr%r׭]MiQ/{5Žfmr^ z尤\׾(٪ׇNEb_S^ >!rqD}PVׇs W/uoڇ/odI{znCWyMžgkw٠s|CgדM NKtzY,V- z5;l5Sϗ&%(KkOn2okx$:X@̡jԠ-􁿙NP=lLZg8\M_X'g#c}uhe;X4ل9']9礮RܯŹk%Hv{ou-J3c9/]mkܯ.i_~kZLv*h4`pW,=g@yl+~2CO9GS.O Q[)>FgwԹ?۪{sqvM%|aehtQ[_GCB]i_diFz.a:7R%ۑq:>čgi%Ӭ :Ůݝj:ZpcFĝ4cJ㌻TnO .^S7?V/ϕ*^+gק ])Z}>*Gzf۾?QۇʮѸD* v5khthߎjS.Ÿ;:Ͽp&ĺۓޕ~ j`y ?{$#ϯ4ZX=X+];ޓK$b9W'wȀqi}^<"GŒ68ei;ɢmP;Tvk:6Ej[Y,`7:3>S٥^C㍎GL"Q/FR<gh ~+\ CKrY\z8Ge@a;w 5mO:>|'+ߩ:Ű !nGg[bmw2 luF|:A*Am< ?eGzsíٷx_j] 3a_zN5;b {XIH$`+*q'jpZG^k[mlWP]mVӠYIQnZ㬽@WjBl?z|^lA6'ru[ηĘ9aKv.455)Пwo~ϩ/di֌hL1mԖ"eQ[aі՞ewmƧpa& =Tnߦ˙}nڷq7W;?U76;2|UL*:[daĢfj-(2([uS\5fwm`㔯b[$ؕfuMK?G-rLK]il.1ִ\E‰=v.' ָn{zFQ8F[ }/:!􌁵 AN8N +ult;I婬 1h%I:[,`NvNs>l1Ş:vFIS0]sώX;fkqFE]7ˣSzo6lTHv]֕;>Y!{[o._6-Sg zXz9V7q]:z Vӟna Mߣ Α:FmN[ L[_{[i̷&{ 5-o9Pjg:kGDd?*I3Fǁ\I~.$rcFNo@. X> ߝo?r:\[1#Q;%ߜr)?qcFڷX̓cyIrG#娾Dve 7 Hg.GG&K\ңG7;x9?,^baOIJ'esA "\rʅu"N{X&X'y˛&XnbbKr_Ò41oA Wjܘ7ݛ9`e@g9Xnb9bQKU\}W/bַ48v/3?K< "[jϰ}"EvVl bTK.WòȐ l-tʥXC_eeQw@"_so7Fr7n|p*{0 &X:R,DrG7f}-b=EeM-\gX,QUrqKQ$m 8f r%o\3g>Ǎ}[Xv)?|2Ÿ([XzU5:tRR"v𸈥S./hKI_BO&ϰ˽Y"2Y,$:XJXr/ 7K)b;y"&y7o}v_ g1 MC;YL۠~xuӡ461 x b8v8KgCW[\sʹEߍͶ[%Wݚ~ՕmGc*­ޝmwA1\Ѝc1QweX2_JtD1/ٵA\vv6rU+ppd-8,[A5\VU®ח'zEzL4׫Ob.<3[y?Ro/!DRR忨(S-/%/%\|KVyC< wcQv X< ,V`QveR8g[:FP/7cĩf89u|>Ìl|9͡aG1ۅf!Zy3p|3fdUIŇ;1ZcWiFv9DY'd.Zkl⽅ r3^dƋ$̧nĢ.L&Z5J#fxMkr%ml /O/xBmFJf!](`l(u3^vņ; ;$|Gbk8@zkF*ƆCρ,1Ǭ*D 16|f.7lgtFfĆ?_s俢ذf(6r{}bΡ׊űa?wsPWƊѰ7ot+0ux@7iu!׳e~Ŏ7#\m\BOl'/.?YGxapE^GXv'o'yw+$l_i@Jy4Cr%l_i@Rwv:?"Oڦ&Iݝ'UΠgI3O>OCO\_΋''_GO$O6riINIO2\x}";ONw$; ^|'5yQ$ۏŮ4|,RDɕĿdJ=#/1J_oſqxLO{/"QWۣ\ _9;2VO|yQ(}%O'>tfN@+a?)N:ke^ɋ͒'9>,v}eI>DnoI?i-l9[;(9zDmov?6w+g RWǕo+ae$mDɖ?go([$.= (JNPOR/UoV&eP%QJ+~-f9⿴v=h:ȕױ_Wo{,oR6KGo.wm>hְ^tK ƻ|4qE%DC[)Ro!waH9.\2xom/$XA%jYr}\/Wsٝb9M~tK*;/yx"u$uxVXrF$EzXrFZ ,ryw%wfiQI_WJo俾ߙhוlr*xgXfY,Dy_U~A/%vcQޓ修`__˖_% /kcFbydH_?a_Z$5=޿W\e-z~R^ d˱LYȝ7']; ga?~%Grg_R̳tUx[xL2ij4{>C{؂c='9Dr|ΰw&g$Vm?gA\ʟy|E{;+/=U,vם;Vutظ|ynot_27"/t뿑(yKyo1"(O0x*刼b׵(oyż~4_"^|n+ Ar^|CżbVkρn"/YHJ D.ًks2 \ʋ4G|1żt⌯ɋ犼x+B̫y{V]blONGy+&g Ԃn'K9[9tdɛX^tK$O=P*wL6Ͽ'X.2w<]\)ɽyO2wGy g t!"/la9SE^r/Zo%J)/eH s ^]^Ԣ"/^dkutxy^hhk^|pz3^v" )/q(Hs9[ ߯y1 ˒\. o)7y9|VN$KuQIop(˩Il_65 JN˭(^K/`9\co|K\3BD,__)@$:k+G5Kg@y4Y@;bi$y ?/<)bG{Ѳ(/Jr)[PB.٪섆i@KڀDKfg@gR8MM[̥`vŧ1R0\?g.=, -ڬ=q&?&]gzNM[nOX|r[B->-N|LzFQ|em- g=gƂ0iekw=ߐ,em ~coy BU/<ެϵ^_hE@\<76oAs CC^9: "?v>(S$(#0/o$ Y\&]sX 7R7R7"7?1;_=9,WיIX^4^24lDm#΃|{leq:T7"'YXoΌtCn%r^8'[9c;u˜vphG䜷?>;_|nw9S 8<}Nضng "R8P"uD;Ro(1徹 GS]sP'OOOAO19dw8n ri[WXW;o>:SWyor>Vy|Q]29q4%3|֣_E|_34$|Eϓ#Մg@< Fu)uz>)73_orgbwkӌ4o[.y3ډזO%eE.Cn=2g ^e ^<%&/$￘bzx4znC!i+[ak "/ϰݦrϐ%yEaybKyf?Xrpny*O|? ')/\x1V*9/yg _4O/VïX~r#Q\ʋOQ;Sk /X|ȋtUDy㸜ו(,"*Ny_"?"/"9[9ЍݦppQ""_C(>˥Xgo/"_b7y\'ZHH>t|Cʋ"V%.L[-1M7~։xlˋs8R^|O7(y9۳&/Ɖ;X.QAI\(5Y?鶲Kx)C-!X>_Ӎ("/Ƥ3q r)/rQ[N[1^M/y1:|r=#P<}l'?@>q(g-ٿx<1lsn,k7)Dy~  0:Ȃ'>:^,>I!W4ZoX'¿Sj 5CDbM< O:mn>'ٳZτcS[;ޟ?5|m''V?Iu3l}wX:73P95?z~FtrsG&iKo+1vBo]ӏtlL[GG ff???o4{,?X|Qui϶ȅdvO%\k)$o\I)ڪ,zpbi 4pY;ui!a"aDg2wᶲ%<;ö{\Ń82ݞbKs$A:ϐ{`Q_\ʋ%(e OƋHby!Ń(DqE^ fCD^tf/s o"ψ,:/ {yLȋ]n`ȋh.`1>_%BžDV))b|$7 ^9ŦFOg;nzL#^|^Y^gm7aȋ8[Xst  E^rɀ7FN?&4bynRˋz(buDy:FrC?"^|^ =$9/刼 -(Cωla>+B 7GS.EvXE,K ^)EOMyqB E^<.ƺ7*[ٻ3‘esG"07(WQb(Z*p'g"O?)T.r^*w,MlF.Blo~ڻ 870ɘ?>S˟.z1۳~fy;Q= $>g♫AOX99 9|ô>1.sZ\p,]G_Nc=d5ޖb7e滧־sʆ-۪'Ѧ jMN~!hV0 '4NZ ~4tT{5-J ΝRmiA9a_W:)X}u!Z5>79uVvsmc-u~>XsקeypΕW ޿[<8]]ڌ\;nu)1>~Fݶu뒳ʉ1:8K\wYwr;u61%gYu7aP2ϺTY[w|>I?%|;e[.cy^nOJwiIRʏR~|l26LqwLm|'avL'cRcmwg/86^*?ߝ#kSwƉ 6^Wjnܫr.+|O9vnMF6y'u+bĘݝu1KGc󼏖kx1:*ר'o46V Oغ;T\7*OmvyAy،gMJi zͨe_ u;벾- cre{[1Bo.F0*\+K\._VǿR2YwƱ.}^]:2\wHms;Mqa^.f<%\u#\.Sf2FZ;rer]+1&.۶>9.Fڵr%Ğr֥UQ#|~Xg][xcrX_g]}Lgw%SI6ʷ`{qe]߭8SO'\.+U]+W[\.G :a77p߫5? ߗ0y3Ccj͕oF oғKkKseϥ .?5\6SKJr]6S ?;^KϺ7np%±ڥgcr%1KϦJy*tYK*mۯ\+?s?ѥg Ͼs1U]+?kX?.1rZUijG[ox"f<3tY鼲mcl.sYI{%TvX9\Z%|\?.* q[8Wo&TrH%ͣgE:?x6wYAmKφʵ0$|sQĘ.?*?CBk[~\T? l7sT1v>SC}7S&;#tƿ9oqԥg9Zm\?+aBgkrJcʻW? ퟭgڳ 4Wg;ޥirm_SΥg3ChiGw:9c|&?EYZTb.?ckPWKeπۆkURgG;6>r>1i[6Q\ --eq4弮)omls?uE?-WxnRO+5c GiJ7ؙ)>iÒJrmNJ)=y<< ?5/}]ʗ[wŌEfmRE fE\TR+5B_ p\h-Ǎc+pc'~>qQ\w$y\R ?6ʷ %_67\?+QI޶ cJVS, ǻVBlC>\j*㟥 5j:gogSJ\?+v^ecJVCyKngv:=_M~\3ۿbʵp]Ę._ՕkaإX>d\J u !EopؔZQ>Qv_بX?p7TkSF)rTI0yRk/U(l(|F~])1b3P?x܇LE?v ~ЎI±S{rXVO)|yTSC}p]ʷ{q1qqQk(W޶_.qQY;<.jrg%ܻy\X#Årp\K6+4:E`\w+%:<.**A ƪB+?z\humg~?7=f}󡾒yMy'EQ<;!> 0[B?rB|/B1xīA@?B R?4'B 2߁XC3BHCW ~G!!ny !~ !>Y / q_C$ķB|&s  ^75~?}>^/ {{=7 wn7 w]. w;N' w;wv;om6 omV+ o[V o[-  o7f3 o7M& o7F#o7 o7z=_׃:_ׁu:-_ ׂkZ-_׀k5 _Wj5_ WU* _W+J%_ W+ _W+r9_/r _/e2_ /KR)_ /K% _/b1_ /E"_/B!_/ _/ >?|>?y<?s\.? s9?l6? gY,? gYL&? g3L?g3 ?Ot:?Oi4? OST*? OS) ?OSd2? O'$? O'I$"?O'D"?O' ?ǃx7 {o7{^/ {=O' d?Od?O{=w;ww wn7 w]W+ w]. w$? O$? Og3 w;' w;N'#w;G#w;OD?OD?O{=oۃ;oہv;-o ۂm[-' ' ۀm6 o[k5o [V+ o[VK%o [-KAAAAAAAAAo[- o7s9o7f3 o7MS)o 7x?x?x o7M& o 7c1o7F#o7 C!o7 o7}>_8?8?8?cX?cX?z=_u]._ u:_u:m6_ km_ kZ-_ k5M&_ k5 _u:_Wj5_ WU*_ WU _WU*2_ W+e2_W+J%_ W+E"_W+ _W+y<_/˃r9_/ˁrY,_/ ˂eY,_/ˀe2 _/ Ki4_/ KR)_ /K%I$_/ K% _/K%q8_/q_ /b1_/ EQ(_/E"_/ a0_/  B!_/ A _/ =========]]]]]]]]]_/ NNNNNNNNNvvvvvvvvvv??~??+++++++++         333333333ǀ1 ǀ1 ǀ|>?}>777777777''''''''';;;;;;;;; _WU*_W+  _/e2 _/??????????????????K% _/E"_/777777777_/ kkkkkkkkk+++++++++KKKKKKKKKK sssssssss333333333SSSSSSSSSccccccccc##########CCCCCCCCC<?σy<>>>>>>>>>.........666666666&&&&&&&&&:::::::::?ρs9?  ςgY,? πg3 ?πi4? OS) ?OSI$? O'I?O' """""""""?q8?c1 ???????????????????GQ(? G#?Ga0? SSSSSSSSS!?C! ?A ?~?}>{^/ {={=n7 wn w]. w;N'w;ov;om6 oV+ o[ o[-3 o7f3 o7M& o7F#o7 o7z=_׃u:_ׁuZ-_ ׂkZ _׀k5 _ Wj5_WU* _W+J%_ W+ _W+r9_/2 _/e2)_ /KR)_/K% _ /b1_ /E"_/ B!_/ _/ |>?|?y<? s\.?s9?gl6? gY,? gL&? g3 ?g3 :?Ot:? Oi4? OST*? OS) ?Od2? O'I$? O'ID"?O'D?O' ?ǃx {o7 {^/ {=O' {2 '2 '2{=ww;wn7 w]W+ w]. w]$? O$? O$3 w;g3w;N' w;G#w;w;"'"'{=oۃ{oہv;o ۂm[-o ' ' 'm6 oۀmk5o [+ o[V+%o [-K% o[- o7s9o7f3 o7MS)o 7Mx?x?x o7M& o 7c1o7F#o7 C!o7 o7 }>_ǁqǁq ǂ, ǂ, z=_u]._ u:_u:m6_ km_ kZ-_ k5M&_k5 _Wu:_Wj5_ WU*_ WU _WU*2_ W+e2_ W+J%_ W+E"_W+ _W+y<_/˃r9_/ˁrY,_/ ˂eY _/ˀe2 _/ Ki4_/KR)_ /K%I$_/ K% _/K%q8_/1_ /b1(_/ EQ(_/E"_/ a0_/  B!_/ A _/ {{{{{{{{{_/ ~??~666666666VVVVVVVVVVfffffffff&&&&&&&&&?c?c?|>?}>??????????????????U* _W _W+ +++++++++  _/e2 _/K% _/E"_/߂߂߂߂߂߂߂߂߂߀߀߀߀߀߀߀߀߀߀ _///////////////////OOOOOOOOOOOOOOOOOOy<?σy}}}}}}}}}=========]]]]]]]]]mmmmmmmmm---------MMMMMMMMMM uuuuuuuuu555555555?ρs9********* 2222222222? ςgY,?πg3 ?Oi4? _________OS) ?O'I$? O' ?O' EEEEEEEEE8?q8 ?c1 ? GQ(? G#?a0? C!?C! ?A ?~?}>{^/ {={n7 wn w]. w;N'w;ov;om6 o[V+ o[- o[-3 o7f3 o7M& o7F#o7 o׃z=_׃u:_ׁZ-_ ׂkZ _׀k5 _ Wj5_WU* _W+J%_ W+ _Wr9_/e2 _/e2)_ /KR)_/K% _ /b1_ /E"_/ B!_/ _/ |>?|?y<? s\.?s9?gl6? gY,? g3L&? g3 ?g3 :?Ot:? Oi4? OST*? OS) ?O'd2? O'I$? O'D"?O'D?O' ?ǃx+xMdt35g؟:t?##ɟ̲ dBHӧO }u, ӽ{$uNk?szcƼۄeEHS;dIL (Ar E.Ɂab}x3ޟc;}@SPM +Ɵω:b^rp0K(g`TNn8]n`hKgyC;}ھ0N"43u7yd0'5]\ﴀ ?2k3>C1&R8ٲDfZF@~*mO ;QZ PFdW*&n33H`fp(\/w002+dpN`T7="s6C3az8Gp.?9+Pʉb+3YZV4s9j4KD/IԲ8G'Sm3ZH6aDiy;jURNd2Zשv_° |vh|z.i|43Esa2 xjL2SG%GV-Z]uZ8bp(sXv[LGʵm?+;?G k=>DY=="`XpNzhv#LUc꽗~_Ndf.̯# bKzhTݫg תZZv>YUfjZ6$z$ =$ut<>V7|n#i@}H fEnFiV9lJ8/q5ncaV;2C9<胝tuq4zߠ_tRL)^_Amr#>5}F c5U{+f 妦_H\c4c!9=7''î"+!0دcmV=iF{)Z[i;I<_2g:(ݿ*i}%5BHc[mB#]nFhmig,Hx8s>NJyǐ찼?3cb=ڵV ֟!)9mnrQmbGsbfR'z^B9a*;5^Ǩ}.ǀ|݌Ym`iˈ1"ыnƤ}ejVYM`j^'g{^vz q꘧Uf9zhz^%i'҆:>4eQ ϱM}W_Үb޶r[IzIg Q=pngDZkOa r\Ǿ+suxWߧ#2}ƟB MG$iXi&zWjM3BC~EӢ>}}^;T}xj7ͲoS4=jN43xN}~odRzz;լ‘?Սut/OxUNus~<=} N7oL'#zFESH8eMĪxލ3bVu%k[5(r:O.1 ~|oӭק_a9#?J3GG#ZGډ^⎴E7:w}/#}zHINMfzi^C]9f˾ ]95HNj W/݃5w}}ұu\hZZPXτ̐p ;<"i-U@/B@A_jciۯ1&F3y~|kZ&]#5yaײȇ.Sv~湆ՕQb,\ ޓ HF2'n#1Q?)+ٌ3VӺR﯌K2A{@ўpkQ۽Q!Rv4HengoX P_ۭ"*9m\;95P"Ȏ.cįB]\ M 5J[eeengZq)灰PS)>Ho=i:>W_1T<ż='ƂH\r]VKtMZ+LF9ȓvv%/[ל@KאWމ2)]gD*?;ދ׳[.,-O$;#>὿sE^]Nug-y,)y摜.Q8r_gMՏquVe_#~ScYמWor5#vme גtͫx+}0Ƒu"BYF&CJm!ba9Qp?>KWMvHKr~=D oi7QJ$4>Q9'R.2J/^//]?Y[Do̍^Go?lkKIY=x^cnFo]D>8oܶuCw3FUw+Y ؏>_smX]׺|4gmjV\-HM[thrm'kاfJ}8m#3ԟZ(s9ݏrofc۷VB6z7Dؔ[yĢsRsNJp z-#uMWgVj5RI-;̛Zv2WU#ΌX/vbWh<|rǎZ_ O G:V=izȼ?yB2Zn}g[ub?iS7CױG)C2dFUk\ǢZ)D CL4y>Z&yZ񹥛u"M/Fg!OyGzMsv?u)A_7g8a,SK fF+ fJ=WI{szhk',5 ϧl>u<ޡaeYRC4`֥%`ioF"'-;.ⲍ/D{"Ff;ٷ~[%AX[/3Pze* JmS{ty%+y_ت U¶ډⲅjl\\%ԭ˗}e^xJ~i\ eFLqB&Ko%A^NT'_a #LPrWFOqW;z)z=kuT>rhTݞGOp˧L5AU(أ+$-NHiA\'ޟ^iF/kqB_%J^JXFO:]ht+5Ac,c˸?b73Q4[[F g~yۤV7~Һk ޭ^V#A)G-$E{Fy*|$e(#!$^~jTwI̲ՀJ/'Di9B9A-׽Gw^Ay96j/>V"pnr&qsd%AΧwY1#P2^jT¨ J\RM* +="> >0zjst;=!ltW8akϙ(ˉ}-Vc}EHW *TGC 6PX#>c zMBH j>+nՃ2 ̟cG`{9(j>3QOݥj7W̓QSѦF<j r[:7''Ҙԕ!Ag@ͣO:9=s( D& ue@a3ކHP5Eʸ.:r9kȕײIFr\^2x/+j,*eeǽ˪{1QGhℼV|:Ѹ =:0!y3 j>+n=]Owߥ[bNM}q;Ilgm4'm2G*bqrL/N/MIXXXXLc}=OhroģR_':P?/քTZ>k^gk qB(ƚ5w!Gҭ ijY:D`Ģք=o;s kŽEG7UޜgfMeǢb,3g0aƈ}R=7e H¶xetWDe]F|sGGS deh" E>GU7Z+G=1!t)%#y aݕQCI;I!Q44~֒zsX.zmTGTwK^^[X5O\{1> s[ϵGKS lw4Yop3څ3Qk^q [ɚOiDH\LP,#hEyX ;hmF 2mjޡOqb^;AʗȐ+-ޞPxq-N0 Lj|rWE#J&˕HXW׀|ֺHyĺG,&}d$$Ib;IN$$m!Ib[H$w$Ib{G#IlHrw$Ir{F؞lH3$=#ٞ$g$If{Fܞdg$If{Fܞ$g$93$=#IlH$6$M"IlHrI$mIrD$;$IvΡ`vG!,;k^ZW5ZW|>GXfF[)ZaRtiOۅzn/WLeiX˓eI ǂ2b _-O0-']tLMT5~c%3Pv6xlAyݭwP69Ƙ5!o|.Ht/哗gRiIr= jVZe]aנwJ5!?B (?yB_N/%WaBK?sY^uE5992c^i2|ʨX>Juז1]2ıjH("5n4qcz5 Ց9J~Qe8ʖʴyQMݯSb[L+ڑnEt_/uRy r !uDq>G<o|?h7s=a͗]~DsB }Dȑh/OeW5AX u>3QXǩ}謨i?@uG?AAs_jaJGL "#K@D;{TuZٵW;JVU8Wrm8 rm0{COP l$+\gK=i._Y|1~͟JX s<5>|{#[<: x(WZZS[[yJRt7V2:q Bk,,ٲeںe -Qv(=,G#&\Jx# 09:_0|b>;cBy;i[*(lcB0;+?Zo.Il#܆HrAΑWHZqi}"0c- y֐ b>\;[EW'$XI2AkBHR?o#Jwj_]U|ֲ7vX7Vj'2ۊ_LKE[xR>+.(\QMymf75Q6!N3###_t a[l;6l:yX0;;h|Q+O/峏Ii_rGL a~m^uƃc,neDOa㸲':ߕs=!UuYMʕ~UMpugL$ Y|DRziF[ ys#AC 8aovM ;iL"ޕ2nH6A!\HoL{9ք ?IJ@HӘ}}w&}˕~xnY 2a_h7z9`%dj8a!'T ۖ !7]nٺD( :$q#lv;Vٟ A$i[/r :Xke"Έ` $~ma|O׹ƞ\Hygkr6L݇k$o}!NYcoOO"֧QWaOp§wL"dr,?0=(|}wL C8y׻1 ?~;nC;~P3q׺EWK﷟~1ܘ9w~?9Y^Xv'k&IxkZJSLpppL_]C78sw>ӮOӏOyWYWY%u7/}!ϵI[q,6x.kbM݇o7Oҥޝs%#|Ƿ~ƫr_[lXrAO/[8곿O/'|41c\vt5Q~Wxk;4毈ExG#?N;,/|LzW~we90f/L{_%OޕS^ sNL_1όbNu+N}oϏ?wk;$dhMim~\}~L}QΕvT;\?ba 󻎆aڏa{ua9r?Y4e~)8cNa8NkG.Ec9[9>@|\Jz1hcoO]I:o˾3\_ZrJUn)j'EupG?Y^>*sl2iXB#Ls7Q4bb+'cK;}Tv <@Sgk.b~>g K1A{'{ɘ74UhSܐҤ;o64^|Dlɞߕ:,`%'ܞ>/9%y1}I<y*{2 fyN-l _l ,'%yKGƺXflI7;g`.f: R Ob{@s_oN>D0;5)w^OC_}YCIp{>RA'{gE>X ԇ0=u DuŐ~Qe`fLG;@LCٲKO;E5ĎA Cd2sHebZ G|WyLnUMp^'04i:w.ڂ-TK6_ v"}id.PZخ8(p˘<1O%<-]OsُK3{uM@[cGe|8?:>,Cߎ[Q%ɫnD{R awVBAOaFɦI0= Xr-AP|q}3;o雪QFIqW0O) < _3)9T K)02mA0ϺO'Jn0ەzqfM`q>[ʳH'f%?w9x)¹3ljboCo΂ 4FMq$M"?4y_[nlևZ6 +`Cw]s!XYg!s s9wj6i*Â)ԁ|ucÂ|EyDsmoWYQ\5kD`+>xyA?60' Z=E|~q[|2dCz>gPn1R^}Ò[Bo6__}Ō S̙E`)67"z4ؚ4([ԡEq|M9)GsAz֐bSaz>

㨄yyG/X^îGv+d=|NKR~ua|ʷ8ciQoFWHDM4^}v()ԹNDTGW,G нS9L0l/dtL(+̅k3jknѼO@}uu&ټ{39ZϧPeUz}2'_'>-5GWa?"LΖj nw7ik_<1I#[>_gw;<{rsX!k+( g"[,Jm>)EXF+Nb%#ZUPp6|a:Ţ<Ҕjn=XRh>{k.@z?yn_<<~m> /OoC? v;ѽ1,-t>O+8?/qƿ5߱VeDTq}2WSEB8niqImlW}9ϯmUb<%[GVwP_{ v_sHďp'sF1.a^nԛ臹{ow|}GF|=;`d=Ywv-cIRhRK0PR{Eߋy39D+|q=Δ7 sOu=C< a7у%~Q{6oO4~ljl۟iǭq{)*qK-;_{.ʔ8O(UC $<6 s'{J8 )aP&h8y,S~KXdv:*~Rn{W|&O]*~r}T*39o}GXWªܻ|(*~,Ue6,SK>1~L鑄kvE)—/$w?4>/1L|Oi~ E c{%&<,ޓ|҈3?)\TF>iϹ}smYh >8)#G"wnc'Ee1o!Ӗ"M%`pRnߜemZ|^}tirh_aeǯ{#WvG7Li-ޱkJtu 11_jL1य़xQ\T4|P+~؄14nBW8ipiYKI]=ѥi1Sokr ;?B\nF)Xy9 U?8?0S*F{Iܑ{|Ӄ6A8vI8ɯ˳mXfİt4GX3r-ڦk]m_Zօu|l|\2ZV._CI?8Qb[ bҞDFZyG˸3-QDۘO\n G΢2^͋E<kJ*sGxJK6 g`~\OHr|~@Y8ug/W+%wlJT$X9U^prܡCy8lſH ?;iw|pW9.a@nN9÷|+9#=Yޯ0ʅ\F3qnCkŦO|v1[\9 ek}q\"sZ}\ >WxA}Ls0g#ͣ? ʶf"6̛wa徭x)?x42)?xL㩼W3 &FGoEwG5_Lyx{<ʅ+x\ūQO<;_cژ!Dȡc [yN)'_Zw{,ORf{p|5iaHWvU}KC# +y: +ya~Vpfgh䟡;Vych2Pя8iNTkD$xe}S_ҤTLvpe̅7rL$!Y&UyQ$Ld]fsVDO:$Y[WeF[h! Ӏs"2j"GPrD -?>O4Tm1iAlNl~lj!gcOn֪[0j>q9gw%$"b~0^ԭ ,s--KS{UcҰqeԈ|t *Gxw(lNƒ|8O Tq_*^ [ex w9+4|IZu&[a%15f*Rt/7h}."iN)vYo`kyܪ@..oFp]fe  ur mʃQ* (#!Cxy(nIUѼceIm8#K_=mhډѰ"k"" \͡{PE?YSw];DNkp'5It-$w];ŝDNkp'ѵZIt-$w]w{rA%ղk͖NOEh^x-vдŅ5>li_ sw_΅_4HxhK+Q+d.sL8^17} ">>Xz2 p(N] # FDe.9\ۑ~n]3M.XvZ"7F=ck9P4)ҭPٴߏ˩7-^rMN#Ckt]&7yY|ﰂ64_nK\j$_DL7 s% ] kؓBljN<'޲4:8NqI д%襭qCvy}a{G.Iۂ?Ypo*iT{^ ^Zت '> pj:iG\1"-B?ϓd*Wꮛ:i0L7qF Q:#nB]M:7555uIU 4_2BZzގd-PE /ÒL͸󚿦٨/icʢQ U|ij_zw}_XdXx;WRሏK<~E lk< m0 p~q٭ڔ5|tN.ER^Y~{_[ۚNii]%NԀHSz E 5x~f3 4ϊZGg\Չ9wf=ļ4c1(K|߿ʠ- ͠w:}EtD'3ꊟkߋx׌# ؠ>w?>P/}럄Cl.LKk1nCXP, 3򳿳1,tOSL̟cw(ϧ5ҥljYNɍemr-!9HY>%&j>Ц<`h$x}*Vkڇ %qFaF`nSP1o`d(^b{JFqNo"-CzB WKӉ7>7opx=sdpfNj㲆_zm6µ,YѼз@Ė&sޭ^=F)v<>[`4dKq7i.߈ǘXoۿs7`n߀0oۿs7bnF߀1#o ۿoI|~ؗjGI1o+3VKBt7qI,,|>Gj!JMm 5ǛQ͆}~MK4ep/ovhiW[tgiP:BHO1iEƻDzqІ֏.Ņd%-//Y^N7\?8Z5~eahyFë20&=w0'mmHtlHyml`FgKt!+6Azw]jfV^-Q-Q-ݫu"^pbnYk\RS_>gy44"Kcnl?@#GWh{xr^s}S3v/k`M>vJGv_ncљ[|ؾL8pG,);]erK55CKyu.,K >HDht] ?@9_ѩrz9F37~{t>+˽xuk]jk}-M}ƣ+-0,_t04nQhV˚2ٝy8[wDl?z ka&*{KN{{3{S 8,}oV?ok9>0D9~xiiQd_:>ӫH8ܟ}<1e9SIns\~_rU.ZӸxO0 u.L=KRV5 jX{ڑ?l||um5"[34i,XHuGӂ|({%hn*{7qUpӼ)хV!ύ!}uwhS湊 et|۝:x6Ddl m.xؕ3 npW/6]X(pGDꒌr4Q`ZxM!Q#ޏkvX"_n!kq_q\Ѽ؝nZiiN@kIͻ~;~+Ͼ >*wQqۚ?jѾ8ߍG8j\7)EÏtllK#mKkJ ;8ƥ\~Xk4ѸQ5f^wzp7A-]wPzYӼ?徥[CmƯ]6۰ozY{O֭/g>^Z.Ҳ;|zuoC+lK֊&]XL͚ƅ#LÊuN䕸]5A[=΃gJPKU/ֳ]ZMy^F d^ȍ/o<I[̹U Y).jLR 9鳟P64'4<򃞥Gs0էR')B~5İs{ Q {h.yhUuy輦[R ]嗐aR R{?/|5zy>~\s9kW}1m?܉~v||<3jA;$dnߝS^м@kͫ,4~_;!M #m[*+c \ wn!svf4K}Z @e&L bBX0ϰw~ ~Ow'w 4̽fEgss a8kqAy!g^;G4]VsGъVr)o =Gy6z[may්|<:7~>on6Y5 -ĵpmI 'Nja y`#~3~E3b_ aΈWSu)3Blkt)ѤuZuHʿ/֨VkT_eM SӟiӧBE}.5nͿ\Qp=u:+!Uk[t+t\\ux\v|]3>㡳)Uzm?6V5rhӟiXM߰*JV];];_zwZrNj}󎨳սiAdޒ~gFqt>8a@;5Tx yV4k| {ϗG(MZ^ån<ؼo0?2KZyNd*9s,ZL^d?r%|1wnݧra5=oC8-& ^Ԋ#XD8 ϿMT1M,c~1 >N)wr~+0>Zb/B:CS5{9, (?TdNhȄu|6.[ [ $b.7B(r\ʳ|J`˟/yS\p1Οkapwƻtpve9O(-9Ӳ,- `iI}!qTWaqA8gqb߾5ݩ~ʴ G]kB՜L4LaG| wѨ?-6 p'J 7sODT^cK9 ~r@R0+",OmO\l׶[Y~=q{z%ݏ=7 W}܊Bɏrb uW_X>;?48|S{.Pw<;ui,.ÒqZp^I徜\C[08_BwVCf˰.\cs?>IwR]3Q8w~xMeɳa]fI~?mq;]oa;~>%? g =s?~~*Z󻩞STMlyIůšr䞪l809іӦv:n_% dh2Q8Px=p_Bw| xαx,(^)|~}7Kp/'ڐrRȱX:8Vcu\ZGvlVsҏd3 u߯v!l/Wډ!O=`5 \ik _r3>HTCRdL7'y8k`Nĉkh:&㡳{;v=+P(} _rd0M%D v/KYh^aX1_]ssa9?puOm*>`=3ߝ- 1K=捾Khx>ܟ{&>o}(3K}gt܅L[l(~Xx{j+tR" wKF*y>^C~WW-Ƚ}gOwSݾZn51^MG<5o;\R|c|WIK"LFE܅4È'vd[՞jlf.`Ⱦf~oZ HIoip|I7nY=+yr|?8?4I\}JVni ?WWW}}ewt*`d+= oupGԱ7Gk͸46 di> @wo&_rkoܝfw^bc+Uoݡ<pDؽYޫ{IW0unF߫0r 6Ц<vx#Gn/f7boqKFÛcvx#޳D{+̇j]==;vW]Ąm 9|~tkR4.t Z J7J'\=!hhԼTFj{*N>pdːw555ZcOwRgdyȶo؞;Rʥ3'[[B5?igftsM+%ѾNҤv  ]p-W4a4t4-]E;"OxyK[||SO 5կOȳ>ru˟~Ҝw[W;u)LqHiiHB973,@B ؓs y4 (G|=dM`d `ek 4 t=չ`ul ~5@U:ePkt3ĻհS,At}h[[+>F etnhN/.+Z9>xܠ9TXx S(АaP ʉ~@w24󗸰,A:}OW-7LzPXڦ?p\:WVS^uPݎnkQejt:]}܆f5V?.cF hd~[qL25UDnhXnoE:5 3y]r Ct s.[\o@~@ˁZF(F\]/W+r%j%^ ? ވ?Hkq2BQMC:=?ꆖ=AO51j5ZN|꿮醖Nvwа@ha|KʗB݉㸦f04Fڟ0}cCcxzt^5e뱆u#)2+?m!lj?@S=*@ࡿh W-J藨Ͼ5MohXY~0gR݉̃ ^˫mدH'근ٚju51 u:U|kj[nh`y^55j c il?tcZijCխ4*F'nhtZ=?o˖NgJVL u?Ӄ?[76Y9I}3ǰUܰ_.'L~8MUiRK;\mi&[??>.ޒx.yIkjx[oaymЁ~@w Q1?5(.V5kk Fݫ||nv,б=*_Jj.3,-JFWunE{ԑxmn M[\Q 迼:ko*Ѳ̺[b5Q~YnZ˰ьpzS/]_^K+hjYmV\WO zV.%ٶdnͺau i[Zmnb~cps/߷6QfD^}\nW_~1oR >~ʹ Ofcin[F\ Ʒǿ$X5*:WVK5tYn}=ghhձ h W4 4kZ|7л[AlkQlIg 5 p}m^O[yYp^lAP\(Z$C.hm 66ֻskcǷɉ?k'E:2 H?ƋtSR:ql:*́ o[1ڸ0w1bNǗ;}83@>~ f}yXmUXO-a<ڂJ﫦 Vm9x½NIH2cZ2!u\H,Gx.#_fڮ">W5Cq8pP^_mqa~cp6 3OoK#g42~`np7o$> oɝiz|Q|꼳_Wfa}sSsnb k= +WߵߛU9=Asxsv88瘴3@9o?Nkk-o t,~ r[°)kko}; ,mۗFg:c袟EhċHzM kN @\ ]djSy?g0a+NbiLð4a ߁菿>ýYӉZOP'X\?ȉx· 9&tp> h6 ͇08=&}E{?O+:4!ԡ agʬ)Վ͙ij?Ȱ`8dُ7aϵao:>fk6 Գ :gSW ;l n|w9Gji9R+QVu9 &-kT6T!Խ} E2Oq|OoybMv 8*oYV?Kå.2Z_) \?u`vĵi)޹5KҜ:^KOe9b˴*Bw}wawP/} e]X/}waw}wawP݅ebw}wawP݅e]X/} ebwP/r#+ZKgMx<ߓ5zO6lm})҇q0p_`610|g:doLɉ}<а|t*/ O17p[\j^Ӄ+{45a&օRNC K4>LG|CzYթ*9ԩ*V2e<KmZn+9䆮ۊpYZ<oc]vMSԊ5{KҴhiZ~igieh.44KݩH::Sk@ qN+k8-"z:z:k^g뾈kk2•yhe}aQ}aii}ҴE#M^ ]khڹ綖ۺ7Zw:y]U,=,ZdziZtNTK ˰]ݮOZ8 ]6-jƙҰ*{-,wHfi6 5TVą%T3>7>gGxVπ7uZPW@'Lť^SyYՉ~%1cD?ŎO)%[/+)LTHvakxu^_`~cpa=8Y[Ni-:>ymEsӼ}^:Ԉ5J(8cնp]x Ʒ[xZha͡wqYKzV|ÿMm芚fgJcGk#kw6ΰ2g3/i8%K)Ͽ(.J fW8JϧgƬ/;[MײxAbӼdݡ1mvLt[5׺oM4me)qVHKV|m[ ~ySZ].ooqo>ܮı7xd~vek/[џ p:wj|t^OSo~OՕ}韧S_v\yu)Jڝmƾ%6\q߽|\x^QaG7 '# [vΏ.&>=~jwn݉ $`S˵;[HD~ŻE5?W/oPSl|6~@ϟ'7z/_[o/cL7|2EZa.Vwi6+b-,m} q[Wu0MLi4I/A9J;F+wEuYն2C-a595'9-^k(LN/L'F"e{ǔ_s%~f`JH|*\^C ]ıa&a߉nnK'Ңt2_X/74y [hS'jACScq)49-?vh}K#ԡuzOk7`,X<3yů1M\rezm7:zKӱx]Ֆմ WBͅVuN5%t?JMu}9UE=\]7p;յ2V)Wy_q.qK/uuupEW Wk{./h%,z<*+~^~K5jneS+:U,oY MكаgmOH0-b:;xyXիkdESjh[d]BTb~VĻqnjE|7u-sU-ڷyEzTnKw5h4n:-?/TLold]{/-YM.Y+}ҷ{wf%u}=ʵnZ{\vixlhn{b<%b\fKo'̖#С^Bsap?込%\ qwcr߾KT|&]an0w~X1,^˰%aİ/Os ~@YwQFUw-kfkѾ]&|1Aͻ|w<_Z-~f3d,[TpK kiqMNoO^8*_}㹺1Amw8EhGt:>Q?}f:r&q`?摗F.s@چB4]:i|tX ~m&Sb׷5w+/M)?O~H@8;ν|Z{*6~}L)teHm4ٷ'ZJ64s:uwۻ<cM(Li K&(s'cRn,ϏaGt-73Jyv,{ Xq_ 3 QA|@ߊԻwoq=W^q^^#Izg^#iKD7:m2mbx<1Q?cI0spKJ?_?S{;uA[dUqMU!E]yG|WH|0SMK_P7Ӹsa,z:~>s~NS0}RX=H~aq_]0ODI m\Z#O_NL$XHLLZ?+̰=Md37r͍%x Q2<$a ^'|Xoy^4~jqڸJ br[ŰAa@t[v@]t@t @tO@ ^k{ to -н@{{t(}.c}rMO=mn t;+{t5н7@w tXCظpit_5}F_ 5@_ 5D_ 5@_k\}F_ 5@_ 5ƕ׸}+׸k/Dz#14OIreI^eOFm?~yz1/{#7 N :ݚq݈땸G׏ʍF_qm oCoCou#dw7Miw7 nD}wPݍQ4P݀wj⠾ ZsMceQnV <*7f1܍Qn2wcen,72*~ u9><k ^pL_ YKp$,n@WCb\2uˆxeüup ẑ׍tnõF:\pmCmtӵ#qvR HF4n7Fvcۍn7FVkWcJT~Nxy*͑ĆB# WdZa>t0ae|7_+8_CL8[C,YCb}^Cٝ/ ķ2ZI5_k ȳphGniG<-m t/k5a-eܨ4V8pmv +-/_'=:ݮi nߴsBlBB IKxk!ivL3>w'6IP WcZt̑2ިj:aeQ8#A +gMy=yj~B0j?j ϣ׀Z|t0|yf05S$N@V155.C@?x̊1xR.'*(_#'k6oEpWEwJܿ:ðІ< kQտZ3exd<Ƶh\ѼpAl׼9/< esL|z(nK'NM3)W1=%{B.MC\"0>7Jl`5z<[8?C3 b>1t>`b>1zͧC4y7•rL0Vv kX=srpsߝgr.JJ8I_9ԏ.^%;(:u'ے۷Oڄhޥk'ʁ2T[`*$t(q6H:!s_V -iۚ+|qV$Ep蜲e#=cV A2Aq+ \tN?'mGAwrnqY_%ҳ?Җ?8ss׶09O y~o; #[,;S%O"nn$ao/CEj #2oPNnAw?w?svc_-a[w aAxZ0rΕ`k9ׂs xqvӳY{p%l)M7ރ3n9=/ڔEq/V"_qKKx-?V&#pbqM}%q0TU旄R״M/#%'Kl u߰z_mx"X~KGA)Kh~*8x8qV9;NdRq"۰V|l2&Dkqba~`~Ύ'qq`*N[ $`"N2Nw:N On@}rP܀D2qgYdhSpW"$ZWڟZ@ڟ꾶 cOHWN^NLRgamEĎ ;>m#y+Gl%}ۈqm3o1j6bھmOطMzh6ٷz{c{bqqZH:0CslѲu([wug;P@ٺణ51IBށrXKBڮ.w5nbԓ*~>i'*8d'=w=w=wƞ;cOSzg)3oMڔ44#׃ 8D yFV՗形g>w+C-aW7< {$s&Vfi~p#13G2BۇQ۔#3sh}ff M”͛w]S⧯xٍSvtgӉd{G9Tc5 o9Y\g=:])ʖ]tgR3l)[Jwҝtm9Ѽ- {KٍΛ}2ojLw>tggJ8H)*_vX/\]c.1x\KXmc\ic|o,nUS+=?YHe;G.6| sGm5l5l0w6 VܶI+m?؏)nUZgmSce:j5w>f]srg93;'wɝsI8:BP]:WN)~z0d6[T<ƴ(˜^?(cI:Y1n1^kOV䅍~ : wg?e\L5%M\y#}ʓs"}EJ0%:}e%q"UTLe C)N,vQMyh7.G\v1}N w;w;qNu|C`h5o~׼mb_cKiV6s \LٷCtxGhІi;}^.)a>gpL!lZFr5<W^9>,$ͱ*+g|/3  O/| 4%%W#Yi4e,9|,%JnㄳعIgr0qL'0FsKܟLn|ZW]Iw}7 gԟaԟWS}x2,xև S:ڇ ^ X^SD|!K sۿͩijyʡy— ؎Jsf4狺rNrט'g#ѰAj;1/l3Y\QB<ghĘy7Nq6=OwPo}It]Bnz:P1B7ʈ;R{0 wK$#yF.J]j%brc'^7I+ރxx;}Ik{\(o|W=w+^ÒwsY,zR8_x|<ν*w6y%Hxxw?.ԟgJֵz_)kqLx~Hιؗ,qR(?}wo_6Ru_Si "K0}XO4WF"]b#=Dq^˘N 4CW2a^FĪ~ÙSv4tZl%ܪ~r|Y<9~K-KzYzvLZ17VCh_~F's[|.g;jς2_xir2͟ ZAL4f' ˰g\;!\4!ᮚF↍23k-8I~V 杻TM~;2HtKURg38-[ٛ-7$[x~(閙 QZZ$AnK`DFPӉJn#!3=m_t}x>2l F.Q {Y>I`^&{?|;v)ALꃥs!Y8NC%sq)jXC0\ϲ2M}%|M^_zʗeAI4tY6+: 5oYE~} o3Vy~b`],cL?:䠂x "+LzB 7ɅFG jSgڳ7eƁ勽U$!NL}5P=6iz-xR((,ZߊLfƷr B_*Kqe2_{YSqoq}edH#Cx_zQ; k u6b׺_Ryj :7DSk:5y95'$l "QqfN.I_u(cC^½7zOo2yxTd }ex ƒvQm GY\!!=E gQiJG"%_+]F+%qz^. ! xKC ߯ed2cKb.h |EHt'H/61 H !Oddqk|M밞nρ w+xC=0 $FSeb4֔:+ &c{}TazOu)ϻ۶o6a4*qލ= #k|7SpkTml/ỹ^:B^Tϟc=Y s" ,w֣Ry8߲\SG9wԧsŭ,kewbp\˝ӈtri,NiG|wK>{]9A #8"ҽވ{wQʄ'<KM eop&~zȘd5N~bvB+p##ͼf3~%;iC*Q8+O8ɿ~Mta1σ1wtǟB$+/{. C}I&om&o~{DYmf Qe9l7 lX9ґsliL#F,N#r h)[?C}K͓CDIs!scŅAq*~,=)[xq5_"GKtxioOoR(rx8G gf%v<;6n ٲ:]z wp~]+11~Us=j?8x-!kԈ'^}6%?zPx~% ^S};S߷3|YsC\]o{fgL}3Cmu>(n ui_kACWR\\ r;ig ݈A2<|^0Hrq;z3yZa&.u|B k;7Asn28|WO*n a,2weƲթx{'"G 2?ǝXgoy`0?򸯇t~.|QALu嘋J)3K\Q,8qyH xc,/ج !ȅכة8N0]؟\8'AqQ_~J˻&{OV }ÃH[D//3N^_Mr0*kS; Y^+#ǗX 4"L1Q.gC$m5`m,p\椱bt,'Fy'ፆbpG4_ष(2B6vP#Fqm&h=w3% &_3>*k$xEP*z ᬛM'v 4,k@;NH l߀85#*m530\N9b89 uV4 ^VK:869v5]/2'祀3KQnyF}r9nqTF5G1o$gD Sx6v@Ӕ8hxCq_I2ڽ/s`6S^ w!ۨ4 Zռ,ow!oCsx>v]g\ u p)}W{^&j[s42Nj$C'1&gx!CwN&i AA2 JX0e/O q9$.L8ϫK!.겐Wk`5C4yy=/_?a u/{qy嫺] 8/`՞߽D$kA1ڴ3L {;Ư T?oWl+࿗.GPO<+1_T8\ +~Gԧ>q@qgiG Tnrpɜ\V2Gr8fK@,YzIM.oK@`\^^[==ȓh3o]6'*YZKgiCW45*.;Su(k :q~|$uTc<01X YH?v51`q:.0U(G C}#O+8=>}!}o_)3<%1Տu 7usy}3=؂1x& 9;"x:xD i6"8Wl g\IFaC9[(eA)ϡ<9<8{t<*{ AF9Q8$?J֨B4|$x'>yw:lA0n1B{zO z[CnɅK7Oַ~6Uޗ@y aF4Ps[n9bcSS 9%S\Mq)^g+7Дc`茄y$982~!O<:@М#GApN.q'd9tp,:8{rd&ƹ]$#}gh'pd?1RFN;yPsַk&31I{&eqO83QqqqH_9~r&)eueGY]veGY]veGY]JyY 9YZDd;0ċVkg PP},h&|˹0$ F{9翘XAXc{IJ & :Uzp qptuiڄU6d}𨋣(TTsAVmLg;B3Z[ΨSu:u)ԩ3iZ$kg)q&[Bgp * eG]쨫uPW/Ϩ9au8h^⍊3@3>3Bky)0%/;#/;#/;|.sO[/|^[sF; y歜c888g..t*?&-z`C_)ŇI:xZ>t|+a%^zNwxJ9yGל[oѡؿzNx~eݬ\18(oeDyt*G'uKz/E^ybi-yT֜:V$ yRRO0}ӾƸh/z҅y8D,߻p܄ժ$OW#a5D㵃D3ΔVQnAA~>7הK!0;0G ڜ@bnL1yvGeq &6B\{0,xX7*=}#rrqɤ]O8_'g)c:YeyQQ}|ۭp xpdȞȑ= 'L-ƙm}$'nIl+ pc\[-pp\ptü7"nJqvE͙Q0KItCGy-C*>hyU*'+c/x|G8kWZ[{U /}I8)}Ne.ej/b[…o/y ef6QkƷw*.(C!pp89|7b7YqX?$?˘k,mРGO*p[bX%,^im;[_Ƿ6γG8_QTӰyx媐.U8vRLx.pDQ89 [P-7s_L{p;dLDmۺT:X{L k xN:]I~f^;Ω/K\y8<['/;`NB 3)!)9~d_7ȻFkkXNq[((Zҍ+#:A^]e8&7R"%Env? )?{w:;IV8My\F٫<Y/ܼhb$3Pb5ν6{~OK﷪1߹m djy<%ђhoo|l|l|lI>J>B>$ZO6ެn]b ο*Vvߍ{LOE;qQ< Hw 6cW?"^ ^ ^ HxE+^JHxE+^ ^@~un-7,(*}%2PZ͂w[廠p~M9g{GzWPO~Um11wީQ FpڼƳ(wGtKՇȽ?%-neY*F$ $'CxTW{kcfߪ3Xð/3xL,:ı=6S +f"'yũqm%!e/fEi4N݉cu64e$.ܭ܍2jˍ)S㢐enz}1bo?}U#[!h;0a-Tm;hr^A{B87g[7M}̉MYNۄa<+?enToHlHy=5Iivp.e:6X,fJcTg:;˘n@Gxm 3&TGWV ~Od[v]A*t'c|i}x2y,WKxӁXO*G6dM`zpM[5 rT̄sߜ<N`rԭPu ֲ1,&vl-@6yA=AnN2]7ݭ1Yv9xrjz[lqfE]g\ C,T}gh )E}gɮcnb7{)fIlt?*X_,s~WZMfǵS}jpRԅ woN\kb$}*  cTXfXT[!\|=E,}/S v}w k!.{}6+!/v&1|\ R;+T>Qk;)M+&A;1^8srZ ֞7 8GP>רVnn{X^*vKNI;P}zݞ`qaYaF$oFŤ!\ɑnAO' UG󔇛_tlfbv>Ϳ:!\7.6)LN/ujFQĥ钠c㑽{,.]S9!,$z[Mɍ]6X[K_ٽ[[mn(6sҟE{>G٫/V9דpeɤ_m1Thz&Q/HgRwo~.vx}zl$\:^ 6JA]8 ϳ9)S K|<;p2屝9 rS<,Ba oRe8𧊱 ˳OU97f=ɜ4|>H><(ПUŬr4[aSEgm r.{>$ˠo(H<ۭI/pi6}6N-'!!/L G7 NC9;ͦxضCkXC0bWX붛f)W떕g}yߖ#k #}Z(e^i"cƻ<,fV'՗bi<3ƋTP!O o 3=k<~Vmz~ڃ^P'<B0Z\1+N\Wk0.2gyC-탣9 |'Y0|b&NYy$Lw8G F9Kp㳖<u#*rIgTv'ꔺM:M7W_[*p5w,m5ҰF¤`b8ڏ!yx"A.E/eWk,}\o:y xP5a`:4sxīN]|ǾËggyb/r8n{Pw[W?Ƒ_䬷z"gG\y9eq-K #cy5Tf=%l5 V(:ϕ9 usY\qqUF^SX4\}8s!yqy8b;hkmָmJxvֹhZTNq~zm]29? =pXn"]G}IxY|ZŞxj|||sxZ=+;}u&žzx8N)O߹72N-$o$n;){ص\o^[01;?=R[挄52)z}Oh?jԁX=$]9`hmaeyp? Ko$8 {V*ko[t^}ǟ:$crpo9,{t°FZkD4 2k͜YKx#֌twwjJ~cЩjԼN: PvĤ`:aR8#?gzw} pql)}H'&xE6|&)sCy5*([hRh 9rp'lɰFx(9@5@ߠ8S3mާfٻNrQ-{VIO6 FĖiaUVod xt19ҪJOVUz1W)ψ2trfc }Q|xS{qs:p!<{ rl x0Fux2&]4%Oq[PW,x|)ӰbM c t?0'T̔E<70~'Zpc9 $[|BwycM/>4^Po\[4 p|;sɕ;h.av!ݝ>CyC 5 ۇHX1!cB8tBx<{]^„W?p­ 尼roUxR(㌱r6~F&wE[+H;9܇\r5[w)Fڹ1l *c}i5|py|v09t݌perphX =&ã.-:"~%o 8+}-W\oD޿W7%|qJ}Gx#A5FK]aN0F:r?0[/Q^"yC˷x#⻄6$K7i)7mt;F$L4oLCP3G!.|]˼^^)=Zc,vAlc5\(+d*#%}(aKrr\w%i9 qi$oxhmq0b/mܳ]7ByClkfǚ} mmCz(g#g.14ߤOI$I|0|Oб?F[k$LN2 fy]O+:@8/2& g=6Fe2ެ&V ^~^ƥ:ﵴ;LI7_gL+x|N"2(kWS k;Ӕ8-'㍎ X)pǃtRIeLn gHK5"va$X#cn^,WM k/3'ʿ]SO6}ա9Ja{zY,s/z=w]5 hWubֺo.>o3P9^7LuuVt=9яlퟭ$,u2w`sJ6 ZeCm t8(}Eު>4zV8|;l\9״R`ñ'DtPYA9<6e3_Fp1$)*|=^^SI]\V"뇪/K:dm*3;|ڶ|[+;vƻ[XMh W} d~/7u=ot)|;4=*8Dx/3@`Edzv02fggi%Q6tN$Wּ&߭sbSpw`:M\{Ӱ|{o:#sqQ:98w;+hGہ'~vj8?<<&CTKK;O pRF)mtmr8)ӓ[^?Sg*AIsvF4.{d}^!CvyNf<IC'3Kjm"/M+g;vnꨈG8^Յܟ\ȭ|OW]mp"եK*.h:9 pKɍg=-cv4k3 d28Ea~tD-$zKp>Mb1.Ki-,1YvSq%.%u}ػEWkvqθw]qTVv PtZzeؙ8O큠\72zةAuJ6M0: 0wqk,γ#"æNc:)$]2 +;Y]Ocv=op]^Ud+2 tXMK|zqoH[@rOSR7~Vy]_B7a;;RVZ~X,RywvYLe->vQ,/9N8ѰZѱ^L٢{[+U͏bDH'n̺1v}Yݘ"Q;JSh*MԻ7.ۭ/oߪ?펣ǵ_׽fv=1}p͘~NgFsY?Z3m?cO\<7SX}?gϑT>78bj\'w%Cu|]:(q;:#7ٵkQ)DN~>\27t />C32Ja~7؝qlxV ոd"U?luqZMu}F=#<<+$r'#rdq2-x=$B-aq&$Xp=p pW>>,'|tQ2-E}OL^na/|/wA'8_kCzv[ಽ/j\.s:+hxP/mNNG9=|&Tn_# ~gWkѣk$qKч]׃ڳ5*wJx?C3q^_WH<:V zpƕ'2W+>& Z֫4(|+[/UeGm+\۾o#pIԦqY?߯?+3D\sW.:{?Hks.K}n0;ms֚NGu2>6by4oβQyqQscg8 \γ54_{9~CvnD2}~1r}"IGttg|>xvZN CtE<\֖MG8t ߰#q|ˮCȥ񋖝]q<0Xv n9EQ{s?` g5y4V,^۞99_/AKa9}PYjv;2<l@ P#f$;ɾ>Pϗ$;b{[ml}ANcvmA]2*ba5]+ E1Q)z}feH q?;{~Onjpc k)]d tϯ}x]ҘgMj+u}+w(Muos.D,؜70m`yutb7Xܬz'0774A m.ԚK6bx8h#t{W}w40ZI߸9fJOoyAY4دϗ]uXIwGGS[kujY[nj?.[18] ͧ0x[1V\ cGjLG;'#/b>zGB:Rq#/)y>R׍@ڮ,C1N,6Wˆ!nщ3 q𶫲d*vR)W}ǛuCkwzs'NOOks7g45PNvNsYo!NE% /ȁٰ?v'I*oS?OáI]ԓ쵷gu<'z0.3;I69\ 'wŸܖ?S]>6dr%SƮ8vz=*'NLdĥy~EbDXx?yXq{\LIYՏf:c^ƧK{{:|SZ-y㘩dem2u/s}OR;z3y$>t60)>q/'mHnrdv}uWX8N;KT^}=paFubhiwۮ1z)8UQ2#·mF`Q.U,7~<~'/_7?YGܔp_GCf9mN6|YGu؀߾S+n5ͬ?``{^.ϥt\9sT$VpARcu- W!\Ƌr2~Jc3%=`]%.?nl ŝy8.`} g)7z~?{9t_J;XH"K\h:vilP[?WNޟoֽ-լ*mך7 n.2=NmvS[{vrQ㘽n$gVwFϾi[)X?'\̆TFXd<6jv0?[X3 ϝ\3LQyʼb}a+75,pi]tvX`Ssa-37?q6^.͍û27]Q[jKsq) #pQ7\tN_+}[{\}[76".KfM{gm']n%WrO[YV;{1SCD!!G$=?˅D$\s0?u7aAXe:#NXqu.H?4K2=Q`??Giv} +5?WO}a{l>Xqa\zo]K^c=W/N{BYorM 'ΣB+B>.j웨ӕr=Lo*CzpuxGAQkvBݔp'ߏ#/cZn1.d,SǸR{Jc_>llW0✣y"g"qT eXE`j<|# s8x6W]/9"pz:H] ::K?XSׁ]qoiMZpm+w u&)Gk7ҾF+п`X{^:x =}s/~)yJ:Ux %Ss5#.C$*O;]&޿u}OOJ=uo]վ1*!^siڮqveuuvAŸ^VI=HciqR&py_X ΗMY} kXȨ2sxW6UUz$H]f/{0}s/7"H۝ #=?X = p֢JNF (@~߬q<ǩ>(h,0iO=(TW{/punmY!#' :w9u! Yr.Gs@]*狲.mRgrЙiQiyچDlG./<˄LYS<6z;LݢX)~~}g>x֯/+.h.6w?gVlsٵ/lJp3_oje^{5ܶFQ3dҋy{ iI핔+?*v]. R ;1b;杳; 6hJ5W~цMgl&Sӑr.OaAm5{h!-~\g6&uPל/ݩOw僚y)|{/r]?n/=5aL9_e|@q&ü8ߣF=jPi8tM4wxTwtR`n9M[8woQ?QP*rH=w}cFu2cnǬֳqw)߶s`Gph'juv X˃{hnk{hx\O/Oas} p|\Ӣz@l]^Z>H8=~ɗ@_- %a[߃]'Rc~9IH8[C|SВ n>ݛؓ51dc=+x1=]<7cjƨIWGCS=WϘ|>0/g9O;$-'{z Vsw;9;_&UEG|.@|. sё?1>hA4/yG6b {n% z.#Y1m?*s/S"h~єyWY6-M{z,aaqgFl:_8^F5'OǟPq䍖/< sg0ݒAFA7#sBPэ8Sч> 仑یfLno鉾!8DL9Ƽc1Gsk/~rt$_RZ%~wAgI(+Fs A0Kn* }{0BRt~`RkWV?S~k}J rT5<VWJ}J?)k9XeR1_x;>d\?~cXYRfZrޱd3 AR){Hu_j))G^Q|{(_b,a~Ȋޑ\Ob{,_rWY" }oa9ᜥB/-a sƠR\gaaOb$h.Im)G S/ܖr1Icu1C: o:4+m2 ;`j'b? K_DH/~gs8v+m\.a=s6fws2u])!B$}LYFǟ Cj/rޣ7op8W{+?7`r./]/u't~z7};`hMD6gipYzM[]7 'ޗC:)K|WL|+.+(B{ wo+m[ӑއmdnwJG~rstU {-Ra_V}*Us*Q~{OVËoբvqV'gLTOw}p=LE'mdne)]o9WRdtV'_[Z'a> oR\:.}vq[xki{yt}VSA#k>֫b(G v W7o:,YY:k<D}B<>xЫwK[ZTYy“S{@gGxJסM㈽e:uċyo6#:2Ki;wk''nր29G6@+G\RtT*3JLh6k39{3 W)3v).p YuSc(O3;p~P}/-zg?ҹ8Kc x*Ÿ·]kI}/e>z-v=PW?xeJ\bg^\҅e4)\wߕ(+ E JrI~9dfi /[Oq/Gey1%Nw Yd)/(?yX3 ԹRZk+Փ08L^HiaMvR\_vߡwT.Myg[o63l~qg~oþMn8Y'pG>-'H_pNqJ>mg6@T?Uuk-I6ד:جVuatoOu w'=9-l^S?︟?OÜѬS(;d-'\9,Vao=Ck[Go6-,ӿgpw!E/v{x|vzbL~eg}ٚ]<7HBQ ٿ~z:CL.\-yrm_116wb\7`y|~lC^ܸ@ydڞ#YD' K[?2m~]0fz>s(L.ؕ:,r^R;U?iM97P,`b]~/؝S"Âj:x< wQ~AE$a~sw^}+f2RV8fR?FOd.t(Ta]MGoGouZH3𸎉vq+>l<;=RKM99=[3u5瞢GY;6%=]!Z]_\⼠W?;bDo*]4?û`j[l;l}ovff G:jՇ~XNο{F7u6}J V`3xip4FA|{ڥ5~z㣕߷|-!PK\`oOZ+FV}h[Kq,szؽI3Չn: #2PfѧeiY|zքil}=ޟL-^"0bd}<Nj`/ 9lqw7o S Ab?ey`{<\?m_?b|eb/{=1[DGj|]?>o]pn1\<<s9-o'E8̀lڟ Ƌ{>'~8xhŮ$d^>&Y@" ߦÐ6 q8_0e&.Lv3x|$oCwi11E1-p> > 78t0597Ӕl0/['N>MA>Y| f˸IqGAv (,e |̺o{K2zsA~_Wvz&a=ns6gٗp=`d&kS nieʛq7|t(~ a#Jeqp'c/dlj11SKycP?eQ9Ac_矆ϋO>MLς.Gy|]Cvhiٰ)s77 ǁ?:'bp>~16n33)2!I/P!b]U6ݙF Tk;9&ҏ9 w߄q82ݝO %Ͷ-27yԟQΞ>rvR9DTBTXb~r0XYTrN?R>"f`LXJQ. &fG :!jܫ[S}S9fb熋s8ƈ>?sj|'iTfaz\d<ʱ:,s|XWQjH&AlQA8(C2?GOʰN"7ẹ 1Ө4K9i)c]c3C GIf@j x:+*2>T$=Os/0p0k?@yiϟr\Zf̛Owwr\RgVaX >D F81,*9bXM|$|;~naE\ߙV8XIJ{t} ffefP n 6L-᷏T;>+aY tټ)-XD?'L~2xH?0En7☃x0&@ 27gAZ3fcqy>xrZA9\tb2M?CsNgf0u ~>oi|S9`^uas\Ҿ=5 {t ?Nnbx-&]>H[.fiVʋOYixK1A{GYxe" eޛ510޸?qQφLpKWc*x}LcMoM{6 ?/M`2"o|o|9go|fgo|flp!׋.][/8^trL@xlk7|ܰϦNf/:az039l0, q7_؝k)ۧYe) v 7ge§K}eXNҾIڀ ["ThXUñe#bc.[8[9[:s[;Dw؅ y?t.'pFJqh1H.:8= +`'%wSƵųI>_{S!㞂͇0`7!u3ia*Xſ œНHW]|Ev^Q)9; Kv8zކ&@[.<QNL\7OtWWE~Lā ?j(>oC狸]cܻ5 7E77pt{#b|w6}#.mh7O?12f]m?ω !{ĭd" ^g:t.~SV(?} V=^OzN ZHx0Ӎ2/O9ʼ<(nnZgfl5u/V 7S"kٷvTgq1=5vI:;[gkx0V=p)`f,| e61Mﶘn ]p&MIOOF>3A>wsE,I~p%yLn ANnF 'c^d{dٯOmgk3gtڌx6?=a@?1ȇ/KOɗ1y +_cvNs{ٵlA b~1}LI fϿH]vU\RZV.a}Av#nT/^=Ol(C*A6GMTCl.Ȥz$> /7AUSh LE4"j[t07K9fOSY~']gÉT[oTR__~TR_)?+(*)+r??r~g"u[[oDp<̄1}+XJ,&wB_(#IG;dddd (.XҿUw)6ͧ{~kbf$_RW톼4n)ƌ>R۟#cgSdnDO? 񾝌FhR>+y؟K|0U_ٴ40 HV\c碣ݩN{%5?vY k}d!"Z/:tPO `'eѮ]84ev:|7wjo6YɊ|d΂\@{D={=yZoϿ_}{Mx7v/`P 7]hC?76Hwok 얲,*eY5y.n?E;{8d.DjQ`]b9s7}yQ޽uesnM緓}3=_|>Tf15iu7hsA_tD<;#SAǁpLw‚|4Ol=S/7/л~7þ`Y#~Y:ꈲ%4(mXذv0gbda{q4Ƀl]sqΧ2{ιpXv{O|Ǚ`n7'eV{[4ߓ8,΍ =,$=I6\Q{,dJdC{|icǷ_c0qy I[sB[c8ik GmM~nk< eI[cqm=ik,kkRmhk4v}ԟ Y`8w\vN.ɷ.|.v02gd"UͰ0>M>F~%#v {tXK7ťRMq)~(L ֬S"{/'3il_YC$N ?#^@|оQ∞ :y{DSw˟nk8-bT lޞ*;S܌۫tiXAccSy,@*6L@rH"6xY72 2L2LttgXnCL Oy|àe#Ss`1Of&@f=k^sv_zk} 2G.T(r{x|6=v1Y8s+Ç{J:^cSOx_힜7T\q٥_=n0yˬ?ucF4b06N/a-i+u_WG$7m$IDzE4x/IS =uZբ2ϼ!2D)*̔׏nfn ԍ,}_ܷNCowh3РR2_K fѓ ͜g²#[033-5>O ?X{4q{z̈́>sk^ &{ppJN,zcR: C}\룸ӔmU^=fFcTm~bg ^>'a{־?@wFnΓ]˿濚o]#2 J=˥loy4~ǰ/΁ҦпA~~-. :7RTjFUλaxOQx꫟ .f87RN̨!r,xRԷWB'",yۺTm>dwoljHfG֜#m/4m 7߀oNnmoZ ȩ~dmEv? +/'jLh ^v9#`d Ž@l! GՅb#MC]39e?wt}o&PwH}lSX]\kNOVJn•ʑn?XY8Yjf}_ৗ].;z~Z .ϯˇsv6=Wiu Eђǟ={L;;oj^460,>R^[8p5fSW+#)Ϸsa?{;5x\(òuGC臺1.?CMM2Tܸ.y|Z]_Q=!{NQ\F{^_cz@`\Ϗ08S_A'?gW7&G䇿pqyc6gvpmYmoBd58v}O_A^%'$Ͼdz&͐tέg3tfP{l{2:ʈ?RClNn h݅\5TW'~ړ5DKnܗ?ʇ:u6P]˕!HvxftA_{ cة*w;[e*2;Ԏߨ;;O{:?y<\;ms[R\CR-3Ԯ)\m $=.o.f@-Ⱥ- FSG,ޥ7mj5øV77'$ m & ?`J; H<|q^ޞigYiFV\{}67__/]|uL]֌.ko_<~ې05: /Da$}m"ӷ˩sWgB-Q},[ wm<~ɳM^iQf#}O{;|*Oi>Yif(ÛF1o[xHu}?eOKwU{|ðʭR4k&o˦u~_/DTG%{ST+ٗޜUnﲷ<_fe_ۯ/4 ~WmrN%}~dao*:|.!? EU_!)}!h bf@`HEM+nxZ=+]]z9FO/U׻Jeͧ)p3Un?>}B@i$(w/&7.o'E{5M-'7÷i'UN:~bt_^}zۨtOgLF+~0F͆EUR鴿B(CY&8"\T5ƭ6|od`MuPX(oA|x^uWTQ>gr]V4?FAnjD>(N Je勇K" ]r] ^(rTqUloo~pxtt2U~K__4)CcEs:I.U"Oʑzʱ uVk~)ӓ_/Uk:ZQ[b_yYoU&}KN84|jɝJQDצ~.*ѕm6J5g-"e92>%O'}ק 'i2 Y3aYmHfMe@"YT(ͺG C~v7{K"GzuZ)'t`@PM^c+k #d beěܶR?%p£+xݿo)KT y\%4AqV9 Ibm?['|nA2[|*LbH0cC]( K*Uά)?^Udh^NPG,>M \>$!iI3dp\)Zw/]ۢ*u)Srdb?C2B~ d1ڭ2o۲{Nb[j"\/2Ry,7Uei@zؽLueu@CZ,J.߬e9 Oi\2O`Mԋ6u9FiO>k!-zUìFB2?q-6E @X$eH/f*Wl'&|yͯuȿ:_!OKT.^>%#ʱa'16æhd?h~.*Tm5*!6rAңhVYx}WNx[ΰX$с sNçq([vK #11Q"uՋfܢ~dn}<5B(Z̈vq4r`KW\kDߒS cC0zeg[eHqx`e̞U,}\4}W٤rYUtCmUxabxa; 2U3&2]fnjK aJGىTl7"ySb>5a3ƍsx',OXyP}-kt]r+>8ք,`=32 @ub=T W|mM,T fP6 FE Wڒ5v- 778]5jLa(eY>@Iw3BB?uآ$vI#3'n8NbO?ס_G&oY9^BMr64-`\xg/sAt$u7a]<Ҽ $,c&6p'˵qXd`;7ϱl.؈*x? A$N9uu<HR$ ?|Pp|oPH(mo~~WG uD $K}GXn`{E-'3?f>ƻ{,Ŀ0yG~/Z}Hv< Br  }2^o*0QÎȆILxS{b`ЇG<))ND?lǂY %٧p~-QY7j'aS$c#} `^PGWSgh@yW$6K@a&d^ $c&#2([ F8, Y;B;2針X21~WSf[݃ L;K*w3*:Ckcge79d~?/G7`WpD Ha X؈'rSXڳzcX/ ,dJėG ؓzcw(.2Z@+g;17()'yj.?mX\6~X]=qnNċ; 0TO$i$}OI3XB¡HG߳]w4鵧ϟH8*wEy3ЅiCJ.H"uF:H)~η3\NTŻ3e&'z͚Ǽ~Sahŝu&[òܳ"Bya!+Aq@8!zJOx?JWPMhJ84|y뒭}  D3Ϫ`b}Fd{Ȋƅ/#`׳Bo@^dD)஺pÆK( D ,< uxΧ],x3qa:p0) |мwgS!;_q\?0 ehPF[8̷@aQ`s4-g\koRec7OӰt؞$B ʛu]3>)$j|ܸpyVsfOl 7{v,ҋ['u~nҢGh DEhBn(::pƗF=>M{fr*iXCeu[ٿ=ú㻻G%s\<2|ع9ϔxtܜpԼb957muuؾ=BDk-w rӅ)&m\ظXO;6igT Jw]sǨl\TiM4.fΊ͇+&<6lE*g44!~k17ٹ|s:ySɳkB,/ї=[pQ氳:;|̍r}]9$vo UZ3JfMӢvDt@vSZ>[#Lިnl͘PcnF +oo׶hڼn`@7m{:OtaG|&.W]lω(QlgN3B IL/m z@*M(і&$zoC{/˸P {GE d덛W$HuKh&Z)k!wl0pbaD`Ϩ>@sAA'~PD0(vntF z{fOED֕u[4̊6v}˗tcb] K0;!1H3vtn&`L6Qoy q&Pփh'qD2{B?^g TUG+[)fWXdd,#:G8וE~$ ;}=ij  .D'ScBD<3n3V{$ua(bYaP"!3"ńCыQ}0X`sY=rZ p߭<몱w83oZ, [l{$+GsM{^Uo_(.MdͿkf&Qᅣaf00vKVgSdp+M oae} #[(!c ##Xyj& ##X2- .3U;n%#q2շ'J@ĭC[xg_P a4.,uZP a0_yW^|e0_yYȒ|嫘t= _<'rBɾ~7 sYˡEF__?&hU"Vk\"Nn'j }N^Uq aaW7ۿfym42 cPM42's)`!qfbA6cG)11(Bl@p-gS4&h-?Ii6+z+{n@Wv~\T=af38:C #Sqm[㹇üF$4~a;s5L\i<̿q!%}%>h u(qsaǀO(L0CRH 1X|_3Acx65eȄ{Yya%l<6 ` `l|a̤#,s|8޹CA6d.B!=""ʱ<o3QkIfoϏz}ξ>gfoϹ vż>g`3oϙ7s 9\z}<ޑZAppÛz_CXΧ/ޝʄ~:K8ls\ 1\Wssa1a+B;8n.5YgPi͒U^5O)M,|nˆX%?S G -#f! qq[ɽAN&rr@sKƕpjޜij7ZE~bx7֋h2Tψ-Nׄ'"В|<<rܓ*+e̿ CqV %sd`9ǵ8w2s w{b ^zvI8Yo#a?&KNmomyyV:)7nD2,LHigz|g!o?Q (~o_^]4?X✨x,މUW:54 Y\t+B/a%ܹNGq[FIr!4pW$mha;]uаc?-<ҭh.S'uJ/qA,: !9%&{$!|鴟|v#ipIۧ;3{N!oUBY(oNt򪦍D?`+u ʷ'\LS`20Os^e^eMl_˵ Cn%$u ք"?3 N*Jy y$ege Ořד Oغ>=cK"1Cmf/` cgٚs~fƜ1gefY>+ Gc313Ľ93c313Ľ93c̘313Ľ93c̘313LL:3:3gb12,`LE.CZ"[pM,%%autxd=5C@pއ$طwB|;aNm=icz~`"WwS2%s R~7_0aZǴ<!=>8Hɼ#鼣_44GH!V4GC 'u -j#][U`.P0z)k8I)K Ay\t @)ϙUM|O6 T6Ԇgoƫ8/%{1fx\HVVy⾺ԟٕ}ɳ*XFn=.S 1V4mES?;S&/M>oA8޿uWYvc-k~$vhDP{toj鶁yq94<MŴME:ҮvKaz!}n߯Q We7ͥݳIxWp>:I$ow& ,EӾpM_[KOLK׍;Ҳ5H\s P݉Fy8F ̾e{CQwFWpϲ>Ge޵Rsں#ROčlTQ~دm_c"B?sBp oȊJ 5k2bs礭Vgo ::y g0{t0jex^%s6~SMrۡi?5OGzb/sn0hB@Z_}CސZ=?[J(1:dy8N ܢ ~um*Vzn3#]8T-;@<a Ln>t<_Wo)b QCWTMNT%t`fISMr|[fe*TCW#ufd1Lil̈(-Ir xt,eSY͖G4gd](U׋g ե/hPu&'t~TKO=:A*K :{ zDAؠo(sy+ZaIdalXc`dޅ]qKa;pwyOC,{Leuޡh3̗ >∹>]~?_la>i"ekY!ܓ_B3+,.Y*`y浀/Y};_gθ; wgA]=;QdrVLY0x>gAeClY0x>EgY0x>gY0x>gYHx]xpO-i!ȳA:"z7a `>^(7ҖCb\ Ì8q:MGcu#4#zS'>_("I||!T^zy̯ :&7Adjw4gC "Gc NPǟAD&X^|c_r.]FDO8]5cwUz^MmcS5=f~"oNIS">s+YyWw}vҿrx29`ԘaioH}\R|+.;C4øfV?/OEk Q_˳QҼ/Ez~M>%k)'Ym`Bs,mD8DScaWeFKx:{~GZ+kH 9CUBJlS0iI{(ϿZtlX^\7(]K(cu~v0|ڞ6Eյ7%}gv}9'rFXO=Cن{xRxfҧާ:i[p_:O|*;tF6Gu;KOuUR"2ŕ;\ Z _bǩ=qT12݀d͋;X/ V8FORž5v1ď:n.LNFʼnw_lmߟ֖?=>Y`y85ZpdLpIʰVZxJnP]AH*d|Pv1S>폓MQ6dCd?,Q3cF+"&! 2p:/gͪ4!s]^Jw~|zcaT݉~ ^t9;881\Qjrѣ'/z]G̝&Fצ:㈬fp}TCdu6zg [X?`:xX 1!*c3\OXذՀT Շ6ESFbګ򈤓%}Wyu>BDkf@ٷ\X=HV:Ak}I.n _!:C}WO÷h8C t|IqyLI؆̓m:J>ۢ\V5=xdxEq-Kz$QT;y{ (vs];~& 063. 1gHַ\Q>쵭/{xx;ʦB\UoMI1x{#=q8ΌükjzZB+Ezb*E.] }]/P͗m\gtAܮW[&Dnu^/(ԨF/\qY>ԟi*/:"xwq-[uwx+uZ9D~G=Ȉn\ `hݳPWmJHnSNmӄ(g!+9̘֡:aZk}QJ*·}P3M! VţR)7E *|g.,8W0UK*Z/ WWx*ٙA`=ba3 _>l Aiufr"p=z_oc#1U5!&?us$ ԜԺk6!f\z^dax:IfK Gǽ{7H]rj6½c {J[ܾ^QJ %m0lsTQ` IcD7~z} 〝 rE`#$=$Hw{Z1NNNi^o'!^p;eaY;WnM&F c)sm?la*L:1@7'vؽ}tw6P| o1b@Գ5Dpj.@dH{+k)@l+vyGMdN;C%uŮcL$JW Meatd96cm8'ozNK^MS|}x8j䨾4a6MSB 􌜟LԤ4mcy@⃛09Hԩ4wܕjb-!&W7f}zӑOvQU3b *86g+3C+Hu*|H;Rv“aӡ5;]2[yZ֞8Z_|W{Z>_ umJ~O4OL. Un <=qSc_?7tonbWo~[D*W9&~k[-O-[xyZ8 z;-HnZ-9+X/aL誼7q .'"Pmºa G_ fϐGJ`̷=aWmCM Cq`8 '#%u"_ ;_.~L&Pǣir-Ya ̿7{!R_MHϓ<[Jg nl)7Hkԏvgke 4f-n a}pgo݂;du}Г"%uc ^Z%!XQUCM|hWܦܥo>6_\w:pG{طK_V[_ {),nh|obFq--'Ф޸W,Ӣy@kؖiض=T 4U戼p.Vcmqxpk9Oڄ%GlRmb]ÐSO8~npQ,o[!j[*g6r:($%MMRaOzoƴ?:;g*i|B7U8hx2[䴃7vHn1Gx 9m%]YPg ߻1:{ԳK@nmߣV9*e[;.g~ow'~Y$S72.UM` ye S Ljs%=gEk @[ŗ-ۺ!R6y?jץ~ ={2qrZFy{}5:K$7CK€sDo#nu@Up+x$7 7|Z< c\&ilCusu5-bex&r3x;/m67 7lRw(tKL]R/0n($'78 xA-h|Nv+X>[ |s{ U moe"B:Uԏ`cT];.yAxo.0rgJM%-bqd)AG\2k. b`Ul Adkf|c`R^ME7;6`/Ysprm{tX o>1AuL|(y6u.or#N*'EqJ9>ZngLf_߆방=1=TNՓէGP[eX;r،IN{cL'K{ujk~{߽vh XOiUwR;'mfNׁ植I;o 植9iIZ8i"1xQ$7`Lp$a.c&d[ (o9$빫`Ēw olԘjB؜lS: V'#{{#Z5lQ62= c'z/-M}e{"S95g-"kx|C&:,j&6Xf!,+Y\6Ay.;+A~{.Eadl@k,%;A-q{}1;s=ӎ>Ve64x[=v%o{8 (>߇ʿrL|eWBev9vg>p5#|L|S/K5WuZZ .:^CӚ Tk<2L[Ap &9KPcGwsXZ+^pGUǕNyQa&ݩr pycdM|e q#ʭos{qmYՏ;\!gktKktND 4ukP>~e`Z t՞}pjMVƤXx=TkJXϥ5%Zuj4.LqZ#8Ԇ&Lu6b`1Wy09Ԁ\5`7'ր/րLo%P3$wK6Sٱ.]cEsƏN$tguh2l:Σ0?ms&}J; ˬa!̻ ^-fúy~-C( +G KXCs&.Q3M <Z/`X2Mq|@t<!Qnv`vydșz@(Ӕk^NרA@:ӵf/k^ךdioJr:Ol!^d2kVn k#z*;@_1/ߪ'oGߞɰzV({fHf]8T*+{v*q hb_ ѓpIJ+ SB3lQ߇0&߄xf7H\ #c.M>LiS8IXzb 6<\!ZyY(a7/M5.lGK LAƝ~AK}C_:8rp%v[ymҎĐ+U"+.H8Q⃆&` {^{ :p ]<h'ڗtC2:> }_Y%_: dfq#g\ j`OQ:CwRy9lgnVd0"8@֍cݣBx]c:N#d*@yxۃw9]sWɄV8CBL"y}鴤g' ?U-wy|0> _!5oV&O_i=XӶ~vܠW*B~Rtq̛&,UuB͚O'%&mOemb޷R'եK'N93 Oˇ:1Y8X ײгCB8ld|K?G>WJE!%uLkķ4%Dfr8=31a1.c>`LbˎLes30||DE u+% y=p0Zuf!#!C|@I|=IuT+x3^ٍo&̠].2:#J&Cg5QksC:]4DM8"5ZM:Z.Hmmzvvw(et+_T6k-67=1rZjۈͦw3z.} ^Ԉ-ߓ|Pn{C}pN{n'O*Ym"wҶ8_jfp͆6d>4?d&Fsw/{̼c}U[ZcΟ (Ks\_3l<_ouPbHLTKA}vwN})a[$>ZhHn~x݀,MTla=r⿩AhێypNcaG'n?V4 "8b8=TPd:u= K>|qw=޴ЃCx 1,$v,_׊-z򷗫nc[E g6 q2kߣd Zj Gc/$vJjz(Z%wFX=TizN/j|=(/`gƎ›rxvID0 ܡ`x6Ŋ(,K{mþvAbЄ?-JxwcxV8B?=^fk}%( T튽pbPPeO('8ݎrcRi<2 ZF<#M?NQmcmw` M#q:˥*8eE!ro/-d?}e.YN:ϚD}Pw`*=ϻv}xADb#qvPÛd~ݠ ӳ׷㺆#s3Õ#ԎwlHM5yv /ye[Zzyh^8tj"ts#!r C8qQ tbg 9p뇓|3!8RZ݀lru#|`fܛEr`L䦫7Iܮ7m8'j80BhIcʈ}0T83Vgy`cuYcu8<۷d~1/fv]foG'"*_+G7xXyXB`X$?nLްe`RPk1kkE"F : aEIN<ҟ E':IվOktd:%/:4hur5Œ:#S7=(|r|AIMRRF0*M7QW!IcdkajmdNc]^xSJGt%\iݜB[I

dwl/ST]T<˿~˶AuPw L_.>_g idrvN#:׽^?gCNRxJL܇OqP̥^fC?I!PDX/Kz~ (DXlmɰmqrv]8V HבBbp J]\*h"_uO]գ א~f~yz Wkp)/~ayy/ ѷIﳥ=snp2s >:_Ν#CH{D:n0Pן)ZV-*ωPYn jÓ24UM yp/7m&NtpDN;f E{zmBC.svrC~(ټhÀ﫳钚GGc!M/߽eAv<-`oy]\|3$ QᑴnqTy )2w) vjHQ) A]J_b1-M9x 1k˸Kޒ1gM(<% HE!"~^tXJnm~{Mߪz1}ɡIni6aKg!=Qa4|cf>n}4M^S˔if)Vn¢O'F-#_&¢;:,1gMz->~C̳3;a'Jn#q.i<NXЊ=(3AyOh3y? Fϼ)9.Vs"n&z;pwܡ{ǸCv EҖƑD7hΫӣeI([/ƷK6>wUV}5G{eDWt0Px)Z+Wu5橂^_7^Wi2:SOY._1ԌB2vg00^@1GDcp4M XxaV"OB{ d#B|$B$>aOt& 'vK cvi.pb.|]\<8NeOCB-h 5I][>|M/A`]nf# {{hiKFi7,aʠj8;] C\}ǟ/|W/uSīd1so!VUf1G8Zh=' .7]Vi-9f;XqDp@ ,>;.NbNry란ޘqkn`҇nh-_ӏZ./C`göa|+zuM{>ҸSݨu_|58눶6+ʆ֧1="/JQ;MIZ.HD#E}^36qfSA%adp:LtYGryem륅ئB[貃K*D \2h;7Nievf9d)^߅-z{pue[Fx_VF'L\8>5褞 @{z*Tvwʳqœ̹Nөk!>Tnn?')Smt{c3~|b^j t5*u&`?"<#x f-xgdKZqO{f4c^[S]5Խ}XtcXAA}ºCN?ğ >]N_EsWGS҈W'0~|*<LԪ{}ys g IIU#70<{&lN y͹u;;95!5#'nGLJUdsxL9:=W)\C~5 H[֯]=m)K!nⴔw>LcUn96`ӈ0 THBhauvtxO0[tl~A9L"Gls7: q^<ߚu ]q`hVYc^r FG0wce[LVjxm|z;4Syx{놆A9 ^&!}xjjتDzh^=0:!n{^O#sXx w Rgl3*q(z/Ϳ`򯑓kd4B8G Y̿P a<=yzh>5` M U{#|.!ktB6>b &*\0YLX !c }oxLJs<沱:aTY{۪&#s~y_y~._xHS*x?_HK)x}_MFB2 BL?gkO$)?g =7# ~8u;uǾ~I1@n_dR`?:$D}=>}>c&,7II>XJ _>~R|b 6{+ }xXu#%यi?{ŗHaHz4!< M :Ҵ09›Op)i܍\&Yuɚ5](\ށ)oC/^^;^[Xt5&6N 3nb#e)Ҭ'I_}MJ%f۴vFBkEVo)@y]uC_RKo]O͎JiNl%r^9IeA=(CػuػDu810PB>s\q'F!VfR҉]6]ߙGJh}3'0f>}tg#:*ʰYP}A]z.[z:"1MsQC:Xl:wn Gbsrx()^@v^_aOB/.+ {#Pb+>밥~ r:g4'D=q—X/Gq.zfI@m> '}Ӣ5ycgбըM'y `i 16''S(ʪ^[0 @~ ?(7Ec_al ug1s_ܴneN0Z"X苀`\) O&[!B|m5||O4C ɜM(ĺ!s +>Nr C!@R82䅐nI ĻcQ8u/U&IMq1F!pܱN10yK M'_gb.û\t |pbw8%[*;4@" Hf]tYcA2!3!hҙ33I&]ٕ+*q  @Q:dwNƛ2P,(iZ8\)#,ț$=*t?W㋾i%lQ8:jSl8:|V{TMOQ{T\TOZ, /i@1_A߼x&#g1{<-ykyȁ6#Qjf6CyiZ#Ү#Ү#"Y2 foo[@ yyKׇYb~J;~JI>{N=v˞S$i>9=M:ST:vmKDǔʡ"dBH:Il)Qd,s/]~?~Fv 9LDI6§DI{]}]{CD)qldjAC I !ّGkN=4[ryFmvR蜦DInӃ1GGdg1Al?c*;US 9*X}NBBB;qvA W }.5c<}K]TNHurLf7ThKhuyB mv>yo-{~[* Ž}mbBԛރOnx4>n,Å:qĈj2Ir}Sz;QP"T.n|lËiݾ4sQL|wr]3 ߪ%^G_ Z `<@*UͻVy{%Xl$hwTIy/1+ݯa!Xt}PRX"yTsp,P^.U*USM)98i'4\}^ruN,42/D;'IM&7x ޚ4ykbTjr\᭑)oh%RyNG/ogұAB&A2O`B6K庠 i<-)X~LJJ$ P"JWLLZ̪םLBY6ƨmQkB֊]'W,\WrQ)z!.zi)hᚅIXP%N$T8EDoIZ<̯h4J݃uȧŤ~ھzgʵ0$4@hcLɍ1&7$f"1Q$hreL1:*,"x}=VE xp9pZ:`AMMBK~ߙEɹiR[\bˡSfx^O 5Dɲb3 H,DRN/R>ʲ:cQL Fxw+ VuK^g~# /|>#RfmH*U i $N}L|& %7}ސxl*PXm;r,I*P,!mB20C5i\{>;|aSzę%PA^$/%sZ!A->ӓwm|T39SK'S!ێvqfѦYCWؒ izxag| &]F\n:_&b%>LV![fҳ:BP/h5<4 CӢ| =5/8]m:{ݸbǵ;mxzGO5DZvmJ4̚,e-ݖ8l0)g񖾞כj_꥿bTj%l&&g`VUdp5c~"_*0uRj{;hO+.>Ӌ^ l~L/ UT:jz\j{$gM_Hʃiѵ0L} 8ikaX7T¿wuLF+dQp&Z*P*T3V+ WIWP%>-8_]r=dn zo@śiy7qiܜt\G snXS'DEՈѯVgLև?%ͦxF\pO7M aՈ.b'GHgj0%utU:d?Z ,յ:i.W\ֿfTkSW 'uBU DgWg7pӖ*Ű*P̼NvgׅzF P-,k"ˠEi%|&?`̷b-Xe>ɐ^B,)*#&%ӵ>V+`=~5TIډ(`.XOs00j7Dt Q?X-ma:2^:~5[ILa' gSu?; S0uO; b:iQt9 KC%č`i]>w ݛND$sWd7QKUK"6371lX0\>I͏fhby/3MUӽrerĜ1 |OOj}PC EՋTf ) K;F-\'J',-6bȵ:c6p@'EDǂR((6Dr)%N_좛(؂]^?*"\?*“p.YsND:Sh;<=zmKgc\ףm,kw-m#-PK) +GɣV8]|kkP\\9 WDjɌ?~iQhĩr&.t\or01KޒjlVuQ87b@UY/:*!2*[,2Pzmt7IShgO;U, Ii@5.]E#lfy֔,gϮl)mi5}ۦˢ/<_b=-ݱ R j^=SLU7LZ%+uroBd(ܼSw U%̻̼3!f+`sڬTX ++]ԩT+Q!ުZO|$ pQ^-K~:0Ex"Oi  bGGqlX [^ Eb|NOBiOi_%_ ¢0ħuk7*5X ƽMl;ɹQc$#%ct"'ʝDPKr{`b'bqTvf A=?Kn&1Ë^,a%4[Fg[(?#H^򣿽"e7e* TMdi9 I{4^WD|@Z[sH2bF"F/P _mq;݀#3({#?MJ+\S#l15& HCͬ2@#ՈQFZLtޘ>0t,R6 w%P5)_4UXW._R4fSëx. ߯$S q:W58 Q*=F{ JA>rƪ3~ɼ!+|DdX?Vy'Ar,:H[8C?f՚#5גtYPfad˝BFGIALDJEn5tF:jpǮZʤII-~Z#uvi`pג6 kZFsi 6K ~g_VY" PGRKe/ 8ybi^p\^A; `/Z!r*BٚXlOK^ 7쾨 WsO>-3 iVMfgjrcO$aVMY4{,-fŪ=5HW(>6 x5GS,焔.@8Hv@zE wz~ .6'_}5 :6eV+6DFu[n]<],tao>}<]njS?'Ea7n왣 J,x_ڪs"В`ujw\sb9+_X++{ڼz$ۉ(-`EQTuCyxR?h} R۪L;2Tejid 1W1 \yGVѦʑԶG !K&T!JߏÍF"D߉eʷREMnl mj6 -ݖdKuh"d M6OͤDJl" !yKfn$q"0=s)"׭&Ls$bcndBv²)blH&HcgϫQF,ioRݎ7ScN'c(xS VHKG۝8i#:GԵ$a@4 ʏ2TI8g1Μ< RtFKԲ1tX ާ)ښD5_Wõu1j}Ek'I^#c3馹/"'HZׅ}K(& ڇi[%6l1(Pz!9ӃQJRSKP<Ȁɍɍzn&Ĭ&F\i'L]r*|g?gSPWF8E^foiS_eZ,5nMo2ym[ӡֵ !"sA`bc;>Sc4؀5O716 0=%;3 pI87o[q7 qxڞ najɞAzQ. Pg,b=^iP͵vmZW"\Խ%ԫO[g KZT*`e:,ZT)XnKT@x"-O)U ]EL *yz~VLݒFmm3˫yzWʪ *} FREc晹Cnl\  u b,|-w˙(Opu\d qgVkTFH)8 OQⰼs!_VqֽT*G >ZS.7Χjrm>B2Ȇm :|̣ w {Y1d@) eBs1Z(쏾4*E#!؇d>$3$KBp@#{$P+.Xtul .bJ&D٧RApsD /HR/{^DbK^ȷ; E@lIޣRd"SU,={I ˴c ]ZÐsh C5}Mԥ@K[a,m/NjO$&6{]Mp BQֻ2XSjsT(W &"W=Ta! ILDR`!uJ#$!-0{:;vSeZɆ} 5 }Dr|8ypttQH~qΒhY3ȄAo./3r+}"#Q&I&[zu0F^ݓٹVRth}⮞$U<+sBGbM̓ ]Z>ITNI* J9RJOzty=ouYUTHbA7UHM57"_A^Y@2?v eW(xeڦeXgۈЭc:k NuZwu֔!aH24jr$*=Q;z!3#&h`ɝM,\{т<.C47H;Nwmb({%;ݥZ`pCv Px-ǼZt?/=%\ҥ 6^mN@Z,Ȝ 14+N2>&mcpZmRPدv,Yw .#9ǖʯOZ&=yL3Ԝ}HA<u\e :Mq44rt׶5zMңa3 IP'Khos1RHb(L_2fNf;&(N,F6'gUԀH!W~-(V( vأd$lwҰSOS^5hb J biV(0pQ&!uQHȜS"԰s杯0]GC@c¹a+C':zNڶq}*) a!#,@o / ӎRPeݙeO7cAOixkgi” YS5pJ1QkQ;xz``[J׿ΰCOI T RXɏBd\_>S[W"lÒJQO|#'>QO|9>QO|Z`O uDbkdi^V^#Oڷ7xgڗy|SrZ'Ewdnђ':{j%k8ah(;t">)덮G8%-zak鈭5OQ\+ uZԱa8/uB. q[+1k%|ĘU1#<]+9kUƐI1k%|ĘRcVbJZ1_+1k%|ĘcVۘ5k*:5."0OJ|VNo N_2錸*+ [}/OI MBwJyB'!{Fhi#`=O^g" ժNNkK JxD~3<%̤#m=4?=y?&NSAFR}inNOIKwHJ-I]-aRCEw2X kW"ax@ll7toFmNi/hY*`~'-TW}D0{^]&;y<"9G}L/ sHhh&o᳽W LDCV)ma4IrXNh+eTYW!OA7=k+T,'F39UQ瘤7Im/?ݟ'Y*%c2j%|(('Օz- J qNN&(z *3k~i+eZ^u$YJ`aE3RU): J[\(/΍bqf\߶ ?%ȄHg%܎OIӗ@9~yMdB+^N‚PrI;v=ZY/Ȑrx%-9)ErQ='DE?/2Iw᯴)8Q=JϪ~G)|@)ԼB1Z(3nG99YȒe9S3+5q;J|N 7P>8X&0 W.vK:δ9 K{b1 lAw7'b{i"~%"RZt]u??4B;vWOY\)';ӹ h&r両(! y?_h8@4NY7v+4I)'C/8#Ujg z^7W>hDlS>8 Hyɛ)9aZ|!t?,O9$\(I:!daNeINƪZTُ3eJxrKCB5Ezxjx T'?uUIT,ʇCӄ91=+CzunCNC'CZRRHZL5q$ti$ UUDm3Κ'>JOAۍr ˼;i{_C׀'^f\BVjhޒ= j9]}#˦ Ͱ+n%Kwmv59 S5OJFVST0[]Ow2d:*~3zUO:^Rc-6K9X e8g?SҪ7MK2T 1SInG0vqP[< `OOuk I;v;\TIci-TEdaFxZJ5E]&[㯍,:8=N*^}nCZ*F¤#7(8>U_-t+42BJd W史 42Bfl蠿'*nϛj6!jZ>-݇ "76YyJQ7c<A9-- DUV#CLڏr/1qtbⴶ]6p&vvK鸒@q"R9/ 4b(FvI-etB7jwh?uAV|_5jOIHB.k% ~^+TL^EL/ +K9cC_[nz/'6I=}I3W5$l&6n+0kW%?`abqt֐D:އ/  -(,('oL-L)l0ݿ}f@ߙ!h"Y62P< ƿ,)XWudAq~PU6\Y?|ԛa53KbOC&$Ow9ͧwME_F?o3PqB_۹|H!¸њTV"ϗDN-;׆BŮvr+^31=HEgV$|RVK* rb*dn7>*z~VYO} N;C]=SI??/I{I%Y3: etR8Jra,BSm`t#m~n1⎄()Q-E$Fb274.$SO/ǜ}.a#'Xd5ӢF_\ tiL};mZprB+%m ?.Nsf@t]?U+8 j+5 c G3[|LV>@ܗj{xWojyN @<' >C ( BUSTjy",a姉2K~W0J51!/'B7i(.>\͉ş( tlτJٸB 1­zP;w79`.x{2]hwT/(]+2@E'^˶Av+ARG6RG(ApBlMǢJ^HR'K e'RzibkZjl4H6kпK Pio)(bio jgHa{;(H~ ɶ|"8h2LQhw |͐Roq>Mʕ%iL1(ϵ6H[!L 2zJ ) ~^6x]|G '&nרU"~@f ՔzE\CCzFA6,,pj Vp\nS !| Xv5vֶb: dzMp)enO6ۛ(lkpIHgic9Ѿ|IO޶D8,K1핊1*UnSh0*^&bfMT::UTb)Z -.Va) :[?Xo@p''>[oäZp6c0}0π*>_$+hzԭs^|>^H5KE? DTdȌCfilziw*}̳%vR\|\STorPvRn* .X WJ6UX*O %&0B0SR41K5E7!+^]Rzi_:fYo]鞓Yo+jA[lpM+>CQi526nz3}eArzx[Ij&@RF5P'/5ٸ C亠 FrQJN,VsbXO lrcH`m%zDݔ_||KJ>EBr+B+g(6+=ER]AES}1R{CN+{5v"1NROϠ0Rh֮% i>nA Q;X.;~& aQ!;>][|I`ݶQ |!0~ȤK!,.e*4^裰spX;\nɴ#]ّM[X*`8K= ɲc-SX\  }4P F̱ڐc#Z:jG{NVeO ܇8c5I7ugvNNa$\J ɹI,#2c&:W/6;N, ,zT :Sp*oe3\M :( y嬾P=wBq@ኜ9ȥ}H!>DS[4)uN` PaɖڒHg|g{布_9Pt< jS@e6Ysn4h$ZvNз?G-ϲ\w˾,зiFrf= f$4ӏ2N !IQ=#َ*g{6y<6; \ٗUYٞj b"o !z?IKJV[fo[?M^mJfei30:p$?֛ZJCPPkDeS m)heOmc,5o ޺Gb7(mO,#Eydۄh ~1mCP6ye,#玱sEyrc]x4U"3yXʫ]}pP݈3}|3cq>nJc)NiYbdw]ݘ(|7&~8Po+'r^8<Ԟ ̫2X3y( BO]r(VU"ћv"ԋMMS|DS`z8:PE"1jՋE_-9i'+j98aB?`rτ,t+5X,?2l`¿4"%Tؐ%/F#*&gA p J}'JmHH!"#!݇ Ũóf#9ʓfņC۠oŻAյjXɛB1ZN6hE^~X7( ݃|Oq/W ~|E0(;]%HG"q+a˜slb2P)F朷(I$cL>1 Ƃ0}n ꖟے6춈jӐ'm`,uI/̸Wc,mܲ+v=m+6HGL;ҏd$ԜŎtj~Ɣ InNc Hc,eO( jK@ bQzBVڛ}@ 'Juq[gCPRZv鶲ne/dXbBm?Ґ^}B%+!:hi sZ0׉vx s3Z<_ěJ0= Å&"]N#} G'&4N|EZ]ipr}Cu _!ҿ4źVyo?1I EJɈq9ȢŲE ,6݌8 3ebv*Iu&XV!YS|O`#Cv!V;_Z$XSMf zb)s4 >*Wjv"o 륺gb%ORa)$!& pn?_Ǝ rc.9Qe+~[va'[n'r}gT[iK|=N>6u3oDSw[Sw ]=q"Ɏ:'799 #+xA~U'b)W1~ j;~1_gV1ڸO{LսB~\u &෹7qՇ2ճ>!}72s\}3aVw <,15351'"e/k0ڇn/ >2Weaoړx>Rv{yn,$}}e uW0=nzga>?0ׯu/vfóx+g?x] jb?5c~1nf>f*>̰5_a$}o] ߖvџh?o`70.uO k߰aq">#?=t<#?eaB}Vz[sAVF} }6>Ƙ/|mm`s <;o_3֗o_ogx=cs(~;+xf1?0T? c%//9dh?6c.#]D.D.|p"1o`' pc|x87c|x87c87c7c7c oİ7c? ߷Q}3}( xW_ư߿a_Ͱ?nh`̰o˰o:1&c=Z}c=p, <~ ?h?Ͱ?8uBwǁ`b/b/fLnsg20ce2J}a|s2.w##G3\Ű?atGOqha1:1:?1I??؟2}+q'a[?Ȱ?h?Og'3Ϗ͌fFqJ߼ݟ͌$ $ $ 2wOed_Md?y ?ݟVIyV)yV)zN+>*w?O1wߒcLf-0΃}o|߲ݟOO3f>?͘}1_G1_G < cggggG3g$? ?$,c=Vx6}+c)Jw2k2??h???h? ~?magTwϗ?8O{ *c45y1N_+21sN_[ðXϙ `0Og;L? `p:zݟ8x: 1fo0hc`_ac37go2d'a?dw2π;π;sw2p&1:k2hbbo3۳x xm1o0;sws] w1?<.y] w2{ w1g1`,Yssi { Ͻxn 391z` c=X'2kDz` ȸZ'2DF{3C?g'q_gϪGLd# zAH $c}x?><X^ hG2$F{h=\ObK2%G!W0Gb?!(_ R(- /[_ 0Kh} G3G_^G3_0_)21х1kxBI <,c~t!rwWc󣯀na󣯀18q+?>Wysƃӿ O^߿?y Of?g ?~2 <=eGiyc-!?+{L3!?+%SA/4NJ}-? FzA\p*}/  ]i?B#9I_Ag /mk sn:(yuf<0שǏąOqMpG}R~q+D\Ņq\r 5zS\?q=׏1Tnqa";Bѥ"5nqhq/.UPcVGz_HiV6; \wd+F:+1(㟋vn:HN?xv䦃n&x~覃s'YE7f;o3H F7+kX#n:SS߹R%7읃g?E7qOﮌ_H1髐Qmns}ct0ʌKtO3*M"lbs]c&ֻlżx~> :DwqaZ^=)o5snw=}@5̹sW~禃_x0sWjn:9"pnnN'8jns׺`w#sn㿵E<_uo-sn㿵P`wD~]]M]}>70y!/MfѮ|?0asBt0e3֍uux^zM[Odƃϭ\05s#?1}.Lq-x08pvеܾE73g" t0#nj;݄|itDm{d\3MH&NaO~݌u_7bތkm gX ~x~oJɯ[u9bAwʹ @w9ű= >C#s >Cw/WC72x+̻"x:!1ې3{=7Ms6mq<[u*v-"8q;@{ߎ`Y̱n+`_ގ$[W#sH&1}Y79zby@xcsڿ~7bq@覃a93}tDD^pӹ:ۙli ?./Igųa6tmXޜv|U:E1s謊0t7d} t>*5x~JmNt8pK:o=Hy)zl=H"ϯ{-W{Q[qS_w^ӜW 7 7phH3ڈu_OM݈Lgo1݇U/>>[G ֋c/[9Nv~Յ_s1@D_?7k?Ϲ@_&/^X a_06Y&q&&_8>ߺ~A5~=_{_bG 0yiKczx~=ݯ0{y/s\~!ۇzW~=_c g~=\&r{Wa_܁_ r둓_.#elav"ï cqhpïGz.G/g/ =c9Ozcǐ׷21$["r_#olpozmx:/M;~n~j 6#;Wy!s(~m1C o1/7#ooe{O o3={Ofk}g'wVy`>2'Qw1RDkUMnu?/Mdw9kҨO2zwݧP1O[ 5 id9w$w5 OkgE[v@ǵ/I94_AGAXt<}]c([}OoD舽w?ѯg?5йX/~={hc'lt.dı xѳW5Vip8k+t~m<󽃭V >ߠOm`舻 ɯ, #{_H[~mЉIHF ~]FDҿ'|a666WzߋFp9S~=F޽ɯmH^6r9mdSˠ#;2~mhޟ~!ϯWZù#^AwZozr;9_"0ꉍXx/Hm 5Vȼ.0^C\k CW_ nא2X}p_;&Cgm?*wv~;ӯ8g 6}m>dR_W_G^XAq?VH79}p9m!Ƽ3oNxV57Cߙ{"wN޼:[bֹS&ag湎Ha~]8q۾m[68I~B^~:b^{K_HDƼ36o HD>nVo_q~D8c<΄#wfC9x?b ï+㉛ފzgKc&#Mv~a\X=?iï&kݾN1"ݯw׻W4V<.{_%ۭ5VrŹ#ݾ@fηHьv<l Ldı x^ :?*w [qT=Jyg'F6BĨQ[urcqSq`osԨˠ9jypnOvvw2o]qnOv_WG q`wR dgTCh I-,u F'hp0v?sӹC0PGWfd ʵXP5({+ ~h{P"Q 5H rA_*rPP b =JFwTP+3rU @Bb @ 5lU.or{\T`GˆusPero&UCB3QGp劂8{\1G> R wI\1_B诃.#{K=l:$ '!Yrz?|ECrr鯇g*ס*B _Kez \e:s劆Ѩ7~̃L [l6'u'0;7A<~a֛_麳drEtAY1 ^CۚW-1 9 7ߕ?̇NoNwL3)Fإםk 00{ 9N[_Wgh.8bhV,Ѩ8G_@C _`'9o#aF966>|0n'yP]wc>vri; w(,@ ]e/$˅!O*0.CmNi慨]rrţwsGr Zxxbۊa+JqDB|ƠmQ1wd=SE]uRcaIĺʵPUe^#1qh4Wϱ~0&V2 tl906(40p'!R%ѳg -upG*QW>^1]QtK] w/ `AG*\{FDsV,p}RP/pqL. 3=83&>8op/}lCn4mnZ(߼Qu0K1t1/,RǶ-㿌)rR2wQ[]TDmh]n3>%Y"꿖XODבǣ븷iǣ*#8C+꿞< _O.C/w}_ʵ j_n#]wZd\'@}5-^f1  rHaRiRתև3$ĶvFF}k0ʹ鲮D3(2;8b~Nuf#mn,0gqN`RYY:*?A#'Ͷv=}ufΜ~}9jv  0 œԅ2A0+nCH]O[迏}^I)N- z`Qf;ݳHBb= D`9z/uL$ߞ~򺀵eSh#J?<gܷKkv7GZ¦JRgykeb9gdm^y2KlěA#f\D]aշMÈUޑvŶيۭ.'p[+VcV 0Ff%7WY%ۻGh}bC1}??Dlivg}RŠ;~_c[Lj}~ߣ_\`[/Xe.,y-b'}q\epp5>3ĶF}| ,O70$ GA$υ<b<<dyz!y.sQ"0,Ofyay0< y> y6"yn&yn&yn3VXLl&y >gy>gy`y yn%yneydydy"ynkk#y[[;;gy'yGG..''gnIdyI"_H"_X_Y_YH{~#ybyXYI{ y&y ??|þ??laþ }g&>a}C>a}#>a}c>aaaaaa}O>a}SO>a}S>a }3zzzzz6la þ}g3??|þ9??_|þO0?[Q:x/{-#^[d%q$Wc&q+s7\ \ͨp_BCv߾|$98_K 㿥o||ۺo 4㾆o"%8_gd߯,E[]}kmFtuC{7]!m0ummmӇWƷM~_o57?SNGfA pU$ǩS[} 8o>F3t7EP|9$nH5q.J.eH}_H^ :qؼ7|t} ?~s^CK??3rg0M/I$g q?C*?gGSC=AG?z_\|<#߿<\=_1p^祑lV΁liAq8I^-QW&!Wmeh(ֺS4;ki,S4LOO0ásHLx wLv1?9VvR8c78)!&W,yB!T, kJÞ84%^qF1<# ̒}3FﷻwB"l&ZHlm%D%IW$u6\4D*=Ij<ҿ IA5J F! f/Z& &i3+oAph->KR[4Wq/%q5ҠKbۀ4]bP4,Ҥ!~PDcY1O|un1 98?_s9%d{4$^sҰ,o߫!)KKIj r?¥a9<5mI1&21p"g ns1O?f?s1_x?s!\FY% +*LɪMM'韈&t$k3a2vGY^*%TQ( %#k}cc/??ϣ!7Gփk[P˚78 ?V;DؿBxnZ=b'W.{K ~(׽_wA/AP#?hq[N!;IbzjbQ;b H7ơU76Z>ZA7Y{6s)^a񋒆~ː/|yVk2i2n4|LYC 3&Q?߷&u*?_"b}c|qϸI?:xI|?Q~ƘW &//db~ Rnb#-~}% L~iغg=^pn~ x܉Ǭ<O>@-["[C/J1Ox)ҧ˗F\uIkh)q8$sAY12gNF?lj4keSKqR_4N1 Dxi DP4NT-S5/A?2_?>b M8hMǬXfI!}|gHY|Gk`?5 Kp4NŞۧWI \4$,3ä ,ef41,#S|L4"GciieI1hUHT=w!ҸH×$|v.OV;\ \??O<$ /q%$J'8.C_H4.@! K4&i]˹K4f]jqy)p)vdHk4nݙ`q'$x!ʷ=#vߙ(9I>Lx`UmE-=x+on?5| gEkBV 9ZB.H$s4g%5%8wh v83#s|;hjpbL&b||WZ Ω|пר1k {7W_l_uLp{:?R7~/ Z^A%joT߫sa|^{S 9W{ 䜽C}~}od~< [= R:0y(W [dus{ {o?he5P .t:>i| A{X=1w;d Ƈ՜Dp蟇+lp8ji|׆X—spi\EMu=}@ e6~22O_j5_ 9G G{zy_ !X}u^/Q9pdp*qeI&iF,Oͱ|=bt|0<>ϋ`Ch1 k^Db>wC5;@BFuFoXA`?!('k0qt\~w?.O"?.7Zo\'U(vs4=zYEoهD}r2W;$xl8}j&c O M  2~ : XN4Lq.njV5b-a~b߽oľg|Ubx> M$sGf꾫 O0nj==XQN(rm|CGc~IYWkl/}=p^9uyb? nPgɳ ]Xsc$9&зB;r}~e!Oa??-Sc[sW.]s/?wE?EAPAgy?=|{./G>o,C_Bn9Dzqys<;{,B<c*4F΁ĐqvS߹bIyIA<d=2 \ثbod&9:KsoC߆. >Fۥ5>i)߫_ZJވ{|oGoID{S4 D俷6ږ;Vhq|܏GkH 12FukSw_S4٫?7!93ː:C.' [修w' }h a>S'> @$|}y~IBۜϯ&!}=__o* ND|y._W_?݊zZoGoDĿ? ى@:&摍>ywX6:)[ZJA|WØ&{}f(wCoy4YP,a|_n[X>,MVh 2QQ4Yc/9S5p4Eilчz14ׅkwr4M uf%JtsN'Kӌ|O(M|9yPvQspCنqDJe|.<%] VwSJ) q`]:Ksr Mq85^SȤv:5.VKSړȧKD~M 9I|)QN4Ϸi&0i_:g{Ǖq#m=EV%C\k#e;L&o{>|4]Q Iӵ{uP r)dxLpW-^ 4Oa>p}(ky~;LGA?6@; /m3~=,/O:] <0n\?Zm,+2m%⿶ġ+i63[?Ey/ D~ap3 VzBBB>AViU3.}.oˋkx^pcG^(W ҕ3C%u΁ܷL*~?8@^FH_q_ˬ׻-Cʽ8Jc~qpe2izKy3{^ 8u:]$M}p$A1kIS%5Uj_Fz\vɀ44 4p5KK@c8ϟלCk!Fhڊ4p}>DLUaHwʨ}8!|xu4Gg_c=i@'kOG5C`nصSLK,C.R(}o ?^K ?jC4RJeYdiB! .8heKտxCBQX蟫G} #۷7"݈_{v#⟗|[jZ!pB}-kZ {{&߻5 nST2D|{x|5oC)/7C_yFSAN/8Ŀ^f8ЇFzP[B%z<;ޅ߽Iޕ(͟:uW4Dk6JR)ܠ45^ϻ#sFGeC,.07[ƯzE8 M(XKEuD ?@IvyE?y< 7a?'Zz3`\ߓ)Ϳ MFY/<Ḯv ? QL^A'i0bi1OX~+ {Ӥ/<>M-6p8;1{.i ,qkE5`[YG67M&^Zhr%8XW--;eceMlqҲK?ƊSeB1V\"-cL z>?iSC_'-a}9Ҳp>}U9i qIˬX~ iq"iq~_̟Dǟ'>+-dKK^Ǔy6(hQGjuCk-|,J#}^/A?v_탕r~WZFb=Cix(YZ|PZ٤%>]7 0{8ZZ66)-5}rnه%Kq{i \/-K5pxפtPZjܑH$pw?>.-d?x 7bnݏ QT=GS4p ƊQ5Gx(i9C}_H~XmXpo>IZ 5{Ye|SǢ ?O]{eZuVZ5b_HqWfi/^ZuY!|fuq_zr\_,-kMwHKv9+7I{пWjMC^7]3r4Ty={C<Ӹq<{Q^'oҸ  ͱ8[xܓ?IBD+ٓwVI俻l|?@[#T i {5pjܙߚJ _qqgO!˯>!=k2M1,O#UZ{4&~<<=O#=3OM=:COg*2q Sg'A{:D{FJgj4*|Ϧi!==?OR|VߗJe3{^BcX u6j>ox`>п }(85&{[N<@LY#ʘ=7H7ِ$-Ho8ĆbjaJ%;׆!qU&a|-_D# ?gJ8QGϻF8CwN qL79qLG5evEM8vل8~?{5ؽRc<~Nc> qy={rl<^ǾaWıYv ?[95$qEW 54p cGC'NSccGur ^}w~L`qUwxno=5hPONssYaHþ Si>HY$G=yHO3GqtL3O1>^Ơ8eבf8rPGwz qܨָ/peX$7#ؓ| !qhӷ|_^aۦs[qo!GedQt4]kKQث%;sy1*ގ|(8v5p ~q.{ywRű&_:;qܧNZgXqV [fq3rqh{@(g5䋣RC_ƹg5=4"=q*BƹF5=ؑ^J!UŎ:WI࠙0,^~> m>;zWw6E ڔ&CM%ب 96أhǛo6W[Q}⨭q-axG~-)iԯHuQ8;p>lMLν6|,qk|O=h!hZ+Yk8Xpi-J-ko ۳ U6VoO;5p5pqhGp8'߻ 8.t"@h'{=zkT?>ӭ1u@ti>8g\'w u1u1uD|VY㭱w7kA.| &BCvpw qx}oz,εߗy{pߕGށ;S>?@Z3|͡#g۾?b [&7>R VZMze GZ'Ekbu&v@Zgo;6&\XrH)g)]Zwָ_Laˤu p:Rni Ә> N{>퇉ҺW4ɇ:~F|)&b:+\ﮯuv]_Hy52[W!t4>+sHA#gD \9̒=e;T8P ܐKqQzx.ޢ;CZaF47IQ%iLط?Ӹc0&&Ö{G4' &XtAM &ӔcPmuSN- zl]]7=ŽEZO':9ўg?E[z{VqW駽zA,-di`u3bY ӸHazQ$݁'uU8o{U}=}Һ*6IeY_KU_%EҚ!R6#WD{)1,K?'v6\1V͑{)c_|ƽB_`.e8<I~,}덖|w{3+[4zoD/HD/HD=_nn_J!|WXM}tgWwo+֢x \p>_H <|+\i]QNbuܯ<8lKTi}$AW,k#5pi}\}2w~ϝ =;y*bBpWyZ]&wB;*hw?@K}fWHە dnQ=vp*;&WgE@{~[>AyG̾ypEvυإ ?my߫ɧ+mw~hKM[d(?b߃y~È8{+y17~XÈ!:H,I-_Z\ߔc~fNSk#Y]7x/?Fպ(C+9GroO%kTcVoʑπ5\Y}v}C߰cxKU -/hn{1]W 0eHڶ~HۂFϽ3 qMf/8mKԙS\FjLzo _C%6MO&c> bw]]cv)^|ZYMn-g5a(N.5M\l5aj~gf{I8?ߌy̱gfZ}ҶG묯.m_tѾjI/c5pU$\gZu1sV>s m?sZ5p<ɴA Vj~5soYZg}~s@G4?(cgϕv>9Oak_䡷oO6T}odRXfFr<'J{ \{xR\Ư^vr'HQڒ,lZi@;[ǿ~G6mnL~R;!Ҿ?ck$}3~ߦ3j| ܐʾ \pƟYgHC2iO;o3x *5p ~V.^ ٪yb怴ybi?R/O^ɨ&pYwO߱%+s!֝|u.;K9w֝3Ծ9W Wj #@^ɗ3"F92rs19.?wy]/.пY8U AB]/қ/vEL_YnUa|n )nпW >A^Pѹ 5>Dݡ?7Cnnں;S4{;ROvwscπX@M&׳NϸX@@c= [zQ1{ {" ѽ@1H)u,i n%8=+}8^{nح{bߛ` })C\컌 ka𿯨4<oM?j<A|Wo5oDpo7M& 69kpߎuozuWl>n7f}M|9k Hypߖ/Qe mUwsS8o_+mshҤ=߾% v_;5*]h` 9u <|ru gG5|fA|aOw^nɷig|)lVg ݆: 78^u?_KHW|ߞ u(7:59UciNMzcimXR??%A+N`/ۼo$;HnhwԈhhH?  50CaRC @{`8ZwZg`&J3|š=(Ba!Xtqn篃J9+gD$9jĹF_R<ԏ/Q+KԠ8 ND}kk g=Rr~#GoX ;$^|UjUs~*pqi \_8oYuWE[p{y-~^>y-O wW<,Lk!'~Dp#zy)>{:GbZȗHu߆af#aߞ ? 8/b@b߃fu M,⯖dʼn?ɉF~(Ŀ|x]{G!Oq< RQY8Di<:emlO0l坏z _KBm$A;qy4+h迶 >?gs#י!=|:8.IU]1ekD I}'ȫW)j}XpNqwXWrA8.ΩW%A^!¿qb]"_Ҷ.,o884p[{6@:7ePrjgJI;,a0z[GK_9řW.Ay1)ľb=6X:&cWy֋&JT zltEpcZώn ϗ)^T/! R뒎IqhYG$g#ط'dIǑuO{Bt~# 'H14Ŵ&!xݕ,IпKT qnm}t;"n2M Ӊ0ƅ{-ms"f7?.ND'H9$N*s5T \%}w!Xmud,nkVCY%+=%az~r3dm\18 sd"r* sM}d^ s s2| sKSn ܦqN*8sF Sß;?x]Nߩпwi|3{[(8D{Dpt췡AóN.(|^L俷D{Gc8y,:u$tYr~q8 =^jH<=ϸJ:l?7'FF{gg#u5nF{?f=!}CoMC5'R>TkZjG Ͽlst9s>~xs>w._{!tƽE^p58>O¼T{uk鶑7!}|·y7q>;V#itĿ_#5|qnZC ~^3ˏ??~A?Ѽ?·-]3TC^ ƽ?iqʀy]_:g q6Ͽ|?ηP4i̻+ӬqBo5YWڤӪƿrX:Sh{.̔}Wa?^-jǻӞpK(~D˷Euim yѠtN)5DLN6[R .%3ys(x8W:C5֨_t]."~V1kT=8{#%Vs%Nܻ,+pIUyKsV, /͑VItX\'srξg!ydۀ3 ?0^Dž#YT* ?8;W <*)pN~J.ʓi<_7 kPֽmm B!4BhdBhEY&pG&bLdk[-ԭnu"4B&|_Z[[_[꼟:ϯ|$/G=#G{y#= wNSg"Ǩ{8>jT5|{kث·F=ޣT}}^*U= |#Goع۬@*xQ,WAշgg{,{+ۓuSu"-Iw jW+CIZR=(OY 8/UǷr< 'YP{ ?iI? "y2N=w^ޓS2wF4}̀<:xo8YjOyzNoB1y2m7Xfa:gӼbMO1N}H|G{7?wn=Pg)B,aF䎽8b, Fx3Գy߻y{4ʷ_txsT^Mϧ ̿2x~2gF9U&h_/Un09=gzE6>ų&^!_es~T]bzHksT纁h!T]? yTV/(.1ׇXLbo z2;K 2;?egC>q/@6% pпMz^mNLF п|܋пmo{!"o?^L_? DgeB>YпOsėy WfȰKп/2Jp>hZp>hZ_୏9?s0^d 5pп>|W)A}Y?k,_c  }ׯ@l\+пD>BIq*+këп6?0/N ι&ƫпr~BwB>u%пokпoz8߷F!ؗ̆})A~נ|^ ㏗נkп^uMTsꤥi>O ?ߙϻ]qD5w} N^G5IQ>l]Cs|}<(l,դbȂ,=jȂ^IgͯiA}ՅO$,ϖ/BNPC}Qp_~(?;>!ό|KE|T3Gb/kϋHtyŘΆ-73%ATV@58\%ռmjTNA5TY jb|r: Ez8|7A D gRq]蟩.2~<{W B2~~ WWeп03\[ױeп:#=ZA%=~ ә@>Դ72 0Y簠j*.\cSͧj{Oݮw3Rs\'sWQbN;oX\skjj[U;GRM}y=:YF5a| \^D5hjZo|H5v[SMQ˦\j >qqTYKo:v0il_O5E[McXZ+2?ъ2+zgTK,G<+Mj/Ԁ\M5 AzT *_Uп?2YS{*Vy( peпg!WCǢpп>}>n O\~L@+|'#[]qw? 'V2*8;qG?kűd8>_<_`rx(cq#ǩ̼|2 j}d./k}<^gΏFy3?[Z`e58vO޺`2j[୽ud>\޺* Jtd*$^qs>GPFI 7yӠ=Ӓb2iR~7XJY']Y;qf=?7mi A<3_PD , dPbl $%JkSo3߇ژM)q\],lDse֗R?Sw "Cs-ƙ|x/gƩ{Q[u_[%9뢙 cӣ9F|2%yG9CimY;kmo N&Mq i/ 8<: BǐY?d 7u.#7)ݝ)͛ɜŏMd[>>ِ8ҜqY Wܾs5^=#aEY) wy y,Cp %),ںoF_`73X/56nNoT堑[mfLؚE4u֏[xw%jCbwg'8l<մс61߾mJ\JN5vLuo}N9/!>r:<[_\qs2.G muo⠳zСH42ue>K,x\ ',~4{mVt2>&ߥLX6,nGwwyiWHfcw >W&v-/^<:gј}=?0v"S5p_+,6$X/`O;d^F\?kQ W` 'PpO+2OȼW+sy'WsaE|T#'~ WQ_?)گC֊> sɀO  aypa6aAp3K\qAO~i9P@?͈Z_6~o%;\7b J'oyW@j5m !ˆs/^.2onR s1 $w^څMˣL6pj@k|wrDQX3'jҩv\^1r5T;>HV?Lo79MϣZZC` #R =Rp.j^baWìڣ5=c;@T={9\}!y g_~_c``C!]|>,B ?]0, ;j?+[g8V"9J>1jϵKc՞.:, ⏳rg 5Q9zS2F5`J x[bdLT{Lk)^*n:BQ8kF;%f+| Otʬ}dgǺ^_!Z0sʙsq-пջ~γ9jF+[gpпҁ|Cnءjk,xEciCnQ:ƌп[ V;п~H+/A^{+6Qvnk)+?>۠w CBڡu;0~m.A |?r@ ~A|q@'%sGh^_C4WFs:jV;pV iF|f>%Tr4oUs. in?Q{׈X 7Trz! Sj`dv Bdvͥ] 2TGfogn&~+ U=fTV3Aj+q;h;蟥Q\gC z.>jm&MC]:N⻿G{?iu1u?+~@ە(]N俿TyDC'߽u!h73.n. g'x.Wџj]]sscL|.~Bw"ldtO}dNp ^eممJ:߾$nsG`t{+K$SFuRDu߾_'߾_nL}fS0~~NP/>'Nu~vP:*m SDAb/߾2[!h_&[Juv?ߟsT7)߾ߣ`~~o%T%h(eh6=пo_/߾? ;VPq&~_,h/HPc}{'=пI{?BNwJ?&^iwZr=j͐9O wF|g%oп0?=_ſDyw߹3p@'ķ,xw_/_$~ H0w ~ /r w?/J0%A.O؃]+!_t ۞N]YӠSqtojȷw/ՙ쳏Cרvp F pп|( ̻ >s_t7HyAnJ/>^пuyAn.wK2}:߭ ~{m:6iw{0%N_@ݩ5xuzyNߟпR~o߽::o}7t?Z.FC2s4a4M K 7+>пgu>п4u|ss=nEy{r] 78_ SR>n,}gG=r!guc{߼SG_BaU8m8guc/ 8ߋ9Y*A^8u<r?{qr( /B w}tBWơпyաпtA>_ x8 "^LaпU Ehá`\{HA^eA5uRzMt.Sw8۟o{p>C p 7ĿLIYϱ9 pT ho&Pݧ\}צIYT9^70̤^w030LZ[X#MTWά2cVOi'bO m=3} ]_{󮟲-czbbwp"&:ZwFlQk~QtfMGa󣝏;~9¯;_,yјtq`[_gw+?jk }6ðk3Fm׏r [ ,:Z`7k|ܱ!TH/$2pyTCs>k1}|q>T?_7Ow\p|];.gtSܷ|1Rdc`c\? 0L|~"`~ J$`"~HA\9+p2|%TAE O]̿;,NEy?w`Tej20NEEiSQ]o.T |\/џqпU=wuiпk}8_l ;O]:tnu[)ӡq}Cn2 xp~mx\~΀R(An-~3wE3wW?CIB ?>τ<w2?τ= KgBq,Ct<< 7ߟgARCyQy;߾I=&ASqA g`~A^[8b@\A<7W?υe\[:w {[c=8*#Eo2B$˘">.&,rr2 UX>j, pd9"PK%ˑ:,],G[kX&ő.,A\9YNLzq%dIҸ.ܦX:-,id#ߟrɒ?;,wAnW#rލidIhEd7v^KpN48vMD չ6@ěNNkoB;Sw$>.3,AMxj+bYsX؎Gx}7#}RП7#MOݺg5]nF[>οs 8俳߉w׭_ u+~t+ߗtq}+9Fĥ^3 M0>)Awq@v8_C}*X߼w}{]{/so{_ק2aܸ{/*p+ՂAj|ݼW+X70@8_`tǙg_cbwY 4?ߟCZsr?-/Aڑx]o#@8YQ1|7=Q׵( K? v|rz;'=K(~~0,S;{+Cҥ֥tC,`҅c5Ìs|3̳ըʑ8cd|(X28j uQwat\K >wuW'5]G cH4j_^D s r@jȏ)0/)뗔 j8i{T?jݝL ꦂ3 π{99lj/5__~opzf C g9"|M   u|~,.-Xp*RA4jiQϴtjϴbjSmAp?OFw>C WJj 5\'"Z'Rg攈ORz dMUI ?w,UI7I74 2v5A wx*8Aͨ!,jPg<1rjPgܮᾳ 2At:^΄ ZOO#4*a/ c5gJ8' Y?nq=j 5<%B3X5#QB PfqSËzI H a5gs%`⪀G=d?I j?9'isEԐW9h3/DV}:<}Y)mnz}ЈoE ?Won&_-jkF|XXglJL?e7r)RoDo|'w8_To #g{;Z/R:|)o `:dpb25{m~tRa ̓a L]y|D&!5Y륆n3R5r{у/R5)x%[s/X>:'X3{y>ǸRj¸qC|4yܮ ї}`9r5GJ ~?Ӝ 6B($jTȹoKĄW bSB{C~j? jj<߈EsVmY ښwWYhk6ƿA3Q7[Ü:>–R%jL.sZ(5>'q:3<'VhY>(x?.ǬBc:ߓ9_z'O=<975"KHؘPzqH8un>I+5rӨq?}EX.&_:G|@j\יq'Φb+>SZ;)e-]g9Ը>O 3~3qcƎˀ+&u%)߾<ߦ*Ot̰{ԁ}.anjO 313 9髆//8ϋuY.^[|=f!o0xwǁFx7e=<"?(~^,B2׻e*I3Nj (vQQGϺĭox7 ?T k񽏖3etƏˢ(O/NPeY 5Q uQShHwqSәj^Ɯ'ggø0 D~8cA:5=#lϫ5磝\{%|{_?˵_wLr(jRz23):ùˆ{9˩ij7_+RSL _+?Y2V~LM$h\pCnE?@3נB?7v 8Qxj8xPmVR|]WԔtGWR}2XW\uc%|X\?VSy V5jįwƾ=.i;VP2|5s*(u ̇"v;ray"ZZTDM˲ZAME}uu 5}u5 WѧiUDjou"`)_5|?_A`Mׅ+<6~Ca5m g'80U*l>5mG (l|=Y~TbĿg싍T'˟wSGc>fG࿶X`/b0O[\7Z  #sP`ŷ.q|{C,xt-oķWoCoCou!m[=oo=_G}%+_؀oQ`6@!oo#!ە.1iH)Og*~6 m_w q,5L#i'a;7SӟvnJNM ڹ oa;7c'hf NɝSAIř~YY,U^i2Y}Lyϋđuʿ-YdUc9/Rq њnF1VviXp_[czqN~<ڿ׿g׿5\su7^6 #11zn- ֜L=WA֨P><8 ?('ʳzy^Yֹ}dS oG*vĿ>n_̈5N].cۃ_,W\{;zLP6vhqc"9AE&Yoed=d|J;4~NI;'$w >W,?9Ż {:C&cru1>DVc?/J̼Y31/]W>ArR\17,}JTό ĭg%oAƎeпU{?UÉksߢ4ϡ{пŁ{п%sTCTp稾H!o_@ D{/ŗп$>_B ze\| ;62U WUwD>+[q .d\|?š2Ո%v*PA_;5r8_O5! 7Um$MEN3"lgm Y Y\Z;v8|xCW-!:I_|{u~}=2R}}6Y深8U9ϯ#뗩1cWW;o["C.oTuky~CY1ja6C4هݜ6t&z4v9o ܾ$3hocY,ަk@{k1yєB;!|k*Cc&;5>LKv#5o8uػD[C ~ӚDn.O1s|ЩLss^?ֵR!m|N:?j˦s{ ̼8%+#_[/Ęջ7wmbuPɓ-Zz’w$Ng*e>nxB6T赁ewL[a|3rљAj{@3@:)Xw@mرk_@#XwC DIfC&@ov~@ɂv~G -tA~-t߯EKt ͈3k?O)XZ;µﲨ`~1w ~?.X`{5s@(b~5?A~g5-@μ} s{l? }Τi^u;㏗N/XщAmN/}~5gsW5$)+pk *GcvuQs,lLͯl #+l珘&hO.lOA9=?J؃%؃w\|WQ5BJ<߉ȳ3 sF؟ *4I D͋zK5j^փ5mjlb4ݏw Լv93O =3bڰ_}7?ˣҍAͫn+5J0ߐYߢ~^þ9o  ? + [Ͻpп |{C6 έ(8;Tpnwǂs=пM|{=п͂s=п2_Y,GAUPۢe6:ߎvr@+:tfZɏ{T1/F̗>8솞3:\K_hXg5Wq:uJ{#yf4uJ{Vp xsM:_ X Sspo6Wm|oKEPo俭a7A&(~C!Z؇k:`o |1_:/Y~'8/uEC?保|{!!C !??!.!N~ ?{5 ͅ^C[2O~|!vw!ICG=>|F!SQLe򟿂2 _e|{^J | /ߟ^v*8?5],5g.)@`laσ>lJ y׎޾d׎dg e;σw pV~zwmL6~-ADԏ_KP?lc|{>:LzHs&OpISD~ Q@M O6?~ ޒ~L`ڋler±d7mMOhOS*nR@/Ɓ.Z~?:v1 }v}SǷoَk'x1ޟlAx1>l'L(($ {u NgO@sJ,VL-[ 6'W 9.hDv&~b/ph'7f$~d;_Ng_NU}Gn I`W!۹=#p}{d  iߺWǸB6wQX]G 83p}?|{Ϳ˯nAoRkM^~iާ ak֚V8 p|{~*\4AJ?l Lg;>ls~C=>l$ό0~0bޅ>G 5 fT ϣ! ؈~ gAf?\9c{0I p<'t$?F?~goNB39F7'!QwsGAl0I'Ħm j`>'''|61x̝ M'_7w }uuTp:w L~NčSzN'w*3}Q0}G09ɂa'8{oo/$l !&-ˆXɶ(o4?O!\~f$ے8~VJ:F-j_ k.?P>K>#Kx)$K/3;tz¥d7K%ᥝT˂i;%#e9q9ZbF-#O;北,?vѸ{_?JeLxc(ԒwE,Nd\,)WW&F_2U%hh>EԲFjv10啘}Jתë鮿u3Wb_®鮿A2xiL/LsHURn⏗be{/\I-;2cUeRhU=a>3p~;(w1V>2~7>w]11tp.~8| j1mL? ksl|^ ߣAsʑ_ E<Տpm`jZ%t8Hm^0>oB9_M1yvܻ_SH 95d(_Mv??]BCtmǘХ2bx6GÜ,o_k'ٚ6*ȳoا'{`?ƒ*~$j>όe;| A7WׅD 4͛ï'{b(c mZ~W2^GP#\C9s;ҙ8Snܸ0 ?~ܸa6?nHo0bA\!{ .E}qd,f$rqd>7k oKK_;uFpm߷U|ߺixu/9[_7Ib{1}0SH03Zr_1-䯯Iv qbQ J!ZUmdru*j:j#uBi~oz[:MA?/#^{5w{n;@({OZ@>kj=.= }FSka_}س8x0ZO8>ǖRkH@kOa վF%Pd*ה kR8iCqOgʦ֋oQֽ{7LzZ/ziӿ}Per{ZL矏xZq2=Z5@E|sF[+&[)p R"f[)z b7s/Z|3ZTݡn8B%}sF9#Z 3pfo>C}ja祏uf,/}ZgAtn9qc@L3U|ߜ 0}s&Ho΄=WT1"]?ggS%ԚT+y|zWc>(?1#,'B{?OՓ\a`}!SkpcV .Kڗ~7a6+Z ^e g!y7 "z,?w^CbȮ=gU߿+֢"4ນ8Xj4?\a}ƪ{H4>i࿤߯ F-5̽j;OMȤ2IO@MzEnғ|{OB Mz_}OHۃҡ;ҡ;J_:Y=RSB\j埽yZkujӑZ#Qk}Oi-Y |38?M3п.עL}Ȁ:8 _k̀ x.YCп? Fп{>DA~&+C~Lпt{п.YP#ϟs"A~fCφ&x?j6o:Gۿw3iNnv1;uC_P~@E p9wWI$q/jڗ!EP9\*W R+ pjԚ%3fP!3mT&'.ڼ52ˁKm:{z/QȷR2y dт^R9~lN 7HmcM)qܷu|c{9'rMrp8&q>ˇzEm pvxWLm\'! j(%Pۑ\d pvW5j;:?_N3Jmǔ p(УWfo.@>s B9ɏs'0ĉl߉U~Ɇ=>5ߩ_ pпӢ8  5dƉסzmCB|}wCJ{wvп =9wހS);ʷ;Oc9пLxɁM|'o߄8:߄EM߅MEMł-_d pпK8eQ;΃MIyп˃8wE> Vʙ8_V)7Uͫ8{aAJN~M7ovQ[LmoSoTD{vM2\pݚ6E39߁vjL;п~߼gLށMC;y\5wFilmh|(g"ФxQAp"/7QQ\=(üܞMuÂ@j{ؠcxjĿ RNt-N؎3>}:g~c~!xMܷn!Q".j'݃YImoƸ<>2z88"T]gC$Z X5읹*_?&NA߼Cn;CC#pOՉǏN{OJmunk g b>Ah;@]k1X>bP8]Ȝ߼9 bb,[oƥ4۹ߤE [\Mm6({pK2ޣi'8Spsrt|Iہ8[̋KzT#]|j?DL=_jQ|".ڽ u|L]z`jקw;C`/G0 DVQ+t>U9͉i>&3|jnY*긹زBj} qm'_N#@Zy ~rL/ T^Q2)ȦP(~nMp/1h\Ͽ>u/ƁyJhyjij?Q;S{(pc4jOnbjO o%Ꮗ{4}!uK\M2ѽ }ˌ|{}`?|}p,m;so[1vUÀC/;-6B*k8 GB>,U A>,}.y1LxeN=_U:1M?s.칭>7u9& 5пmܺj {?[g[me?|k27eпo8_w){m+A: п]eGΌg[?Al++|_<՜u< %G۠dƉmпn?=oA{?u'ko{'U` .Cvߟ+Kۡ v߂Q ߿ .>rh\9"rr^r*€S"ނM&r𩰒GP?rb1Oˏ÷'ɷi9&>M~]48;?j= !8aBaÐZjժUVZjժUVZjhժU!txm϶B/;^.}^z>u9)zx+NC;\ 7bNv򍯉ˑb|([wF߅m2({c|{ .K/.Y3fރovH{2E<\OB E<>үW)Պxb&DaUk;gX.w]?+@]'AVE1VCwa͍͹!kxCw"nݚ&/mYrR7?GJf)3^^/u'mJ݊7K=7?mJ_k|cwb1DaW9oxsA=xs/B' ;;GcvM=.ﷻ_[E<=wÿnGSOߓ'>OS^-_P_0lcvÿ.zum)_T>Qw.?={C8wTz*q_^~뭘}(q_!1AߙأBK7'/@濄qK7H+WoH_xE ^7Ln W uoߨ?Xwc* ;7.Ha7U ˿ ;7Q~yvoR-ˮw)16a㛾F>Z ]Tr/-Fo/v=&7[RT㛣c)+2tŜU[`|_6v=Ɨc{< }w_-[?k-O S;,{w=1~lS^|̹}Ŀ/&<=SZxP{->ROcŻ߿Svź~;O^¿Oǿ)Ώ >o,-*}X}X}{'M^ÿ#=&R^ÿo+?aLq+U_zU~)?V" U+;#IUo/?¿o~߇㞟߁ty; ?*֋?)S¿>~Q;~UR~S8w3#WwX/ߟ7zJ,׆쯿5;w6~M2e9|o9R, `;b'2eAy;o-OSw#CnbχNկ}?6:  [֘ͱawH/75e7p{Sֲ3[vv&{[aPyy6;yzoU{#~qgyH~/{6+ >;[~{6D~{6#;}*?_=}&{\~o{#7=}Q"k  }Mzÿ\y;}+?"=)s_"=}{I_~/{Kv/ =Uߍz?{W!Q:|pf-Xo\}o^~o^~o^~{^Bs\~߁^~߁^@y/w= w(E(oSw8\^Mv)?m L|>)[B}7NcL3vYܫťM/}oGa^{?{Coo*Doo)m7řpSz-_<&(Ŀ)|JM5Ŀ7ռV˿}Z6o_aG[X{[7ռ~"?{( >J{@GP)lCbnCG'x݆bnCscř/3_gg¿r¿g¿?g¿?| boq_]ߟuQ<^byJ;zΞp\j ;vf_}{Ur; Pf_M>bovf_"z"k(2NWYO4ΐM}wfߓ&>m5M}rwVjdz*;GSf_by{y;WqfyWC;CG}Mon.r̾ :6.JUK46{Aug!-~Yܮc3Byi](ώfB0NNJٹN*,F2k| UeW+ӑg>-{ Q 9r6郋w٤jg"V^_ ř&.Pk8cݢ8c9wLv6ś>]_+<+]1 ȗ#ܮ]9VE{oD֊7a߽A ;8 =8 =.o/߃_Fw+=x;{DPoOa(mw{w{vy4kGÿ'hF4{*W'kx'x'W7zy{:+ެ(ެQ7k{ÿ(řLho]q&7롈c_tTă1"cv/F}`WIOIx/ (> 8p6u}_bTwy!_b )ƉX7y{&$ i ob9MRw}_O*o/qoj\ 7M?MSAos.HxsXg f:)n`g)Yz f{0Q/Cߜ57R C"E2!-VxXÿ%%e)◡oY-Ws¿7e7Pe[U00tÿgZa8{6\^߳{_n@/="WSM/(Ω&5s o_a^RSwGÿ'+O> >QaۭWM(gyU2\. C2BdXo|Va"ZIIϧ$W$W$o>&?_EU* OUo@R_ VJ5>UϚUϚk&);zbg*;"7555T˚~V۝~Q~VCiT]*sI&-Tb]8y;]z|\1_SOχvC̀-̀73ݤX_ʀ7+֗A\ni*/r} ߭~>wPyy.w(Y-w*Kqh[qh'\^=LZ MQ)e¿ÿpE|+Υ/߃sCsK_D\Rbl)k)/-m痖¿NjvYR{Bq~) =RY"_:v{rY:)ϖrY~uQ-N8/-/J_/ ݯ=?W+_O z)l[͵l4U}}V¿~ /Vq?|%미 9vV! o`۩+j_Y |X r0rpro OY^^1?g:V/_4-voSK9ri7^1> &(/i'։Fp}71xh<&;>R= = *¿i)>Bv/&w:o9#rfc{g¤A'<7$lgr :YZ)|\A{Mbs~3'Q]v=Ryzsp"Of|s_QݞR8cU8vYƿX^ϗbx?[^^7g߹'o1{uB\b/8gNkcL<>`k3k7<5Ŀ}E¶Սk/RE"-Z^/R #H=RT/1 F^/Q6KGE1eyy7)x {yE/S_e2Ul ƱW//Iiearμ1\[\>ƌu>q濁l Nޕc,rKOWo[icWC(y]Jw;u*y]J5DXح`Zo%c8uHvRo*7P슎7F?ȏ1F~8|TƦ,Ş6¶إ`/o MEcYO_|G8Y_>OY_j*E9쐼6Xy{ِa!T\$og*_AM+2WYAF1*i*uS±mT4O?ńoa,>[ 1T^ōy y7fS3S*H:ol//Meȓ6Sӱb3Xo8>vuI"E7l(bmoHf^mpvZר~x5_lk0,*+N?zG}RZILŧTy;x kG߻> o[s¸a o"[7uq ;b Cy& wW]8LŦĭ _#v&_;oR+~{C4PoƏxSvbplט=3Oni-ai@ޗb>V MEyUs.Nؗ:l*ۭLHaGW??i=ˎsMEǻSo5f&⻖wgTSq >qpN Pg=ٽtg cd0ؼ3T8r簎πHϡSyZ1vu-FznHn݅? SD{J?\-R2z/T6LK13R3oa*rPۂ?ǚʳSM9Ջ'm*͕jd*/'G}njC Rvɦ]t+ϮżPS/~4m!Yr[1 RdlξeXg~MLehŘض7ηOwm2^~n*w:})KL {TæEKa?je*o! =xlW9}d*a蚓 2?ߓGL M<ng*Rإ'%}=;?hKTq:CV_ʕWez5ˮklbQígliم7 nd}u9 Not;Os?I/صO<βଆVOMe#ޣ$TOs?"LIxvl?/d3T].\}78?}#tjk{y ;߉שID{.Z/8R_0oU\T?۰6%߶Gcle|Tg~IC)PNmS|+}B78vif/ ;);2^ޝ&¶<[LgE:Od*}MK7q,durK)Ĥǖ7{Le _cvmLesߠǎSYKJsO}8lSy఼57?8),TκY,m*wOK=d4=;qv_k9_ t-\[˩ߝ53U?F!ӈf(,?"4_2SiĿE1?,zĿKqwl#mvpάYKp}_.W?8(%akg wX>hdxnbi7N4ǧ}l{ig;{/9]c <4h63cHhH^禛! x G5S"o>)r$ׯ߅/V~$B[߀$y]+_\ *P"7$A)O!M߰dyh KSF^¿obb72Mo|1Kl)w .w G_Ʀ($/7+-w:O+aM L8/Y:fa&w4K0#[c)OS,ðO{Rƿ;2͌W1QO=?b7lj˄x2ƿx2ƿx2ƿy>?ƿIr3e] DoaK?ƿ;ɿ7 8EIS? _Z,w@')h,w%vߕمJp<rqobg=|)UO+"&VYzUPb=#=߄¿w* {vob}jRTaZ(+rk_I8OVuN/'] 6¿Qy-DoC9\$/Ta^+ߖCl[,vv>\pۮ8Cxۑs+]o(]oߛu_bbbN{gv۵yv& ;}Znw#}uNJu߿sv7OqMo" }n)⺛_ǖ\)>•/X\}yP>N :Yqf7[%epKu&R}ne+o"o/r:-oO^.?b|U(Ɨ[_eUVp*vZtQ/j_b}6?N^߷l% }'S>dF!A~W2)άg?*άݞc?+~8%wGcYq6&G/~mW&pP&"&3~Ue1R8.oa Mmn*F%aMWb>MvWX{+TWeHyݵT7pp̾ۃaڹ%N011yT4g*{MuS}"^0vZ2g+7d*ƹ {Mmbk'wo;>o>®T_8g|AS}a?/T_~_nT_,1Fr?;ɦ_ Lu3M9rᡦ0y; 6՗gxi(T+޽~ ;El@kS}e_J?Bj߃El F?U¿ ك:žCzžCz9 % Qq?nV7ǥײX^$= nBя;w(Gߝ!(K_? R׏¿E|ΕkUm} ϯW O{ =lP)/BϷ*G|[h _rÿ6c~?VqnqxܮkO8qG] iyO ׾'_?QrSߓ/RcړK88Ux_|=롘% bRWÿAQ%t}O_?G<~v#믈;¿ o"*/N_w2 V{ Q/_b|CK$_"0 +ƗH_:ÿ3F)C:ÿQyr]_}]H?7&V9[ r¿q os/!>U :s]߄%+Ƴ(7qMR/ __n MQ/*Ƴnob<RY77]1u3l*/ob>zYt7[ooncBvob/e(YEÿ1ob-/3Qޮ{¿Ŋ!=ߒp>D.G/T.G/)+1V(1 V(o>?RAoJA [[ {{.Ja/(E7/)Ƴeż/S¿WƾEZ"UY_"[W,o~A,۠x"(ޯW¿M!r&olc cDZmI,yv( XyyŊ z@F{S^0(-E;o+Y{'MavJswx ~]xw@*Ry )9 ;~r}C'zv+3 *3 )3ÿ/s㬿$yi\ _+/w¿/w(_)5U|;k(+V^00z0uk.Q(|{ÿ2pW~Pa v形.U* *Ba{V_MnUG'*γ5ߡ eF¿eF¿eF¿eF9rϊ8kT>.z!fw\(wُˑKb'|6X"5Dgw!xG cţۙ #SMף+25F45 )iajNW4&Ԝ;?&Ԝmj)ΏmdjRWFsvɦ|eli{75*SJ 55{mj8|_0#Q.Ssvqw\vpE=qMͿy{DMMD噚+ q~735W*GJ0>Ԅ*Ǘk&25*gMNq>kBi85aNޚ K+[_ zk2k+ϒߍw'¿v)>yZ*N(NFM)N)Nw'&ÿ;r&ÿ;&ÿ0//R܏Kw+ǥ{R_kwR߽mo /Ho _)~p|  Ta*Pa*ȕVM(Gcsk6 = +Km¿TGn7=OOO5t#ÿqw: w<3_V7fĘHY)Qjj:+tQ:3tJL®XW3nke:./4꿻bN#Vi?ѹ~FS"饈g)bo"xhOby=&xh6O❢?= ?&xh@;Es:s)W!{Ӊ+}҉(+}҉*}҉\{,s+Q%I%xhH;EFsO^<7ZgσcbvXŹ/Iqm>86ϗ 7ASvobw¿I 7鐼?,) nKv 2LTŝ;Mʹy.`xhaIU0LOU[cjf(-3s4řESL,_25sc}fKS*gjRNM=f-nlj+Zd*mq!vLBfbx L;K/ R1_і2_꼩$dRY2i-KMP[d+Y?ٹ2"Y#/,U IZn2Żˈre?O+<8/YE|'7EaGr+ޕXŻ˙Q+~9_ / y}lf:_U;ER+S쫯d>BV2ߠsW1cI*VY0\a^S|x5ۢjUjW "6zJN~/ӮY{#9 :o{C4{S4+i{b-vwr;߻oS=S¿= g߮,?bYa_.Hq#} J=#¿?:юz Z!ewObnIPӱ?s;IG힧O{6>XSM ?*C(幆Fqc O⻬/H_nʋ?*"wIb%k/PDb%S~R{?K~V2/~UGsHq~.8?~:s~5V/*ƗWߟgo^mdj֫ WMm=|g_u*~S #ֆb8(6Ԟ?]ijh-v=Gq??6VomjύP%y|:v6Iۭkfj/Pc4*u":ST/[^rH^>6ssMe>r8 qXxtC;S{3^ nH5LuOޱvĚd M퍊w,7¿,7¿{͊s_?wKo&(m ;*Kޮ7z3]q}3Sݙ+//Lq}3KqS{¿{["Bwb^_1z +Uz =*=+o/[Êw>G|l(_Y1Ż[_Tx,+JvEd{¯TRڇ*mbn;X:)os_g0_|ݙ!6*KX6ejT{Hϣ9>J MmOpSK8wWLQs(Qpu__Spu?6TUp ߠUTޠ)go)goR$\G;DqMx=7J*'SGﱎ1οKG-ߑs*oRSy7QqN-D9x&86X9)ΩC;.@;K<5{79}X݉V&>jpvorQ~n8y]Nn'cn')_#3~)w~LŹw_b]7K.*{R<[v+}qXa:W{-Tއ]/Sqc[(aK0v%r,zob[w|V(a|0>~JŻs¿U>}rZ}PO+Z~9 RݹRxw=xw=+}>JjiaRTL#eRI hRR+Rm!TJ*"!eRH(R%I>.R!)AJ&ő"I O[3{I;IR:)KjOjMjNjBBI{H%|R6)H!#i??9AsП砟69_______U_U_U_U_U_U_U_______lg?F6џlg?______________e_e_e_e_e_e_,g? YBП,g? Y'4kK.ER/ER/ER/ER/E/A/A/A/A/A/A/Fb/Fb/Fb/Fb/Fb/Fb/F&3џLg?D&3џLgW.B"/B"/B"/B"/B"/BB/DB/DB/DB/DB/DB{]______ g?@3П g?@|G|G|G|G|G|G|C>>>>>>A cǠ?1A c^^^^^^F4hG?F4h@@@@@@wGwwGwwGwwGwwGwwGwwG7wC7wC7wC7wC7wC7wC7G? QB(G? QB++++++ 3;3;3;3;3;3;3#HG?D$#HG? ߡ'lD )s?a#rHbNW^)i+/@:; t|H| u兑ڸHdR+/#JH<~(oo̕Jj 'wE\y TW^Oب\>FZm\FmڹO7%TXW^ؕj}ndkApEY.ΒdKYyKG:1oLCK^SK^sK^%%/ڒoɳ1閼lK^%Ȓ˒גߒwļ64%%%%R~c-7R~c-7R~c-y%KelJoE[z%R~nёn1'2MsO"Ros-ksZ͵0e%>kis-}չpBεgYy̳y1eeo7n&V7J\y]}pAOXo!c{Z!5n2fc \yH2(tz뷼Fٿʣ ^r抇^\-!<ƈ-tK,m=oq--r$WBr1t+VWJ߭k[]cVnu筮2-~\E.E-rouΣ^nswz66WF1v[+vؕGbvظW]]qcng$׼bmwG+/iv0np;7v\L{.v-Iy@1}kQL[+vVXQL[+vb~K+yI.&θO8kvzUsv_UVZU+~M0BBECHB S뇤V-ZO~z|x^.ݟ|>v99a?8 -9'-vX[bb Ŏ,.vt3-9s8\["8/KiLKkK [w]_W[\^ʝkWKp.q KRKNZR_.U~:_*-utٙ2qh%ԓ9-F,sjf]ܻ\mrr~++Pm(sy??(Lvpѩѩ˕++ywJcese'O?)UμJ5ѡUUJ5yhՙ9,vggG_~?;uvg~phѺejezjǗejajj>V.88/kFڴѦ5Gȗ5& k޸FܨpкκZ iD+Twjf Nݠ} Gmp ' 6hP y|k7apQ8otp(mt1_3GlTmmtp(7:8onlt|(7:8oot|ިr*\ZF|r|T9ܭUNV *lR~79MMΜIl*qi?эMگnr&&_N~:ƯWWVuzʯ1uU{Nجx7;|,nlvzfw7kQ}J[õj9N?.ZyvVU[Z"EBrʼnm4v3#mQ`E3罴`ksNnu0*r4bVUU˭ۜڦosmۜYyr͙_o/oSVjȗjTo5{5GjpR#qFyqzT|n<=vG۷ /ە{(۵vg];gv8i:^w;!\v8産_vHv8czSs8O N+Gد;/wz~yŗκW: :{@zut85}@p0=hAAazASGKt8ƃ ʗN~tzAͱ^{H3!ĿC.CN/;$^rr~Hkv?,<`Xvjå9N_8TG9z[sNoߜ&LsM7'is09iXoto:YwwGwjw*;w)>ESӿ+;]iǗ#Gxuap Ǐ9罌#pCNm~?T8?[Sҫzg.w띙~ŗVGQg88QQ/G:*;pq̩cګs859ǜ8tf?Uo:S3)m3Ϗk;ǕN./wzqͱǝ=؉3OH7N85sBpp98`B؟pDgVKzáT9s_/'_UѦ_wO9FtvR\;hII}st88T.O:IIQpAj(tM W v6ȿ撿NVђV Vvxoa~yJz)rSUN9SRz)gF:% N?ϝVN8MNpziiGO+G NkV>i^-s: suLsֱ9W9W}9>)ι ιq:&:[csF?k:sZ ιbN197OGsR.\/Os.SGs.Ox\9qY9Wg=ހ4xw΍197U \v \k#9ytLuΉ-rUpqqgH!:'xCsg} u19'Nr RB+sU: BŃ0Ǘ0q2>,W8 97]K|9&_:m Fg;(rΩ~g:.ҦpG#" ֈp0P-D89x#9|vN79W>ivKTKN]F5QN~<=yэsUtsN9vx-^E;FآآKÃhPox#9q9Fq|8܈7b#88b#>8q>眴7ɥ_|;8/4ssXsz:+b+bbUSӱon$ѵXXg/qNSKqΥvpp.q98ũNƩ/9'wHvɿxǿxP#/~gnW_wt): 9ĵ+'q-Pp|(2櫀KK$Lp ҰhvpI{=nSN &JsҺDgJ,>oUJ,u)D'D7o.NMR}$8Ŀ$''7&" N*^3n|^ d[HB2S-$i* I·kkS`zy[|}S-<3,1O.&hJ+`J iꅽKv z >_x\X[x4yZv;BZ.VS`O|}?3{s|^ {{џ I/0 ]೐n) Bz*`g-$.(^\O.g!}+,$@)F aAs`+sa+Vl)C<5n!Fph@ ֈQnK8HKt^?|5γx\x+WVƕVY[zu=?o_K&V>om(&;y'Dv Xd[ѽ|]zt?f!/M{k"} nx@M?O"SqL3ox-/ߚζאߦCaznm/y;L,dlm!sQ_yaK_?)Oas=ŷl)x[z=c3s)b/E|]}IQ\dYȊI5zOe![;_Rv#?)|Hޅ@lӅc Z؅]:Oc~iOB1T~XEeK `3,t ly Z*!rry^A~Z*Zj^񵬱Бٰ(䳕xZ)1OR-t,VSq:J\y4 jR 1_ZaׂEk{:ތZEy=m-~Z+?,FZ| Z|Z'WY識/Z+w֪ww6=ez/'WEozyַF~6oBD<)ZSU#ߩ*ES'~NA?Ne - **? >[/?A>Zl][.扶3-=?mm+,[G*'_;)Nx~zhW`cvc;C;+n.D,_eg;oџ)QU? mɒKO2d ]=n?B/+-t|^ o oiZ%MXxҲ{ R{gzY+<Ҟa[yF"]H7_U|]߄zxٍ ntP<{o}-A|>ucۀw2LF}v1u8hώOR`Ou';[wGx~G|(O'efгxvcԟNgnl]ima`Ny|4_zL[fkz7=盨R蟙ﻨL|E2?fJ!ߙ,#)~~x2's}2W?ė)}xf gO)FT=-B?G9=2]|2=pga?NV?Fj^cakGuP|gPs~ TAҳMfªy}mE? OOjp}/仗y'KB=R{O ۛ [{_?{)z^1~s z>yoDz杌8Kq |Jpe^7+?n}|j> G OA=d>3,#<[_c|~E_-깯+n<Է\ Hx"{ 9~k)lU~;E4狔4#ȑމw!+Gz{/͙fϜ |QoH+ȕ_w/rŧa:*_?͕^ \ _,X=z\{Yz, 53旋w?XxŊbÆBׯ/Ojb-/^@X' |"} /{(K!Z?7DvCCŇC{bD_C?aKls 5yls0s );L S?= > g|p$8ϛfg,a ,"z=lEawZD81ED,W;"i~?<" -"ixE!_ç[D`+5ϝWy;OtDYD'% ]i]a˟x%%-DsA dX}oLE[Xo 1C_cfXD 1s,a1,b GǨL?ƚE< xcS-yJ^@|Qc Xe-+%'@"^C+P ZZ&껠">󥈧@d`E,g)Py@o%R5KS,b=ur#¿ R&ߥЇKw mn5fPߗJo)weweo?_~~>PGP ?xz221S~ Si\ 'Yd$4{l.?hgqakl;."ϸy>fxl'[dGǸ7"o[a1>\"w+̛Bf#WYd?EE-y+X@WfUy1wJ;R++s(ey&Bhy>\9^7""TiO)_O^a(*_l?Tu&S$=vusF7<>\'~NNNz |Nu'p_n'0]S}Qr־hc?t1o]/|zt}]~t" ^z.'}A>wCE~[P`ީOiO %%aE.7^^ wУ#7Hː/=\~5^|YxNj/kx_zZ|< xl.Kj ہ1^|Wߨݘl'nL}ۍAy}z+FBߨ|>8"׍ wq|vcBA#?76n/ٛR ;|qo6_vOi|nQ7MW=b^I\ JP[of}Y6n0_cP5?)yZ71_*ul'$0A_>_GI '0_1a'T=|=PhL̃h %|yS͗~0E-Qz7z3zpk![ dc[G.V1wU ~*a?w[l1Vd<_bKxrD=ܶB|n5{bymblˉw/̫'wqr ¿_Xc}־]^|./^.Ǖg+2vlU)<[wGc]|!>^zZwL4u{w7wwTi~\ ?ww3;}\[ [-N˭;DBBA<$FI'74IN7Iq/'474wW~w߻u}Pw0X.s%ݵK6ul 3W~=ݭzy?ow}Gw> Q_A=#~>~s֛>#| Gzz<> B롾eg>ݏx'k^ 7LV>OϠNndc:s<` x޽^~R`޹W{wh+Qg[~^+3hBW|xWd>kl0ߗ??pr7ס 7}M}~yVy'g~ޯ m{ށ?b0Uk9x?8W6U\h~Sd}yX+Q,mнO~(^? =;ٗGԙw`_ ;|߂*}}|P(C?()5-|Z<$?߇xC<*AT#s둙 <2Ǣ΁?"Gd#G-\ӣaA~mlQa>~4ݢB0ojQ Oo_ O[ԗ'W|2S-)ϛa^~>)Q':m@쏞V-^<]jQ+Ӫ~Aߴ Pjq:|<#QTkgĿ 3җ_P?ψkk`OJzg4]~=gB5Lg~x##\YCgUUзg&gŷ_9T[yNnl㹉}914ޞS}=ৠELOw,MWMBOW,0i y^կpu<m=/>W!k-O Z8 ZA_P' K  =:_T:_̵h/NhO/Nh~/Vu}?#ˢCq"~3^7cE]/h~_WE`kOس,:1vE'l_Zt2>K9} k`OF'Ңy{Yx6=/gXt3rEK,93/ϳUzRNE~fYt[̡L׾;Sg/A7S4_׵pt+3Ȣ/EyeE_+ǼrТ + ըWkP߯*g٪0:΢'WUo)}[)=lNW-.UjE[t1{-̢}%[C^F}mSky}x~ }ԢgTob>|M7R}gZ|iO/ku%몇וϯ0>բFx]|^_hы__0ko137ooc|C}}C/n0C|ߓXz{C S#MOߔ ߔ>|)}X<\eoצKUJ%Rc=T؈yTVKkdC?RT[V۷o 濷v-jߛ=~[Bγe:杅-=o4O.~G} 9 >^6~G|i`1^\?ńj1ٰ'ZLg gYL$}b|g,&,|-i݅ÿybP_,&^$~S#7bfYL3^_n1){Bi~ŴV«5_xŸu5'bڂ_sߜ XLO|U[d~[ ?~t̶?UsU)j̩kf1E} |#2-M5Y-ٰ'Y _)ÿ@~>P=b|{|@>P|/bf13p17b^F}Ͷ37bF?[h1U|aޘ;<\w.;b>~]a1QsU?ߣU0??Q1/|4N6h#GSC4ӼoϏ?J D1x|,ߏw}t1'+͟?1sI??3I''o>5+ao n6o~lO=o~~ڧog-j.N5tOO.hW?j>Cg-?,`lGBC?_G#J?O7R_zLL_g_~VoP?ol~~i}`f|[{3҃ǯeת՘7/dB:7c%o7z~ٿU翥{KK`1;F}N̿"VEZo;Hϗ/ ,^-~F\$>F<ߊ{׷s/o5O"ߪU;~+}:U=~~~w~w?]/)V"w#kzr~/ߋǡ'a|KNBTk~޹L|keS7e9kbA|h(濲iQe,6AYņ!b}?4X_?dZlr q(Xz m A맢>{-'򻸥KagYl/cm~^?ü?Xl_oqy#_,6x-Yl짖sIg>Ϗ/d%BgP E;bC<\x]˕QWyl,:e)˲^)lF^_llaYee{3LX >/~-xrt֟~ļ,nz繗?wV-B| BP}M^z"߾ }X0L t?Zlq! 6ðJ﷭L+ŧGQ?++,v Ik Gz iN?ͲX^O[^O ;J?*0߭i3U_gu}Yǟ'gKoW" uǷGK`k b^\-}n|륿kT+q4 &bF>ȟ5g i ]#X|_ׁү ]o1WL**ć_ fG֫9kzR [nC=k_,/%"=ڎzE@}Ry߅|=VVc¿xU|U;ת>\:qaD6YyDX'<(^:k:w W,OQ|_*Ͽ?TN1OJ$q[?*w_8S~ŝ[?OR`϶8΋˄w)jz[_oq =ڐaq7Y\ek7L~ŵڠ;`ύ9mTZ/q mߍZbU~*8UXUōC}Vͱ8=\*Y&7)vűoM-^7>|_Gq_'Yי"_dql { oNYof.,5]-[],pWOw |vY|g§ ;3ZbݡK2 [^RrޣigG%{-''yr~j!{g@{*,~ y?&˿BHooy{+~?]dJ~Jfw_HOtWfQ?3{_ -J^/_xϱB_Z|< _=:n#@y|u@NQ zPX䣾7b`7^[.?AT/1*x~סi^=h8`O ҇'P,~*_ŏgy1" c!h^ߧ)1|G:?_cCoGwX=y_|u[R[aˠ'z*[ ֋o?z敍y1PDŽwM!lv쯎 1ޚxx99AG)` 08Ck#1ǵqUo'ik} :eN9b xR N/t7hk kp luq6l58l5t!l3|"zt8's;ݼ.@퉲`OT&?'=xBت^S\}O o>l[J ][x^dB_"U[=`[-C?\h7RHG~+< U'|OkOU_c1~®Q(3Ob EMRXW[UV^=^lߢԯ6B_?QhS4OK|x^;|q0ZD>i[oۊV{m'Fdε~~%\=_<<jKu+5O 4|<vlKK [\k5KO@˃w)POA*K= ԚO6C| ɖ0$YBIB%\Z[K(B ,Z)P$̰wbyqi |K,(B](>?\гLK(~%[7?,)#I}|IRNZ$Co'Z W"7Y2M~̂'+~|1xy締竞Οj c  P 1^`0 E|q !@Ǽ^GO ЃFaR,KK#k!in$>ğe5m '-%F,b]qKϸq%lzoI]Q{y}-'A6굹5c-+,5ۚ[^[%AjT[-i/~7آ<--|Kl:^iZOZuˀyo K|*vO2oj):_eo[j}j|m%>wz]U%vC| 'vZ}`rh8k1R=ebɖ,e[#ZUw5&1'[K`ͳ)M%m-RQr䣍io3@h7f%^Ows-ﯳ"7U<3ϖ7RGO|Hfռ_|x.;a[]7Uzz7*O߇y~W[E1Vm-A-q*V|}V4VaEۅ,7m/ATӡm7/@*AڅYKX⛉x)?bn'S}Avf l-e|K|BoK?C?l~7ϵO'W?͂ P_O_a~m/쬝&|&b4G!m%Jjka+4y-qZ%w7?tHD| !7WAztP}dTOըvs|5Qz@GǮBң5uhI:)NAs';)_N?߷z< }I>^9];ג¡,)|HlIGtK>ϒZ ,&}%N`I':-) s%ŭcIuE ]ňk% ]ϡЃk8ZbI#,޿ВFŸZkI_%|lIc4zk f g:Kzx>ӳa+ϣzY 'Zҋ=KoT=yg%A _`0˒BA-oaInv!le^Kz*B/cKz1%|.O%#>ŖG}mɉO%7)]k޵1M5#ɭNS`߅ZWB4w6Xr:P-8L0v5l%߁ [`wa$py7eNQåwoFKKsOau^KhG~7B _K&Xr dy7c?}BXг ~(桑ҷ)w.Qav u1QC:qeTGٹDZ%<:n`I,K~ /=x:_z[*f}/|z v--BEVeÞiњGF+~F+?ƨlccc??>Xc=FSƨ~ߌ<ϻU/#<a +g.4/?8Jƪ^_C?+hlzaS>L@B 4 ??;vJJ>[**VQ*J%0a b4, 0WVF0ߓaXLJZ{|ޮqt7$g"]ox~<i湮:ffwU] 횥Qo]OWaz zӎ1&hY%^ׂ :?C&TO1~{ GIo7bOߓmzI>IďΫC߻I[@[2ن)? vW o+ .]^r\r'O5F~_{_bމC/Y2:T`!z^}Ql>xL\*`z\3G3ެ j/揞:oy2q=fqǏf_\ ߍ ^è?J#ؿ櫣_|AՋqIOlO~@>TɘTUy|o>'x]C-~o3?@{}-l?~Z <<ѿþͫ.uoe_%W }_9kzOlz\06~._5>ku "V~O|z'}I?.~D}'\y y߁WkG-}||~~xc@gsԣ~d3`c?՟|3b`gmznM `k޼V"mqkANjor7x J3_'g7 J7|o~58|u|j g U04_5[QC65D7CtyqCTK1o )u7DAC)>{'yJޅSϻ vޓ;|}x}AR7C?h9<Ѹgwkuo{>TAV/0|C a~_3nXF@ H7ZFòd6_|_>nv|[Ÿ~gۼ.!m3 7\óͷ 9|B> ϧзuX?UKX?U|y<1U-fzlb maO7X/~?>ny u~#:/Yq(l졉wHH.9R#߮пI曄z)=|T?8Rzl 5]Ro0&bC(ƍxydz(a4]ߗtpi <?gk1/&z(h7 x>7xV>/GX G Ѫq\N|s3Fc:1pޯ~81 g⟂:Fyxy0CǪ7?U<TJ}e }+}9V+KW>f>]1MW#|']\<52]9y3]\8q/D=@_)eoos\yƻQ/GOuxjdr]z"nDWc^_滵|ׁ_ż_Q~5C盓2-d]?3{>#CxG3TO `Ga ;9<7A-MHuqz_77c ggԏ7>G<]3nc =ԣ9N,5瑉w՟Kq|!?Zi$K5x~>)OϤoOR2L[Lg~)N L1L Z{ 'S.7ޓ[c^c@>NV}uON4߃Ɋ0)ҳ#)-WmJGc%cS 5Ag~QT#OU,cTq^؅{zxjoYgjY:fYIו+~^-K8/g t|(3XOy] Zzl窐g~ 4MtMuo ~Qa(]m3S?C?a5LpNuay|XQJ;'zmoLrR̯)1?/ēSl~7w#_1[,Z:`^נ27&Bfu1KDsv xne~w sfI9[CGu.El~>xgNs Os̑o?su^8>q}n[~ r\id̛/ou{'g\?`~)# >50>6H^f~-ƿNo^V s:Wo*批tv|_,`~"<՗ȓ/@^y5?y7LG~ͱ"_>?>q_x$=e?@|?诟(|'ja7c3e6 ۢivc2'yEs^ü9O|>~euŧڿT{x|*}}6ϧһ 9|WlM~u~c| _F=W|a//>dcc|Uf ڿ3Wj+?i+30/@ܟ=_x -4^`BosZlŻuo&g:P>-2$Pֻ]2>W =(P~Kt^A,)%e7@_(^c~㐟B;J2g ;rŇP/ks6jVyk>--2LTN?K5M|Li)iײtf`[Vn~3Qͯqg/4YoyG~<͜MgukV_uHx΂i9HG[櫏QEһEym2?~^ad߬~Vh|ܿB|/.+BܿR__a~xq1-dU¯d~*xy՚GV_y{%_-__#COhXIĭͳ_jRVokO_ى rV4/W_auҿ#1Nzw_5/bb?q9W7~jm6d}K]φW?9S[ޭ7sK͏o_/>/?Ŀ1l9zADؚU w{ ҿo9ГnslQdF낭QB?7ynJ40m6M̿Mղkfn5 ;/菱7w?l~w`~߉|}Ja:i=3q#?>SيgGg߂iߖ/-%}-7E-ysDY@qŕ({J*)s7x|/xdf'?6G ||^/hia3Bx0漉|Xl3Uxn|U&øk?zZdVMVRVΫkoi?JKqWZcO@Ky3z[n[Gm[96C?Ui}9o]._?=p^߮X߃z~`/UoO#__2gP_v6g_sK{?_FL||)doY]JK}mEv/ҏߎ_GiD~z ݏxwJߝO1^뻤Bw)]ϮJ.q=*7G1K|P.t =;7O\aKiyѻ9aҦݩz;{F]fni|~OksE}I4[H/ ==%٣oekG{tfjsq$ݫ~< FzſVh +o>oB*{\O? 7}Oya =ڧxP.~9|k3ҿw!oA}JEJzל5o/ 1uU]Ja0R|Ys/?ym5= luaS=:zX|м<(>.FjL0*CU*`r? ;2"^W}?+!͏ǡ s <ɿ!΋/BZx+Ř+a+'o^ua{ ;| G>zD_ Q۠Gv+(;ǣ2Qų zs4GAOJ_|+#w>c҃jym c4c Z1<291͗w*+wfU+OYL[xG_j0:ԣo#O0~3Q|8~\׊js kЇu޺:oV}ߟ'y7w- ?'TҺB' j+~Cŗ?P՚O{λj疣>Q,obͱ 7Z{VzF| j^}#|n~Q66Ŝ͓?e'es,-nb@9b:9nB<'y 񰕯e΋gm_Դ_k-SM' dXg]Sdw\z8>bܩp/8` ) 1ϜjzzJ#[sN'Z@ }: pANY@tg4/~orΤc19SLGϊa^:>g,ؙ ;+ΖX߳UvN^}?AV]|˵Gb xtb~q^hN?>+0W?g,yY)O`gQuJ:s\O?n9BnB;UwZw.v[zu!^uqA5]P.>` utG.m1\d=󸋪#/m,oCz~U_jCQ>_<uIحB?񳠫0_ao*^߿> ){g֟~W=O)ޯ tS ~_QoňOvGKXZ /Z Sx@)3O,+aМ/8?u=oSs5K'ϟV~ZB C[O ෎3`X`!V6oho\ [9[c=VfΈVu}kͣ-w lts)_]8l4Q=P []lx>oհ, `,Nc-I"4v9` :9昃tKkźxW-OfO{XPsmA$ncA|]+x#:$0 z ݠV+0LJ 4؇-΂^ufA]o_F}`AL>7nԽO7fYPs݄zĂa-h z}4kn+>ax9f¿fɲO3sY^mAcra鱰k&3M-h2&Ô ؚ}6!7 X女O[|.7|^sS]nA[tvobͪm:o~72G6YztwܜfA;-hg| [[z=lWk,fAfMx-x F?Ex ߧ-w--e9[4/g[ˮ_ЏWo明ɂN+;]6cAޅlU]iAq=ῷ*=UnUz7ֻUx7[/[s-?Wdxk7z-͛[p$knQ'[[p4k.yތ~\a <Zp ׼D׹^9>? ^| vK ~0v qGG ~ uG?yt n #ׂߡYo3Qm;.[p;`,๳D3A;D`ɂ ;ow^ߥf}Kxwua-aS.JyjsL%~haiدayZtXE9S3iQb,O Giz,x<~>n`xdsD|wk>B[sw9&#eӟZ DjqOx|ޣQ;ނ9ݣ|`~G~ޣ|67yp .^Xg8O#KЯnE>|toD>^e{o%, >x>,-|3aיc۽-KPlyւ}Nc'ۂP>8S?>ד~~ |I|? ~-Wx*5ȯo9&b^/  OAiOrɟ/тa>Q r̉gx1|S=/"_ŧ qw ϰzooҗ៿ |/?KZB\D =@1O+Ut@oK>%(}FOPҋ?z;|(r(|cOכoF>|~A~1lPBrU\؇u\73Їsy^uc<m[etmd +\]YwN^y\|Um.몹B{ /D¿xsŠ?'0('D|x9Rf·~9|4O&e7PPXm18Ojm >oC﷡7a;?ޅu0WI@s%`lŇI`~ ;lesuKnk3\Gx¥Qs.>'`/=0' 1W JG7%`$sJz?!Bzh0od9Ұ^1uxDj~fW9Gk(T+]a45R#kj Q|$v>n/s-@ݪ5?݉ 5?y-|o-C«y`ͨ ٘? Uds:sqi&z\۰_LgGb1|~_%z.B`KS/I@Stۉ> OUmKo7ebk`X䳥{Z暫elٲ\OK?_;W>o߳\Gx_^~q|g_]P?y \BohQ~OB^mS*u{@9~=(΂J΁oawXAx=(<([O+#JP6#a+ЏV'n? hVp@Yj+zHp '__TOWCPoi~uplpGs^נK?.ż7湇U xIgl`H9{GJ-G[ȍ,&GYW}uYȭu)1wol9r-/Vg܆T3r Bh =B|Iy4 Ͷ'Q 'G5XH(1_"cKZؚ|@ :y,~c-$ xBcU<&ğ迏7ǕmA|6Bޏ?'GWl Dw31u+ y,5u|:BOeIZazJ)şy1>y#*W>ʠwOK_`ο?V&^|S;IiG3ڟg*\s>[i3T~2>+ |Vw%"g< ~I;C0=GcxV ]'XH;w דPO/i/wQ zۜB_>/e5EZϋ7r}wZ )~z\濍5l/u%]K)_/i>؂|^x+u~WOW^Q~C路#X$sWTۻP߯9J 9 ^Q}>[w0_?oV>C^U?U Mu5s5Z[ 9_`ה6 ϷaPyQ҇玺GT]w}yK.: z䣣u){ץ?`ץ `O?b/=x]ퟸ " Y/\Oxf7oX w>X ;7-/yzF Z9F9:oM7ӛ-:Ǜ)4vz!_oX(oySY;f5-߬U NSKGgfN xuJЛ/,2 wZmNz-$w 2 ?oހ%@=fwr,-w7{B}aX?ޯit1. B=xh۪Γ #v7o_=w_-VZ9_^d|?ͫ1Shאwd#wĿY˚yn֜:;gXh4UY-4mzAmw^ﶷ߻]½] zX>lO`胸з.[+EzB<.(So fu_Wx-d ]8[],ԃya mw>OB {V|z/aI=M;Wq>HB>&B~ Pp{J^"= \g7c{I7E ݤ/O݄˘G)2zVg{'v }n `ZhwOb p[{- G-;ya& TXX/5 PmV lfax>g`%?;92IXxW¿!W}8uHG ;lO0~jH|8D@ZUSXy_NawcC5Pqm@;1jo/J?o x ka^Чan o׷Q/:Z76,oCe#a~;yb[=gX`v,< Ux ?|[8T*6ЫTM-* ˲'#AGXЏ,e;#[ψD xGYxtDwƼ2».1ggg"lx< =RH~ >IoLÑoI>,|}G>GVXx*w;xFO#p^%>D~fG)Q (cRl?R>PwQ/ja+31_ÿ4CWi~~f94Ӳ-<s_|m#M/F>#M8=mp _GKO?FKOׂet@>GЋh F-|w#Ҭbg wߎwtrLj?{2`Z8O#l﯌)?1(5V|ߣNJ29y>cs||+cXZ^/XcoW,GyҕqMW>~->]E=OMϰߡ"2sv5$®sDq:_Eqz=Ex~%Z g\EeZĭk\EႽ"*,nmUon>Ї0"_,/0ϲ(; skaQktf(~ x|{E<=?"ZAd, ̯[D>"Ƽ~E`ŗI1` ~^sbG|6Q|>L̰牪gbE||'VZĬxصd#|m|$E~'gR{n_,bˤ,O"8L*7/ߤ:|&]Sfssvy 93>?63M2 LiL/S-&˰du9r*zs,bck%דF'˟u_\X~O6a)ҫ͸JgXD lz3ElE}L?xg#r"DzYD晩?o8ESտʁjɿN2Gs-ߏOTo//Kۋ%C|Y?%B=d X?K̀s0"Q!^~Ix>>H5G(<8z@׎b@P_o4BП| )wGQtwiҳ47s7Mx^MN"iשxitwL1gOt,.-?nz9kat9fzE\%l{O-~}̖>j -g_d˟_*5C73Tof4[x؏/3oz4C=Sz6SfJOA}͔b/63|?kYcy" - s9P_j@aE6E}}(lJя?lH/M"9m-9-c7o9,f#"Yfo--vcVEy?,Nmjsyc @Z]лZg;~3C>g<|ΰsx:~?uf<f_Hog9|9m,x؝-^9d/;sSis5ǡo^^˕?׹ S[d  ~/."CQo_#G8Q+>~$D~?JHwLQ>*Dk^b{s X-%EޏqE>>m\d^E>Z|]3g2vn +=ilah{LqnE> +CΕ?J_~XP'|~Io⡗y-O/6G_Ɯn a߂9Yz}\ G| .[-ЋfQ-,6BE&ZгiQ -N൰,ﯔ ZXgQwfQ}XOE݋E~ /Hxj>/Q<%W,*zY|_`Q Ve;[r_PlcPǵrZk|_}>/mfQ bEmD}.dQK7OT~?6giEmzUz\z ,ka-V@_IvbeU|-˳2,;lQ>2E[.[s;XߏZ.K/*ruc ?a].~F+?'_-Q$~U ~)5.%W|B?Z-Xo [kTĻ^ )+tbE^4͈[̓+s앚o+՟muZlQJӬ,6'wRkD}TjxWJ?"+tu{*哿oT߫*n@TuПU*'|?m9Ga>YjEougs8Q3,?Dꟗ05/?`5҇Ϛ#FzߏY#=i?~kğ4Zǫ3_+x/8bO g~Vz]W6׹,+\ЯuҎ:Xokau5uߺ*yvg]E5_[?wX|w4w#=(87y.^mno[\f[wqo\o澣 vss߅z_27Zwo;Ļ>|Ts볕o}}1/z|?tAW_0ؐbn 9>o(6w(׫4w8ؠñF[ |7v27fn2wK໱ߍ~n2w+Facq]7;ĦXs? =܏C/7I Okm zTc'>YYbϓ S$߬yd,[0nV>7N#_zTгįg2`ǛY sE?,퐿V3}VaM~?wK3kOmiaPu-m"c| |"<_~[TP[7p s>oĿ:+ii7GI[swz% ~ a{ez{E,]ЯJ/ \Ͻ s7>= `w68 \B\y5i-&|~.>/7oM>|3}3x|oA\O_T)^̟_\Et|ƚ ~m)xpk*> C*k68z(&`^(Seeҫ7Q`Q&`>(S?[4-~ۥܟo~üK ;]Wͽ.<^ͽ =o􅟏*O2>Kyr\x//Wƚ-;~[Г׵nWV=|[>g [>(ߧ=`=:?b>ܣz=Hss׃{Tߣy'G5{߿Vm8_moMʽ4vE{`Y [cx Se7FTZ}"ѢtsN+rɯ}BUW-Nۢ)-E6DlM~K15~/`_lE@@_x\z/~Op_LE/yi5kr_76m;Yt 쫁}Ln =Jx?9﫫VVУ U&?*CRxR,GJ귲ڢ'[^ummPMq@< /-?gAAu0^a9I> Ais`51Au֢_D^Q/T/v[+ЯC!5!Dεh>~ |?TaΩw?~jۨ>;ʚ\|uE|Nwé8g]å~xXzqXgQ?zOzGW>/Xt/:Z6דAlNfsTw}h^ϧ?}wGU/QO?2_[CG@1Ic-z0:&A:&AJߗxc&J;*ZTJ W%Y4J*o6V%*_%UIOޏKO>EDž|?Dž\-,z,H-`@/K7Vm5.Q[zP~ykkcg篥Oۯ "|_O}8P@OO(r*𯖞cjZ `zYl"?hoZZotzM8)oj-&m3n1 o[̭ o1o+,W,&9o';IO.OfdŸMyaٵO8걦l{M+b^v|Te1\o ׻j1-)IO[-Aw*bZ ,aͩ2yxX>1tքw<,yi;pb3ii˟DI =av:#>> 8#Om<6b^'j -=_zy 3a7XsЃ-,esV ϶YS1@ϊ_fNp<<Ϫ@?<[l1orrz>[m1oc8[g1@Ιt_ItzXLW9g7% ?si,9c>:Ws=ڹ*E)o:;{YL#\g+ޘK`>b>:/՜3,kR ~@K;~*kry>`1q^Y+f0V'Sʆ%X021?ꔏT_Wd1#Q/uQ1z| ?B?ӹ>~Wi1Qߩ= =wA/dWoMN ߓi%Oþm1T-@_.ZStEu^P/g#_L_zcgZcrzq{䫾^.IOf%s6$ -&^R?5})#]i'tBT:Mgf={ȴcB)욙N*BaBQ4$JM)B(hR4ѯ$%=yRߥR_ ={B}g/_};,x;:"?KyU~IKE߾uX&_}Z}/}w?|ۏ~>7V5-n?+EbY۲_‡gow_ޕu='>PjG߁P>@P%Je}A+zɏ2 n b m |DCސzV>|?|uxB!$+!ת{noD=#FAsz0Wz%"2^bs[Ex;Lys%=U'WE|~ {V=ȏI<+Z5+~{O鯎0#7~Hx;_ }[dG!ٿ!Ux9B:*ruLhs'(;cQj>b{:.: _Nz'+E&>OV#_Ϥeq&ZG?D߱b;_c],2P9\~i⼒ߪZ\m韫 ,ǫOOs-Bw],x/rurO/-;_?-;?JIAb3;WuϗgX\zpL%K:2w?{ahqYDoq"."׼""~i'.?k߰[+r;l$2\dr큱"S6E& W|ֈ|Wt6 FFcL<-|6Ld2*,n|W#>ml$2Dds^OP*2ꞳMV%22~-4UV?JSuWk׵jYb㉽"Ovyy穾u'[d|~mDrP_ψ?/ \ogzC}*2CE6ϧD&i(2|.2Ӌ//?PKgL|{]H_-2X$.Ğbz=\,_{"+uDngqKWD>V$2fE ˊEfOgzW2軘Vm#VW٪ŭ}u續K={[W+jΗx=duɝ%r9\/zԗr[=%"3ߏDacw=Tovq̿DKZ>,MdAa}ԗ g}k#oԇ_5º"c$_;HӀU_P?zۀ,n4K,{o YU[}c;d /?R7χrC }φ^CS!EӐxRwI~|軄"c?~0=¯K̻HK6\%oRJ>_r~8|)KW9aϥ̯JRՑRQՇu|u\2uB25bR+OU.yJeEޯ _F<-3e5;O֨Ώ6_-FJ5d 暯ؿz](L#/|y]| .^jvDy_ˋWWuyI<^>|%/_f"[w _Q|$hbe>Wt4bYߗ|w(5~ bk*Efr8|5bxllk&1l.q|-$4N3_K8bVbJq)󍈼|e|wQ+ͳN{wEKӤԻ&{4 1&i5m~47:* ]M֙ +^մ:H|42_GS6/{+̗f/)߇ 7l%¿ʆK vTɕyG b$Kr|u%|X+7Z\|)f3,o_:K>j|3eJg1E|B3=)B Sbۧ<#%|J-0 Wl ?Dz·ؽ)|і~q-ywv5 m^|>GT_!kLg?8}_V;@S;PY$,Y,"hO]"=ӯ&ӯ.=^GU_?e~oث}ސ|Ie墯|_-0 /qԣij/oJOkßo ?QO}q=8{} cb_JǢۼ+%^Hׅ>c_NJ}Up_Od=g%AO}\O~!'nT}w#z#ONH5bK_FA[{W$?&_$%_?DD&NJN$E[%%2~#}O/g;_lͳTdS˿EwJ> 0~OppJ& ky^w/Hnz$?*18 }~OUAOت&/$\d_IbGGl~q?Cԟ}B){E)K|ȗzrP;zH;9ռk$G_O&UI;uJL?XO2ٯxp,Jd_jqjI5ԧSϮig7ek7kek-ߏfy^w /׬x^=R$tldK|w[|-O;YWue%^;ΰ TPӑ\$X,XcK}ו|rmG'lo"Oﯝ,eP,^ߟs~?00~Ri _.Iabo"J`f/X|sNG[=:1(k/4>vZB<:7"N->ZƗgğvY(N-+<~%K-ɟ*3[{uN7yoWjOx\a/uͻV{]*I$]GvL̗zy"J|\$_CRdj}],Z뉗Z\3YeWz⹓ yJe+,RC/7S*FO0ZbK^}rQo2I+o.>"U`]>"~>ⷻԻ=TN{Y|/ G 仾/ayް K>x9+؄ n$͓ߘn%odJE.tw73ž72;g.uo"߳$޻G].- *OÛZ|D}HwS( ﯅o~\"}3/" <ük3W{3Gﺙoa>W-SQ-?Bw {Te¿[6[m[Xו|3V}]ۅ/]+/T}SV}X_7;Qu##FWQ'1_7;U׍: Ţ;qdԏG?k;}Lٝ\wr= ϓtOI< =-ۃz!={_{Oփ|g‡K#Q~Qo׈ӘϛR?{r0''zWAO죟g~{0^ԯ$b_J<"|%~mwbK? +2[̧RdCm3k޵̫&z·JaorTwy?݇!~a?~=-CyFʹ9.~^KH׷%6KEh %,|}YBCMB OWǼI/|?X_%_[BKHk 2~/o` uJKVg)PXп%tO|B$KA%WpW[-g,s.m =>&wc㧉?`~RlF d?4Ӆɟ^-!C7p%h?2~?Be ZBϓ߃fXZk wM[+<(KǾ鬯Dǿӥ^5rK!K/O0ST9ψ +ߧ#Ket$g09R2FY\g[Ko2fY<7,aw@_o ?[,a /^*DfKX.˄o+䏕b̰%~g52x$,bY:g&}Oy&}_I>@_&XA&L9 mT9񲈷JE&n~,u^O>%"2P5 Y3YO0E|&Wd߅Y+fK?d>+S[/|{#.'?|?5瓟?1onn%4ē쫟w# K7V`bFw` vwA/{62e>_n"3%_F7%o+_f֪y7  w FCoАc_C#K>ڦ< >}.2;ٟ ]k/OCg;ϡ =`/2"KkngN3 {'K< m ̯o__, Z<~%7?m6w e4]O{J,cҿ51@oQ;}X_E/[USfHSļ_ ?VeiKtԣ?^_{QwULL ߀,zGgKm{%_k?#%(2'yeLkψFE"WebFԘw7#+/GDȰW#*#ǚg$b"S}KyVe$|S;ӣZQ䇷%ߌ"?#E|+5̼|Gmf|Ϩ](뺨ho4|_frh\?zymYԃ%GWp*<%mu($m]ͯ?>|뙯_}Bu|4"ryH~ÿ~bL#<.|=_zr (_6 ?l`>occ1.w,Kc|?FxlqcfߎJ;ߙM+ _^7yΓ2y ż<8U7|M8yqQ8ߏ2۱=)Jdg4o~"v'*/Czۣד$܁HA=9*:/Iռ[e,>J?I|_f^[g" Kvgs }w,@h(" \Xr,Lmr]u,  ۊ}kvk|2]]{-/|%_׻-|r$ $w"K{BW}5Xw_/OH7oH3,*H| ?&0ARMY C=Ȕ6/[ [9qr$~'ybkD7e=!_.(x9Tƻ{ =e.{ KFkQ-0Zson{oI=j?y//^q^q$q$|2 ~ن'aɲ?xTߓ*VxLw>dw2&L&뱇~?dAՏ}|?KJ~Zn⟩k䫩Oo(6 ,I>,&_|X 7xEs4 ,Çԫr,[!32O1i/h<,|!/<oI_ۥ"?ߑ}]Oohdv?Vc%?O|"s?|Ts-Q'7zl/ebf:W{?< ("!տoۄ?0%O%?N;/OiߋO`iJӘϯzʳWvyP'd}`‡ߣD$wxOC/Cc>CKԧ2U!SK}z؇}$N34>"aEo4"08*}{T+=K'$-pRcI%GϓO3oMWۂY<ibE#a< z$bZGf|-e6?mh $?{:K}̂I>Y(+|Rt/bzW ^.L/2/2>ɷӗXPH^ibj 6hn+?3R-L3?3J,B3[[>X{wcmDcE?1FmU㷗|8w}3~'g/`ꣿU8awX0QO^O4_ J< ⳣw׊u-"d|yf vLq蛉=ΜmTW3 "oU"|{,=I~IT'GY'^ד,U'YGOV_B)EJjK?c O?iRʶ`/?5͂%~}$^Zm]61Sw_i=M'||4$K~xz3ÖWiKE|唋o'EY,8X< Q}kY?gUX@,S(O=JLg.?߂#$>}Fa~DI<~8?e;^=K=6d߄6d]_xvy.z|y#|~+sa9'K|=G*~N}ϑ+e=Y9ҟ>?/jv]L~`6L~8<;dibgI5e̞e%_.css˜(bN̩l\g.;%~%?ͅ?/>%w>Ϲ{ߗ ȿ&J=}~/,~BoO%H~~Y׋{-E䏗פ7J~nKץ>K9](1]R/M`wLƟ{2_bR?ߥ W(#)Si\ 2RSSJY+9ԛwE|:|{x|_s>@KEf~}Wc ^? ǒO$O\>[/R}ͻG`yƋb/> /$?.$>6J[HIBeˋ*-eE-|H CǢY\dF(y/{xA |_^f G=&Y ?V |~Goqy.]쵘x /?I<,f?K<,&w`cPO~}_%B~{y%z*w@F{F}U5#bרGUwLZ-e'ľKɇ'DR5oK/ՈoKշ˒LmY-Ke>K:OmYK:_-dI$ޖ-$ݿ/[oI/ Pe^O SE.">$?N4Rٖtt꫰~,cyK/hKj TKj(G,ˋ-RՇ=.|%5R}r +Dߊ(Kj"q7}+-JÊ Ȫo%5>(o%>mID_%OY;Kj-yae#"2oʖ6YomX2VY V-)N}eodѷx@r^9ג%?^דmo%K~OVOc H>YnIAǪ$X5ӒB&=VaU}㍆Qᷤko`XK$}êo%]'}NDaT'-;Zҍ2jM&2Y"dK*dރROVOk05!~f wM%?L5Kf%*]=PoGI<Ȓz|K&Q7GYR?oXR_oIyYmI%E[kkfī?y "^r%yR?:`ComC|mȒ"C|~g-ϯT(_K=ކREoG~ڷY(շŒFKMC>T.tWޡ&0]o{B_'şTaowX=w;]w&I.O]=E.rw]]K*#?'1u_s]yF>{@[G@/~=]{>(~H=[{RrKzT=GEԯ"DžSߟ"j#>}Zm ;KY`g%_gK}~?/Ֆ9ʒ˩G/J/gdRW^`Ie/皧H[H?T< /仅?_!_l"3+ļGg_-|Hi(磺&|UQWKzMGԿ‡f1俏OI}L3Pc⿏oWJ<|L]%1|Z15ϏWޔXO>xK53}f=_h='''\"{/I:~_'%|BP~'{-iS'2O>~JS/OFק_J~ty=>-z)J_Tg_]Wo33?TLU Շ}I n3TO [? 6) Kӟ~B?'9Xj×/?'~kğ8-s{Ff!jI}WiHgV2Bs-tLT[ noczүolg2̧kX 5oeK/ZRշBI?BDߦ( ].jS}"j,cS6Ͷ~2 onڀl)%$x<]͓//O /'YKJ/Gj-e}=ڈGW#bRbB_>Y_yKuu%޿_&~lԳwY(AZJ{l_컹b }73~c2 TN{|xWoX5boQ=!L z H~f=z `Y7^÷?,w~BEDm}[dTϷ o.[Q"Oc}nyľ7IYwԛ-,ԭTTl)B-.ق2\gonFw=K{}O>)={?DF̓#>2ď~e\/|a|~^d>[2e׭䋁߷f[(=U =%}ld|PWa>쏳%>+ZH[(Kʖbr*E~'\Amg[L|fI6emrm̓)m[o|mBɟ?B?a? [Ho?NWjӒ~,g>/dR/~-4Ja;bg;Mo'H~>BcۗXh[۱R~;ǝo[qwGyH~&C쿃xX*2  Ys'{?3~ ']e?Yc?ʹД(qG 3HgnbٿLr?ӯ< JCffi~NO|$k݉dd>;Xa* DʕGף颯͐W.co|UIg"I AӢ,/{-}b$~>/+|yA+1G׿R<Njo$7 R/yǗ*E&?|wKOB7 3OE/|w/ %¾d>2eȏKREƿJ>E|T2o,7B;LN<;_%;jEV<_~f~bK-FwDfNo~'}`V?A|#?O}?u{A?fv3n/~j7nE} >U}˟IjnsnF/ߛ$~)gj9Z'D'Go/oTL9o߉"Qg/w>*2y#vHE|$ߟ{NѷV~oEL{H^_bϽgK'h/`:(i/戌xkk}H|p\6OS7Orُ#?ԈEc~|>3Ra~?O%~KM_b[%ZG|s%:j{_Snﱖ\D_M~/1O/^+: %hnI?t l-Y$K̵_0u’J~=PeF|׃!Kڵ^zI?|p%7$\)rq}^Go_QOߒ§KQM%狾j:jcY_jK.{TfzyK9x}x%|r3\q Y-(d~ԟq-B;+z< ?NjO2RNFMI⿙w'Ou|v{%$nI+jXD_jH!?+PC| 5dc 5ؿX⿆ANյDYX)!i))TdƟ!s?& t<=<]e䟙\qzK?{ ~Jsz f lK~V 9շג?ϝ ~v6<'Zd=J bXd{IyE&JU|+}EE"w4-3Ef"ӏ6!2^zronwY+gZ ^,2[DdעwEr䃯_/nأvKf;Cm#~/߫UuB]ЎK|^@I|-]Yi&ZWT~n{ԡ(xIQ>.%~w2yպ}V Euuz?_u^5o6>{x^:9y9y9yj*[l&_GOױv?]ÿkwJ^?'y$Eu'O?~1Np Ơy9gǙqPc\skr lϣ\s(? ~#G߻up/\ / _dVk;Ny'kzvYϼ3?֟~'~ 'ܷ|;w|;v3#sd?2۸ommܷwz+[^k[f+l嚭ܻ{@׾ym }_qܿ|#cod썌7rF/x }}s)׬5q0Xѱ|5cF\׽7{os:Ws:W_Uܻ{WrJ]+c%c_  l `+VQs{/_|9rxm-eר=rRY |)k5xuʵK`-[c`16xe_e__Eq1E^k ym!X<2B\} -[l.;3|ƚXk>ro)ro)ro)ro)y>|K/"ksym.嵹3{r\9`s09>yx}NO5ӹf:s}>eڣ=-Ga.}%+/////a0zF}!{⾇!{郬A}A}7q4^=Ӹyy{`{o*M 6l*T}S2S;S;'O >|2d'O> |${{纉\7&rDu'O'0 nsx=gǃw;X;vƹ{ovtv;8ǽwq;|XcrX21a Ǡ{ ǀ9| mශ~m ݣy}4ь9{Fshxo=g 6l$H}#o$@#spνkc cøo C07C9Cg( 垡C O>3n>3!7s``y}0DAOEXGu'=y\ǵyܟܟ\˸EG.xzz8s_6e'd3N6d3Nd1Fdq}gq}&gz&g+,{37kҹ/sM:z  b7ydr@31p @`?X?X`Cg?t/X_`}/X_`}Kه1x>}Oo 7Xo`2ޭ~+^ދ{z/^X='cD_OD_Ol{d444K^iܗ}=:{Xt֝u֝;:x7n׍u+u ]k5jƿ]͵Ws\{5W''''''''C!x<''''''''A x<x<~p?''''''''''''''''ǃǃǃǃǃǃǃǃ}>pǁǁǁǁǁǁǁǁwx;o=x{ۃox;vہo -x[mۂǂǂǂǂǂǂǂǂǀǀǀǀǀǀǀǀGGGGGGGGo x6mۀ_~UW_~UWo 5xk[GGGGGGGGo x+V[o %xK-[ox -[7o9xs7o x3f_ ~%W_ ~%W7o )xSM7o x&M7o 1xc_~W_ވ<ӈ\ҐҐҐӐӐ:cc7ox ^>x}^x=z ^.x]u/b/b/"/":%vO;?Eu寉UW?jjjjciv~ 1c? ~(QGY> ;v;i.xs]2| ^=70x# v{.| ^{: .zOC8~\&eC}~po:+gf#`~"?}\)2oKdo<y3\\%2iS-rFv摔}d#Z"ruE.A@n$r㑛%rrrd["#K< _,0|6rXiȩ"E"2UgsxuȽEތ_]rru#r}5rKD+B$&i"W"yrkg<y)z)z)TdHdLdwy(.~E>Ey5r+Z>>E ߇·hP-|E=(|:p= Y]8Y_Q^M^bL#|/؍,|/o1#|.O1Q"çs|>#F\?b#Fb/&Ud#|·O1|#|/FB÷[>|S_bo/Fb$_ 1/Cc!-&"2||1dr-F<>#|b[+F<>Ŕ bσSԇԫ`#|sMjxGxG/1"SOb#|1Gg=cS)1`G=UG}Qbyy1D9FsQby5V_cşy5VX56Jd+!J~ȅrc=J>ȅϱ/rkl3VA.|| _c%Xk|XkPc#"Xk||?c%X793VM| ?c%dScEJ>Ȇsl+  sl[*2+ g,+ς_,+# sl=VE [?|+|" ߳7L[)2+VIgX{&g:g:g:|gǶvV΀m;~g V 3>J̀om?r/gǶtVJ>Hm$_ïW[ozVC:g[tx!#$BwHd>GHd=oH$ !gWH5$?6$ $ /!gB!g_86>$ bY/&4M3]EL~o%A~{/| ^W_o]..x >/vgK\u.f| ^}n|@]<]]l| _l| ^oqw5|>0. t||wn. t|`]>@w|`\> |>0A'ESS^2'E}H)~>EN=M'E ߓ"I7RwRo~"Փ"I~ >xR?urSd);K'E ONR)2]_/<)pO=)p/=)_ {Rd@=:>yRd?A=tIN?IWO'?P=ddDfINIO'8g'駝CNO;r'9̓&2 (|rΛy9o9/yy@s< 9o<>;σgyPGF wyΠ9G A|fPO _zPW ߝ=Q&(gJ>pw9>;ǃg|yP?J~pΧ#"_A?'>}b/}=뒲_{>_7OoOgOwOoO쏽^bb?>{{߽X쏽^,o/`}|\);{P,/tg>bb~{{X쁽_\-eg>b}b>|軽^,eŢ~|D/ߋEtb?}b7>|賽_\+eŢ>|诽_,jŢ_!eŢ~|諽?_,ޏ/E}b_{_X׾V,jwJ诽?_,k>}賽O_,lwI賽O_,lC>bbo{ߣX{߾X~}E}b{^B%}追o_,(}=J%b/}>~{DA{$Wʶ?{`t#ys>|aÞ󉇻iY=y<?gs3y<x3ԗ=ys|Rv3ys)ev#yӞ)e^̰yQȣG+Rn=ys^OȔtUQɣG='zO?sw<9Oys<1jLwhg<>ۀWS|k+gGr#R'?uJ=)n~UU+}Oyç=it%[K>FT|?>]O{ŧ==a(ύz;gOӧPE=GMEjF9Jhړ宬ĕU;]9|#wMwmV߃fm˖G[?ǧr8jWG{5,珶+n}+珣w7>׌wi᣺ߏKGyy[yև>r~mCy='>:ʓ>Ϗ;G{xtG{w'9ώ3Gwy=:ֹOo_c<?:㏎M__uWoɷqoG>'Е<=BsΞ|1pdg{KMqW1\Yq\F{K>N0/S(xVI>TyT>9:y0*ƦijJ~T367c=X~dlJ|{>i:ֳ?p>RN>d|=X~9~9O||ˑ4yύԧdҵ9{Gs8gzڋK[1mo?yq|qwwux=8;&5nwfMm=[k=ovy=on"GҜgy:[jG$^y:Vy:?5_3=x?3_Դ{?CG$;]Y?y_,4T+*n*Yv^#Yv~& ɳ]VWCeb񧡲 d#8?&{g=ɞɞX49/b5=ɵzlg6ǁnuxßs@[i;?;P틜(w}(yDy[mο(v _(9y<ρՉrۿ |)G\YQZ2PQr3K%79%_}Ӈ~gtn(GJ+z֟7YֻYI/Igm`ɞd~}g>ų_Oy_oPLߧxS<)))OMNz?499kxtzSK[NwWZK35eaiezS= wt쏦zSGx=T~cg1ճߘ4;߃LOK[=4:ֺG֗~?Rql&?}ߝwyiz;N}eYʲ?|߾r}ş%hn~Sv#}w}zзZ}E违󡾢vW{yP_o}G$+n}5}ž-C]Y}ӏ6ZiK{o}E7Z{nۑ(}E-֟v>WyEM^o/ȕEm+e};yvN}x3%?b/~"W4>n~ZU_ξ}~DyD8~b,[/j?o;+X7~DwOΞ':g~uoDUW}c?N?=lϫD8O{g=hqO{D'_?Zg&c>|h{W?16^s}e=j#oR?OcoSˍo?i~9_ml^?/Ol:M~}O쁽O쁽Osv'?_sDD&8{OqON0>Zg{bތҕ(~اM^L_YE?zO}G>X~F?3~$ʋ\}qn|}_}kVvnf-'|O;_U?n>}whq_/nE-{`}}r[[~No|>/ac]{ͯk>ߖO_{`KSm>}|fe̲R(ϵ`0ŭ>X~/Ib?m=oHwOl싃c 5-_M} }>7zguWS'9i4U{=#M&HSlJ=&HSJ~l_ >Gs^4{=͞fO~P9"Ui|ɭoUr~o/Vf*Y,>U&Kyyۏܛ|ٓoyo6{K=%3=%3s=q_'gzpOqD~=?:H oδ'~{>3 ^V%ϳxY+Q4_滲īr_tįl :+7?h<1nX_L<,?o񐪔?-S%<,?<,?k=|xbIWlv_"KdZ|Tv^^"#Kdvg;,g7,LY&,U'ʖY]Y Id۟IdoeO|ϲre?|2sxG,߳L'N$bes+K?$>be_Ym<$beZ&oe-|2-HmT[7DmT&n2E&凖>[~hwNO_.}sŧtoӕ([~h~Zg勖[>i +[h勖GeO=xd哖[>iE-M\MXi/5\{Nr<#?-rOW'ʖZ.mZ.O~~\OE-\IE,|#W|r\YyDl^.O5;]Y탳b_,\\>~[>j埖>[~jz֟DS5roO-*}rw~[jyoK_-`^Q!ar[K6E-^.nr/3+\Y/`wq){+D-^ΞV[|BN W9{U+e7^Z.VHW+D-Z }ߧÕžXj_P{ە>Xj_} Z!W+Fӧ 7g}| Wg{aZ!Y+}U&ʖZ![+^Y>kg{`bx=kߑ([kOV}d~_l+[Bb/,ߵBV=|׊D[+>XkV[>kV=| Vt/b,ߵB֛vV~[B_+D-2"eJWZ}+UU)lV>[|Ra+E8RoӧJODS*E-~^)nb/,_Re+UyOe+uwrDlb-RCm~[?+E߃~J;_a i+X>m˧nV/pw؇yn?U9RV=|Jw˷`)evP/~W+r}_ROV}U}DyNyX}JJ> W ˟_9|E>GoV̾99MɣC?=d-έCړcǖ/"?ϐDy/I{yGtbgJ*ugt5vyi缴#}ab&eabۓ[0&:e[?=x0:9L'6toOx0&~z8L컭~0Kq0 l0߶n}&Ğ[*([<*%S[7Ğ[JӫҜǴ{}}q N{]= W} Cd+P(Ov|MP<n',)O7s][~T[T;$O-*OGʓ<ϖ'cjy?'cgyO<7?L-,Oje?SsB,y~OD{y]"yb/b<.O柝U'v'k}yy`v^'뽝'y!N?d&}Z@S|q_js<>=-¾W8@}p{k<d{~ĞYc;w{hS{{i?pS_ג'7EGl }oohK̓6_{y>w<_~_ѧ'm=g>9{;@e'k77.ޗ eq>z&~}ӶgR_?=siTxJ[TÝ/sşKesqTYeGxt_.ѥ^YW@׻Rc,zyyyyyy~7m}>-޼M>d߷L;z^艧-Ly!CI/\艷-v$r޲}ʾoݽYI=񙅞"_"Q׆0eMtc?7EyQă }EVk}[~`z="?.<">Ţ.Oǟa=dGO޹r}\tr6#8.[pi1K{5\]. d/ȿ.헆~K{Rο.)/ 헆\ φ߆WK/^ x=On6\k{Un=3Z)[{?s>/X~uY샺egn=$'g$)g$,_$e}둨 =_E|ﹲ|Y>{ć,=_{|Ϟ/oe;ɗe=2,=_E_,=_fX>{g75ˮ!ZYe~?/e[>{wgϗm2-=Vq$_滝7|||Y>{~ȗxK<%e>[>{e=|Y/9{9HfOen@-=Sx7X~{-=_,=_'wy,=Kxar`zeO/E-=_S.N }`7 }`7 R X{Aֿw/`^]*g/|.-}|j+|/vY nb/,߽@생GyhD 4_˭^賝?[{w/|7w/}9^Z{[{A<aߖ^ l^ lb,߽@ D͟*}|?w/}|D td_ AW{a+L-@wg_ D-߽@ D0([{^nϖ^(nv_(m^+eStr<1/ E-7Pn>X8BnY(hgO ՟0PӅb̟.N͟.bt ~?](B_ E-TZ~kW+PH}|Bgˇ/쐲[_ .{abo,P|B`b?,PvJ8}+|B_ˇ/|B'_( +J-P}|B_( XQ|HlEb,HpH^X>|s;.{`E[>|a틾Z>|Z>|UND-PzWˇ/IiWEb_,h~H>[>|>[V[ߊD-6Q|"qH4;EV~>[~|=DD-?HD-?HD-?H:e+}")"ǖ_$mEϖ_AND-?Hˏ/.曞G|{`EW|nV$X~|}x Qb,?H-&_k=<9{s|y^Gsqs9{Ϳgzw%S2?ݯW%e8}-ŭ}'o-Nzև>}/H֯V}d֛>uWHw/Tbo O.|bD~@ז6P {khZus^vxk;}Np}/XοWnWKv(E_+E;{_&EcoD}_Cľ!bF;!O:{;?="c" b?OtO<ϭC}{Y| {A_{Ο_?9~s%Kg7{Ο{{{{{}q/=)egݯfS+~_6M{er_/{SsEt׼{//{ŗ=/fKOciyO:/=Oo}d{"_smР䉑GF"]d$>=#"ؠڛe?x/ j$ZO(/wt}y_Կ>?n{S]}+nK[ 6dfc;̥K3f.\4sC4КW}tH^j}n. Wi5hpiNxi aQĀ6]_K3f.\4si̥K3f.\4sWs5~=4sW[\z,lҭ̥K3f.2YEvYM~5;_t_>Mjx{/̳jC{禳}&g.\00И\ =̬̥_ZM!Hd{K߆KoKf㓩S˃-kP3 ZV~SAM ׾36]ۛoKM)hnҨD=H4|3"H }6‘z߃WޗD&vV[U$>뻽oMvuM30\;.# a  J95Dj.HRzyGGxEj㊺]Y5YGc5Y]V}ZmؼٔЏ LŦb3`5fHwswPH76,3HVI$fP1s.Vi$mG7h#ˢi`SEfOM㡐|!z69@F6ql3"~cq 5wPcƥ=J(uäͺ'vc)KV5gʒexwxوؓP@QX=vaH!C Kca蒚 .'>-dOne16^:2Kme[/Ϲ},c*]T3fllABb5`4 ?s9fjLPZ,᥌~puH0s{Dtxk)aO\\U:mmaDy45&c s'f{0|OpwѤ]a4-VKCQVXMV40XfRjhaq`$ 4>$?C .uXtD0'* aAT\lLslñjڵZBX3\ *i-P@S=[~r./xU/5kZZLE㻐Ѕ9GeF!֨3B#t ~iU3v79x#1mĽ`.!w~`֘e;[(k^Eh$c{hScV%I]S:"Õ,M]K11feLH 1CtlsE;&sXKJXɲE܀vGāݮ1ee]]u5{a$ѠaVI΂ͯN+v-nL+Ik$^_66jQpgU$fl13c$^ |:ԨYC<Ĉ"SY PY c1b?C&,ܲv5tO%Vhe LeMtLmm.Dd}c#H]/ioqV*P2^jg=xO<6{~Ká~0 vQx"=]\ۃ,{f3>2堉ѻBIa{qPtR\d簾5==9SB b:֟Y!_/^N{䅍F>aw8o5D C$ŵSkk>wۼ[hGphFHR`dtv3 8ˆ.+`c5׵`wU"5N ;{0{ǁH?2w8 kX?B;8>U܀p B9 _dqP磌w|:xw5cYvK 4fm "(Y,CF'fsZR|CZcA؉ErYΝ;6019c#&:F,˦n8VӬ y:5wIMvxvYpINR@ ěm w|yetV͐%M[bFj&=Y=}MX7Yj~1fYQlav8y9{FG&)> f+ /H\ _}39 hNfSjj#YD,(*؜`A"XGC%vrXN*Q6v5S G&tژ{.D2kDEFppO0zFO")hҔR@</ua/Aw7L9tc,1rN끟&0F[U1Ibϣ[yKtjNH`kH`rx9hbNɽ?2OX@F&v0kIsc5g oO؞?ĉ˷mŸ-m \["a"zW>'2NGuVإw[7=4~݊M/n:f޺ɱΆNjvCmvmmqرlvj#1'%[IstH;cH#L 2Dc} 1g^K[Fy} w9h TIX3VoA,Y!WNM qjߢj~VʗzW䃷aw &?P 0}_dIrpYS뜕8ˁLZw~_p3N?2#"gLގѸa=)L?iM|̲۶HM[%n|fd$7-]^ WcKM5IRck-z-ƭo2SIĽ$3uY03$;8HD馈=$HQ "F£773lc;u#L:A5>4k'W*@i_drYhu5%.=^z7- ~K.fWEfsՌͻ.M<.8h$<늠 ߧ&y?&_v)SK >~EM#Kdj&i{89˃:{Rel /$v7q!5 E9j EpȘ/x-R ȞF7piyYH6~  ӌ=؟h.X`ϺKfnla !]غ O<=ȠHn:[~VQ- џ^z ݜ[6J&8* u</Rj7uxMEi|Ț 2ǤÓڮۡq2(/v}Lv|3ֈaMc8愄6YVæ\R/  D!@F6zJhԽ-NGn k9>IYsmܔs}/Ҭ<.M~W:C>eeiL&%"@=՘ըCXD`ֲ?x#Ȧ/ uBK=a; bj̶NS0$$MSӧ똉M^گ/7_fq<KJ̎H Gm&Pkd,fL k@~Yw%'{MZsĈbxb5'R+^59hI "G9He^JOF"zUjzU[G?/e,$?ȡF}4n ^h/F$~3 Ok[sB;߱ 屚d{=CF?{QehxmILFn6lI<+8eUGbm µ5+f{fi5ta5Sҷ?yۡϺ+҄%Z#ݽ9/uJƳ.R>5_g]\˼~ 9$t\f]qkvZ0Վ[~5ߑx& '֟S[;1BףXXqqae)vk-f5k3&;x9m 6vyY,AMlI|fՃD{߼F>Gh^4T5)M +V,T&iB`=F&wng?i$9[JqW<_qYWCSkaMs$e%\[l|oθ}>xf< 3LȲ/d4>tQ'am$$r$LuGV$vω172V(x;%ķĵ;D~뤽)!Hx\$Cj 7Y<8Y>M|fa&q?LɯMovIE=':#[hCH*7a"O ;Nza ^/Oj>7ҝ=v7z h @j+|RtJM dpXYykc Gh"qι ?:]>d{(щKۋ&o/kZP.e; U"`-!#$]T⻦IYmktґȗiq4jb)kb]/6-n:Hr΂ڰT0[w__zGb5AGY?=zj-I?ZdqiA2Q$ P$Vpوzi.dʺ_k5{h B.w3}XMw"d PLA')gӄ̛ ݍXXЯʶۼ5㦀Kxv<]x(9oS~>[ ۥ?F`_q\XH$?VVcSKBz3-'4 4Bs$BgY$&j,{<#V3)|ZӼΰpDYD9KmRb "tp6 0)|b ߺ0?:rcTN 33m}m:xU%]zWpi{ee~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~_e~߷e2_/VTGDſL$Oȿ;#oϩ?d{ϟOvzϿCc=6J}#vs9G)|/A.Ͽy+oiͿK? ffӎ'+ؿEά5οkE;YOeѿY߾ w(ϋ(ϋ(ω^y#G?p$v{o;>ÿ? ׿S>M=ʴ=wS@}).GSJy eÔS(Oy(exO9(wROtyS?EOS?EOS?EOS?EOS?EO?AO9>AO9>Ox'f~~<111~|1q\@_n 7Зy} `ݠ_nsu 7 8oypހ7 8?#8?#8?#8?#8?#>##8?B>b>|GpGpGpGpy\A_/?C?DiCCCC0|.!y}p<8F?#ǟyޟyΟig.8h .8..Ʊ ._|]х]KW(Ÿϼ|9g\G}}yG}>}}}y>D ?#<<珴G#vH==?pv8{3?~|={qvEwwi]]}yEw]}9߅(Q9E<(z|̻q~;A}p >A}p>}p>0???~ÿ?~ÿ?~ÿ?~ÿ>}>}>}>ȿ"^ߋ{/Eȿ"^ߋ{/Eȿ"^ߋ{/㷗k㷇w㷇={={={p p p Ǜ&rߤo7h vߠ?ߠ?ߠ?yoo777 {~{~{~{@בux9^Gבuxq|y^Gבuyy^Gבuyy^g_g___d<_w37xk7~Mw7x7x7 nwÿ7 nwÿ7 nw ].w ].w ].w ].w¿'; Nw½p{'; Nw½p{'; N8w¹Νps';8wps;w;xww;y;wo;vÿo;vÿo;vÿo;vÿ mo6 mo6 mo6 mo6o+[ V¿o+[ V¿o+[ V¿o+[ V¿-o [-o [-o [-o [ 'w 'w 'w 'w 'w 'w 'w 'w¿o3 f7ÿo3 f7ÿo3 f7ÿo3 f7ÿ Mo&7 Mo&7 Mo&7 Mo&7o#F7¿o#F7¿o#F7¿o#F7¿ o7 o7 o7 po{ýp{=^zýp{=^zýp{==_zÿ_:u_:u_:u_:u-k_ Z¿-k_ Z¿-k_ Z¿-k_ Z¿ k_5 k_5 k_5 k_55_ jWÿ5_ jWÿ5_ jWÿ5_ jWÿ_*W U_*W U_*W U_*W U5_5_58_5~ ^Cxk<5}sWܕ ]eȽqYF?-c\qYF-c\qYF.{^2 ep/{^2 ep/o)\KZ Rµp-k)\KZ Rµp-k)\KZ Rµp-k)\KZx.a<0K]-a\%/ K_%/ K\8%p.s K\/@_ /x/__2/s2/sby1,ӏbm1/o䢟upa:ஃ:ஃ:ஃ:ஃ:ஃ:ஃ:_ -_ -_ g-<]|SΟΙΙɾdI?'q$q$q$q$q$q$q$q$q$q$ēK.I|I|I|I|I$q&铤Owwwwww$DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDNp``~;o\w_ߺϺss~Ϲg;k׹:O_ӇW>c{mzNo\}Wzzw}^^e^}{o/^oxǻx~oxxw=Ӻ=Ӻ=uitޞg8ewg8ߏ8Ź8g8q1;οq|q>c3??ֹc;ֹc;:::w'sWs8ws8ws8ws8ws8ws8ws8w{qc{ Wu gobtvhvhvhnp=x{0|ww7|ww7|(QG2e(>#ct_+}E;to3=F?gw;pGqO8E#8#|5| _íc{ o{ sa1yc{ s0^K{ s0 Cs?>ܡܡ n(CjPC~BO{ۍ_7nfn滹n>tu]}vjjjjC q!뇸BOl`'غ``yu o0_0_0___}3ȾA Ou~ _ ~>G:_{ t@輁;K ܁y8Ww_vnvnv^gܝٺy:[3Ggٿulvn'=vrow8:Yu/8::Gw~GtnGvnE`ffiswnvnvn{붷n{붷n{wC{޺޺κκw휷uYuZnmc[޶ۚok]G6ƹic6mc6mc6mc6 pso _`[}?ߧ~S}jO>ߧ>ϿϿϿ/߿}9?qO~bO9??qOO^tt??OuiaXpp7www=ݹwݺ߬7s߬7oy[֭[Zۯmך[;Ok[9[ڽv{i3ZqkSz=v[oߊ+V[oߊ+V[oߊ+V[oߊ+V-[oߒ%K-[oߒ%K-[oߒ%K-[oߒ%K-[o߂ -[o߂ -[o߂ -[o߂ 7oߜ9s7oߜ9s7oߜ9s7oߜ9s7oߌ3f7oߌ3f7oߌ3f7oߌ3fM7oߔ)SM7oߔ)SM7oߔ)SM7oߔ)SM7o߄ &M7o߄ &M7o߄ w&Mp7n݄ w܍s7nݘ1wc܍s7nݘ1wc܍s7n{c7oߘ1c7o߈#F7o߈#F7o߈#F7o߈#F7oߐ!C 7oߐ!C 7oߐ!C 7oߐ!C 7o߀ 7o߀ 7o߀ 7o߀ _>}_>}_>}_>}_=z_=z_=z_=z_.]u_.]u_.]u_.]u_:u_:u_:u_:uk_6mk_6mk_6mڜyu:_W_____oooooooo////////OOOOOOOOwwwwwwww77777777?6lc#>~G}w~G}l﨏Qy?r#}dݯ///////////////>`/>u`/XU_w]w]w]վU}U}U﹪﹪﹪U=W=Wuު[y:oUUﺪﺪ*OUuUuUuU***UpW] w*W_ *UxV[ o*UxV[2oeʼy+V[2oeʼy+V欬se+sW]2weܕ+sW]2weJܕ+qW]w%Jܕ+qW]Ε+W_%J+W_%J+W_"E+W_"E+W_"E+W_"E+W_ +W_ +W_ +W_ /_<y/_<y/_<y/_<y/_9r/_9r/_9r/_9r/_,Ye/_,Ye/_,Ye/_,Ye/_ 2e/_ 2e/_ 2e/_ 2e?'33?~ef/>d={]ox޿K????={={={={;w;w;w;w-[o-[o-[o-[o 7o 7o 7o 9?s9?sϝs9>}fϬ}fϬu?g1111o6o6o6o=y~V,}>}>}>}={={={={.]w.]w.]w.]w;w;w;w;w6mo6mo6mo6mo-[o-[o-[o-[o&M7o&M7o&M7o&M7o 7o 7o 7o 7o:u_:u_:u_:u_5k_5k_5k_5k_*UW_*UW_*UW_*UW_ +W_ +W_ +W_ +W_2e/_2e/_2e/_2e/_%K/_%K/_%K/_%K/_"E/_"E/_"E/_"E/_ /_ /_ /_ /_}ǿ>}ǿ>}ǿ>}ǿ/^{˿/^{˿/^{˿/^{˿={ÿ={ÿ={ÿ={ÿ7nwͿ7nwͿ7nwͿ7nwͿ.]wſ.]wſ.]wſ.]wſ'N;wɿ'N;wɿ'N;wɿ'N;wɿ;w;w;w;w;voο;voο;voο;voο6moƿ6moƿ6moƿ6moƿ+V[oʿ+V[oʿ+V[oʿ+V[oʿ -[o¿ -[o¿ -[o¿ -[o¿3f7o̿3f7o̿3f7o̿3f7o̿&M7oĿ&M7oĿ&M7oĿ&M7oĿ#F7oȿ#F7oȿ#F7oȿ#F7oȿ 7o 7o 7o 7o=z_Ͽ=z_Ͽ=z_Ͽ=z_Ͽ:u_ǿ:u_ǿ:u_ǿ:u_ǿ-Zk_˿-Zk_˿-Zk_˿-Zk_˿ 5k_ÿ 5k_ÿ 5k_ÿ 5k_ÿ5jW_Ϳ5jW_Ϳ5jW_Ϳ5jW_Ϳ*UW_ſ*UW_ſ*UW_ſ*UW_ſ%J+W_ɿ%J+W_ɿ%J+W_ɿ%J+W_ɿ +W_ +W_ +W_ +W_9r/_ο9r/_ο9r/_ο9r/_ο2e/_ƿ2e/_ƿ2e/_ƿ2e/_ƿ)RK/_ʿ)RK/_ʿ)RK/_ʿ)RK/_ʿ %K/_¿ %K/_¿ %K/_¿ %K/_¿1b/_̿1b/_̿1b/_̿1b/_̿"E/_Ŀ"E/_Ŀ"E/_Ŀ"E/_Ŀ!B /_ȿ!B /_ȿ!B /_ȿ!B /_ȿ /_ /_ /_ /_?>|?>|?>|?>|?}߇>}߇>}߇>}ߛ7o{ߛ7o{ߛ7o{ߛ7o{ߋ/^{ߋ/^{ߋ/^{ߋ/^{ߓ'O={ߓ'O={ߓ'O={ߓ'O={߃={߃={߃={߃={ߝ;wwߝ;wwߝ;wwߝ;wwߍ7nwߍ7nwߍ7nwߍ7nwߕ+W]wߕ+W]wߕ+W]wߕ+W]w߅ .]w߅ .]w߅ .]w߅ .]wߙ3g;wߙ3g;wߙ3g;wߙ3g;w߉'N;w߉'N;w߉'N;w߉'N;wߑ#G;wߑ#G;wߑ#G;wߑ#G;w߁;w߁;w߁;w߁;wߞ={oߞ={oߞ={oߞ={oߎ;voߎ;voߎ;voߎ;voߖ-[moߖ-[moߖ-[moߖ-[mo߆ 6mo߆ 6mo߆ 6mo߆ 6mo)),3ڶm۶m۶m۶m۶m39r/_ο9r/_ο9r/_οYe/_ֿYe/_ֿYe/_ֿYe/_ֿ2e/_ƿ2e/_ƿ2e/_ƿ2e/_ƿiK/_ڿiK/_ڿiK/_ڿiK/_ڿ)RK/_ʿ)RK/_ʿ)RK/_ʿ)RK/_ʿI%K/_ҿI%K/_ҿI%K/_ҿI%K/_ҿ %K/_¿ %K/_¿ %K/_¿ %K/_¿q/_ܿq/_ܿq/_ܿq/_ܿ1b/_̿1b/_̿1b/_̿1b/_̿QE/_ԿQE/_ԿQE/_ԿQE/_Կ"E/_Ŀ"E/_Ŀ"E/_Ŀ"E/_Ŀa /_ؿa /_ؿa /_ؿa /_ؿ!B /_ȿ!B /_ȿ!B /_ȿ!B /_ȿA /_пA /_пA /_пA /_п /_ /_ /_ /_~?~?~?~?>|?>|?>|?>|?^y?^y?^y?^y?}>}>}>}^{^{^{^{={={={={nwnwnwnw.]w.]w.]w.]wN;wN;wN;wN;w;w;w;w;wvovovovo6mo6mo6mo6moV[oV[oV[oV[o-[o-[o-[o-[of7of7of7of7o&M7o&M7o&M7o&M7oF7oF7oF7oF7o 7o 7o 7o 7oz_z_z_z_:u_:u_:u_:u_Zk_Zk_Zk_Zk_5k_5k_5k_5k_jW_jW_jW_jW_*UW_*UW_*UW_*UW_J+W_J+W_J+W_J+W_ +W_ +W_ +W_ +W_r/_r/_r/_r/_2e/_2e/_2e/_2e/_RK/_RK/_RK/_RK/_%K/_%K/_%K/_%K/_b/_b/_b/_b/_"E/_"E/_"E/_"E/_B /_B /_B /_B /_ /_ /_ /_ /_|?|?|?|?}ǿ>}ǿ>}ǿ>}ǿo{ۿo{ۿo{ۿo{ۿ/^{˿/^{˿/^{˿/^{˿O={ӿO={ӿO={ӿO={ӿ={ÿ={ÿ={ÿ={ÿwwݿwwݿwwݿwwݿ7nwͿ7nwͿ7nwͿ7nwͿW]wտW]wտW]wտW]wտ.]wſ.]wſ.]wſ.]wſg;wٿg;wٿg;wٿg;wٿ'N;wɿ'N;wɿ'N;wɿ'N;wɿG;wѿG;wѿG;wѿG;wѿ;w;w;w;w{o޿{o޿{o޿{o޿;voο;voο;voο;voο[moֿ[moֿ[moֿ[moֿ6moƿ6moƿ6moƿ6moƿk[oڿk[oڿk[oڿk[oڿ+V[oʿ+V[oʿ+V[oʿ+V[oʿK-[oҿK-[oҿK-[oҿK-[oҿ -[o¿ -[o¿ -[o¿ -[o¿s7oܿs7oܿs7oܿs7oܿ3f7o̿3f7o̿3f7o̿3f7o̿SM7oԿSM7oԿSM7oԿSM7oԿ&M7oĿ&M7oĿ&M7oĿ&M7oĿc7oؿc7oؿc7oؿc7oؿ#F7oȿ#F7oȿ#F7oȿ#F7oȿC 7oпC 7oпC 7oпC 7oп 7o 7o 7o 7o}_߿}_߿}_߿}_߿=z_Ͽ=z_Ͽ=z_Ͽ=z_Ͽ]u_׿]u_׿]u_׿]u_׿:u_ǿ:u_ǿ:u_ǿ:u_ǿmk_ۿmk_ۿmk_ۿmk_ۿ-Zk_˿-Zk_˿-Zk_˿-Zk_˿M5k_ӿM5k_ӿM5k_ӿM5k_ӿ 5k_ÿ 5k_ÿ 5k_ÿ 5k_ÿuW_ݿuW_ݿuW_ݿuW_ݿ5jW_Ϳ5jW_Ϳ5jW_Ϳ5jW_ͿUUW_տUUW_տUUW_տUUW_տ*UW_ſ*UW_ſ*UW_ſ*UW_ſe+W_ٿe+W_ٿe+W_ٿe+W_ٿ%J+W_ɿ%J+W_ɿ%J+W_ɿ%J+W_ɿE+W_ѿE+W_ѿE+W_ѿE+W_ѿ +W_ +W_ +W_ +W_y/_޿y/_޿y/_޿y/_޿9r/?1sضmJ$;ə>iضi{:m۶m:׼~>oC!?C!?C!?C!?ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccA ?A ?A ?A ?################################????################################7o߄ &M7o߄ &M7o߄ &M7o߄ &M7oߘ1c7oߘ1c7oߘ1c7oߘ1c7o߈#F7o߈#F7o߈#F7o߈#F7oߐ!C 7oߐ!C 7oߐ!C 7oߐ!C 7o߀ 7o߀ 7o߀ 7o߀ _>}_>}_>}_>}_=z_=z_=z_=z_.]u_.]u_.]u_.]u_:u_:u_:u_:uk_6mk_6mk_6mk_6mk_-Zk_-Zk_-Zk_-Zk_&M5k_&M5k_&M5k_&M5k_ 5k_ 5k_ 5k_ 5W_:uW_:uW_:uW_:uW_5jW_5jW_5jW_5jW_*UUW_*UUW_*UUW_*UUW_ *UW_ *UW_ *UW_ *U+W_2e+W_2e+W_2e+W_2e+W_%J+W_%J+W_%J+W_%J+W_"E+W_"E+W_"E+W_"E+W_ +W_ +W_ +W_ /_<y/_<y/_<y/_<y/_9r/_9r/_9r/_9r/_,Ye/_,Ye/_,Ye/_,Ye/_ 2e/_ 2e/_ 2e/_ 2eK/_4iK/_4iK/_4iK/_4iK/_)RK/_)RK/_)RK/_)RK/_$I%K/_$I%K/_$I%K/_$I%K/_ %K/_ %K/_ %K/_ %/_8q/_8q/_8q/_8q/_1b/_1b/_1b/_1b/_(QE/_(QE/_(QE/_(QE/_"E/_"E/_"E/_"E /_0a /_0a /_0a /_0a /_!B /_!B /_!B /_!B /_ A /_ A /_ A /_ A /_ /_ /_ /_ϟ??~ϟ??~ϟ??~ϟ??~ǟ?>|ǟ?>|ǟ?>|ǟ?>|˟?/^y˟?/^y˟?/^y˟?/^yß?7~OoG=~w߿_o;wk]~;i+W_+W_+W_+W_%K/_%K/_%K/_%K/_ /_ /_ /_ /_9s?9s?9s?9s?3g?3g?3g?3g?)SO?)SO?)SO?)SO? 'O? 'O? 'O? 'O?1c?1c?1c?1c?#G?#G?#G?#G?!C?!C?!C?!C?????>}>}>}>}={={={={.]w.]w.]w.]w;w;w;w;w6mo6mo6mo6mo-[o-[o-[o-[o&M7o&M7o&M7o&M7o 7o 7o 7o 7o:u_:u_:u_:u_5k_5k_5k_5k_*UW_*UW_*UW_*UW_ +W_ +W_ +W_ +W_2e/_2e/_2e/_2e/_%K/_%K/_%K/_%K/_"E/_"E/_"E/_"E/_ /_ /_ /_ /_?}ǿ>}ǿ>}ǿ>}˿/^{˿/^{˿/^{˿/^{ÿ={ÿ={ÿ={ÿ={Ϳ7nwͿ7nwͿ7nwͿ7nwſ.]wſ.]wſ.]wſ.]wɿ'N;wɿ'N;wɿ'N;wɿ'N;w;w;w;w;wο;voο;voο;voο;voƿ6moƿ6moƿ6moƿ6moʿ+V[oʿ+V[oʿ+V[oʿ+V[o¿ -[o¿ -[o¿ -[o¿ -[o̿3f7o̿3f7o̿3f7o̿3f7oĿ&M7oĿ&M7oĿ&M7oĿ&M7oȿ#F7oȿ#F7oȿ#F7oȿ#F7o 7o 7o 7o 7o_Ͽ=z_Ͽ=z_Ͽ=z_Ͽ=z_ǿ:u_ǿ:u_ǿ:u_ǿ:u_˿-Zk_˿-Zk_˿-Zk_˿-Zk_ÿ 5k_ÿ 5k_ÿ 5k_ÿ 5k_Ϳ5jW_Ϳ5jW_Ϳ5jW_Ϳ5jW_ſ*UW_ſ*UW_ſ*UW_ſ*UW_ɿ%J+W_ɿ%J+W_ɿ%J+W_ɿ%J+W_ +W_ +W_ +W_ +W_ο9r/_ο9r/_ο9r/_ο9r/_ƿ2e/_ƿ2e/_ƿ2e/_ƿ2e/_ʿ)RK/_ʿ)RK/_ʿ)RK/_ʿ)RK/_¿ %K/_¿ %K/_¿ %K/_¿ %K/_̿1b/_̿1b/_̿1b/_̿1b/_Ŀ"E/_Ŀ"E/_Ŀ"E/_Ŀ"E/_ȿ!B /_ȿ!B /_ȿ!B /_ȿ!B /_ /_ /_ /_ /?>|?>|?>|?>|?vӇc7}8M>vӇc7}8M>vnzs7Gonzs7Gonzs7GonzvM/^vӋe78zM/^vӋe78zM/^vӋe78zMnzr='GOnzr='GOnzr='GOnzp=Gnzp=Gnzp=Gnst;Gwnst;Gwnst;GwnvM7nvӍtf78M7nvӍtf78M7nvӍtf78Mnrt]+GWnrt]+GWnrt]+GWa7]8M.vӅtb7]8M.vӅtb7]8M.vӅtb7]8:Mgvәtl79:Mgvәtl79:Mgvәtl79:M'NvӉtd78:M'NvӉtd78:M'NvӉtd78:Mn:rt#GGn:rt#GGn:rt#GGa78:MvӁt`78:MvӁt`78:MvӁt`7^;=G{ins=G{ins=G{ins=G;inqvG;inqvG;inqvG;inrm-G[inrm-G[inrm-G[ia7m8M6vӆݴhc7m8M6vӆݴhc7m8M6vӆݴhc7m^;5GkinZs5GkinZs5GkinZskݴhe78ZM+Vvӊݴhe78ZM+Vvӊݴhe78ZM+Vvӊݴhi7-9ZMKvӒݴhi7-9ZMKvӒݴhi7-9ZMKvӒݴhi7-8ZM vӂݴha7-8ZM vӂݴha7-8ZM vӂݴha7-^;9Gsins49Gsins49Gsins4ka/?;w>~}v.~wwnw]n7;f7|ovso7w{W{_Ww՝_}Ww];/w]{q׿_/w]q׿_/]ݿ/]ǟ}g;]}?Ͼgwl_?;~r?O'w~|O';w~?ߟO'w{t?}G}^}?}ߏ{^}?׏^fl^fm^fn^fn^f7s|3k6{p?p~]`o?v{w߻{w]~o7߻v^cqoqgw;w]|snN]}랾uGߺo7w]|q______[o[___________________;x{=.uﺋwŻ]wx].u︋w;wx].q︋w;wx].vomwx].vo[-wx].ro[-wx].MMMx}Nwt/oo7}ǛMqGo7 ;zwpGo7 w}}{pgo7 w~aS=6MeS}6MiS)GSw۔m7hꞛr4uM9Mywƛ›^xxxxoxx/xxOxxxxwxx7xxWxxxxgxxNvv[Wϼy7 z&:* 2"<,^'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨'꟨ '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠 '蟠!C?H!C?H!C?H!C?H!C?H!C?H!C?H!C?Hqqqqqqqqqqqqqqqq1111111111111111A?PA?PA?PA?PA?PA?PA?PA?PGGGGGGGGGGGGGGGGQGQGQGQGQGQGQGQGQGQGQGQGQGQGQGQGGGGGGGGGGGGGGGGG?@?@?@?@?@?@?@?@GGGGGGGGGGGGGGGGaaaaaJٸ6iarYF33333sN1㈥4шGnw=sg\:}}(忋.⿋.⿋.⿋.⿋.⿋.⿋.⿋.⿋.⿋.⿋.⿋$I'O?$I'O?$I'O?$I'O?$I'O?$I'O?$I'O?$I'O⟔?/ #{ׯyy׏y=^7x=$xw;^7z]:ua^{vxmkRE^fyMy>Iz}^z^Jz^z( ?_:u_:u;w;w;w;w;w;w;w;w6mo6mo6mo6mo6mo6mo6mo6mo-[o-[o-[o-[o-[o-[o-[o-[o&M7o&M7o&M7o&M7o&M7o&M7o&M7o&M7o 7o 7o 7o 7o 7o 7o 7o 7o????????????????_:u_:u_:u_:u_:u_:u_:u_:u_5k_5k_5k_5k_5k_5k_5k_5k_*UW_*UW_*UW_*UW_*UW_*UW_*UW_*UW_ +W_ +W_ +W_ +W_ +W_ +W_ +W_ +W_2e/_2e/_2e/_2e/_2e/_2e/_2e/_2e/_%K/_%K/_%K/_%K/_%K/_%K/_%K/_%K/_"E/_"E/_"E/_"E/_"E/_"E/_"E/_"E/_ /_ /_ /_ /_ /_ /_ /_ /?}ǿ>}ǿ>}ǿ>}ǿ>}ǿ>}ǿ>}ǿ>}˿/^{˿/^{˿/^{˿/^{˿/^{˿/^{˿/^{˿/^{////////////////ÿ={ÿ={ÿ={ÿ={ÿ={ÿ={ÿ={ÿ={Ϳ7nwͿ7nwͿ7nwͿ7nwͿ7nwͿ7nwͿ7nwͿ7nwſ.]wſ.]wſ.]wſ.]wſ.]wſ.]wſ.]wſ.]wɿ'N;wɿ'N;wɿ'N;wɿ'N;wɿ'N;wɿ'N;wɿ'N;wɿ'N;w;w;w;w;w;w;w;w;woο;voο;voο;voο;voο;voο;voο;voο;voƿ6moƿ6moƿ6moƿ6moƿ6moƿ6moƿ6moƿ6moʿ+V[oʿ+V[oʿ+V[oʿ+V[oʿ+V[oʿ+V[oʿ+V[oʿ+V[o¿ -[o¿ -[o¿ -[o¿ -[o¿ -[o¿ -[o¿ -[o¿ -[o̿3f7o̿3f7o̿3f7o̿3f7o̿3f7o̿3f7o̿3f7o̿3f7oĿ&M7oĿ&M7oĿ&M7oĿ&M7oĿ&M7oĿ&M7oĿ&M7oĿ&M7oȿ#F7oȿ#F7oȿ#F7oȿ#F7oȿ#F7oȿ#F7oȿ#F7oȿ#F7o 7o 7o 7o 7o 7o 7o 7o 7_Ͽ=z_Ͽ=z_Ͽ=z_Ͽ=z_Ͽ=z_Ͽ=z_Ͽ=z_Ͽ=z_ǿ:u_ǿ:u_ǿ:u_ǿ:u_ǿ:u_ǿ:u_ǿ:u_ǿ:u================_˿-Zk_˿-Zk_˿-Zk_˿-Zk_˿-Zk_˿-Zk_˿-Zk_˿-Zk_ÿ 5k_ÿ 5k_ÿ 5k_ÿ 5k_ÿ 5k_ÿ 5k_ÿ 5k_ÿ 5k_Ϳ5jW_Ϳ5jW_Ϳ5jW_Ϳ5jW_Ϳ5jW_Ϳ5jW_Ϳ5jW_Ϳ5jW_ſ*UW_ſ*UW_ſ*UW_ſ*UW_ſ*UW_ſ*UW_ſ*UW_ſ*UW_ɿ%J+W_ɿ%J+W_ɿ%J+W_ɿ%J+W_ɿ%J+W_ɿ%J+W_ɿ%J+W_ɿ%J+W_ +W_ +W_ +W_ +W_ +W_ +W_ +W_ +W/_ο9r/_ο9r/_ο9r/_ο9r/_ο9r/_ο9r/_ο9r/_ο9r/_ƿ2e/_ƿ2e/_ƿ2e/_ƿ2e/_ƿ2e/_ƿ2e/_ƿ2e/_ƿ2e/_ʿ)RK/_ʿ)RK/_ʿ)RK/_ʿ)RK/_ʿ)RK/_ʿ)RK/_ʿ)RK/_ʿ)RK7w7w7w7w7w7w7w7w7w7w7w7w7w7w7w7w/_¿ %K/_¿ %K/_¿ %K/_¿ %K/_¿ %K/_¿ %K/_¿ %K/_¿ %K/_̿1b/_̿1b/_̿1b/_̿1b/_̿1b/_̿1b/_̿1b/_̿1b/_Ŀ"E/_Ŀ"E/_Ŀ"E/_Ŀ"E/_Ŀ"E/_Ŀ"E/_Ŀ"E/_Ŀ"E/_ȿ!B /_ȿ!B /_ȿ!B /_ȿ!B /_ȿ!B /_ȿ!B /_ȿ!B /_ȿ!B /_ /_ /_ /_ /_ /_ /_ /_ ?>|?>|?>|?>|?>|?>|?>|?>|?xC{c3/? 3o3fcw_]|KcS-ʘ_1Żc<%ysl!G17!~sKsO̭1cn9Çcns_ѡ4?S|4晘d̳1s̳1g~Ř#wļ1oc~W;1wozO{9$~աoz_ 1?a!჉}!۟o@7??7i{ѡozKs6h}ӊ91ћnΊcޘc23̧|1kZ/9O17$7/3?-洘3?-;c~|iic3$~b7?7![>bMs_kKw[c.2_sgq,̟;з1o%|[O31֛[y-d1Wosc4uȡo{{13Em%?qq-b319ژa>3Owۏ4GoƟߘ_9#Eo5Go_0GkEcwl9?_FswFpܽs[;׫;jasesο3G|9w2G<fs;;kןw}]wce_e=y%W9פ9co3G9ݧw_g9w9_7Dbccs/x?F9.sԘ9_+W{k{9/晣v.9N_x9w~gw9mC>?D+0Gooo?fo{Js^K_?|)_?p9CZ})^sK`?h:RA̋/0G^/F0G6Gt b s!/F9uCYW$՚Y^?fo_x9?šB~^8?±|;^?lMx> G`?\n?]#E9rsEsGzGG?sQ\Q<~{.h9&?j~6l1cm?9kgic?0Gglq=qLqgoOD9gOX?aMx&D3'S?LIk'n?:WO>n?}:d9OG9kOƧO]?ۧOb?SOEz}SmSOE]OE]OEm?93x2gOFۓg#OFy_g\<fƹh?:y?{9f?9m|"sg=Y۟?Cs9wOD{Gs?޶<ŏG]C> G??o?o]}<9f ΛE_9¯2G_pXclǢ/xX~E_y<sEǚ/`8}4G/jas%F_61?yK>ZPU*E_>U?E_E_lf |(g~l<`5HF_s`5՛9`u;?˃u@Rs>su7DpNy Qoخo؟D߰?\@Mk7?oO?3i?&oysW-GL[ΕGrO}_-זEEߪ4Gr=v_9s-Evmv_m۶ΧE߶>Zt_Gqtomϗ7g}Fy;{7;>=wvO=w'DߵzrOݟlkͼ''{'Pb;6y<[;ۻYO{ϻf;k[k[o+~9s]=7+뙻+\38<{W3;xpg-sC;3':;޸3a9c?I3wDIzGt9O}xGrGZqG.$wDlcGn>GY?o{{#G?Ǯ%nl=geG?v=TE?vx[cץE?&1x[1x[fE?q 5mOۢXnOzkSϩnojn긻5Nnjm5{[ٮ[=ŭϬF?s޼%ug[M:KsHD?wpKsk-pKs1nnM%k›;o9/\}/<9g 7GpZ}s oiͼ9oΧ7E󁛢_zV|SKuSKkM/]wqtS+ʳ_Wn1Հ9_}Ӎ5yckk+>1_[gnX175Ƴ8nc! o|uC7֢jjǹ!Vߺ>!GGN>?6^i}>?RGG#^]GGziwE^]=uS_=u<.u\3\~]ԇQEG9];kkFG(M^YӵQ]jh^YеַkvrM5֐kcl51uM-Dؖkc<&?&?skc=g&?WGjXk]|wu8$WGWGw{u{WG':?JWG'hUOtqU|UD]x*?xU_OVO]UI]dk\{e+= 2?3k˕)TTgO2?w%WF"?=iyOWDyVsE֟+]\+37Ggk =G8>߽>g}竿u^}֟GGZΛGGg<>g8>y>>G G G8>Ϲ>k}>q}w;.~8.y~r\=?.sݻ߯EExqlkc c]FF8֎A?;cDccwLc?!!Dc|uLgDYÏ?!i?X?,v?:ya߫?֘ha͔sYJo>979:|81s&D&ƶ<7>|aщ9]\mXbH=Ŀh4\bX%1"~'aw<:X51.bmy,0}'1=chz8jb[_%wb{?317~7&&y(1'yW//31('柄N? <~Xc01*'n|"O$>mD卿 '#c[b>D|'G:<}Չ$>G?}dnb>1ɓuO$Sb-}r#1F}ٱ?uDb>?SJGO>W|~<>Sw$+z2SYXOg8S[?OCb1|C?zb%>ma%8+.}?z:#1.O&b?b?`&[{擉%>+1?*1?u}81?I/3c??ӗ_hH7Psb&֍7%>?Mlq={J)q^~Ĝ색9#:|O9+;ϖ$zgȏuY=|%859qy&s%؟=8z%5M&X?$1>x7y,|gb{<yۻޥ01ļӉy+ֽgbhw$kso/ 7^41gCx||$/^/&֢Zt?ƾz1 //& c|b5.?ыSNmR<=o_J/}718\^:&12݉s_z919KWעoؖ?91+_xbv? ߍmCb8{K?8&Ε0hﰤ~_eDZ-H~/r\y/^N:'#c}N8WzC'/'/%9_nJ8_Hƾ}X|B\o1q8}kaqG=?>/:qc?pk>μv]o'͹+M^>%qNg|HźFCF?C/D2T$kd9Q /=, 4ӱ롊[ / Wɚھfa aaԞއUP{7Sl_`ck3NX)N+&X`zv^pp+YpEUybk>^8zͻ<W|X`#joBG Yppū" 2QFSNNSFa}G;;B߃`cdJ?Rkd]=?FӑuHq32@nG*o*p9'(ksQf(㜋3ʸ%_ 󎚣5d>j]R*mGT_ђm5Zu0GM?ZqNvOt:Zܞ G+u!ܛ޹η8Ϲl|(K|>F.G?FvƼv󳵉Hιq>fyZQG}pXcyNJWcem}[Xin!?Nsށ'ٺqe9q8'(~..2N#Fg--{qԾ|wn0^Xʽ썗Nsˣ&NjW`VD&򛹕7] ~oz&^rk ǚq|Vn-h6&: N& Rah!x)ڏb#d/Nlb\~8Q<x5%({m58*8Mkr|pWn{;QqZs=} MR%d>I%#sMjvg>I9LLϝOL:w&ru {qd~ LN6Dwr;M_}fwXÆs~Ab6˻}r)glO~ʿ~O5[ޘzJ/SUN58eO5'OUu ~)oO+ply||;Mb?M8w z9w,f2N/̧)oʝ|9w"k[d6]bT;|S9ާwdG= 9OW;OW*w.UWլr' j6xl*pp+]j\ >5l zd5CyP8|d#@mvSj;tFkcw3̮w򿹻 =Np w3/LWL[!;SqNa7d{|[sπ }a7tzt7\:A/lkYgݽ+f)ϽfK=Nn;K1 f-R;1k_zrْǃf<>lmv [Y=vXnxrLG~ښ弞(#9{b;Gĉ\Id8GI9}8+WړA/s3{nݬ}o6mߔKzn{ KrjOaPkñIw7=w~:62Wq8؞[>em|\[v|\wO qn=w%>‰~lm^q[:Ixr{L|6kksWaO[d2\(<>*8wy=.Tq-=*>HP{tž*qݍlM׌=G y^FTSW ],:Ez:E ޻H+/ۼNG{ʞ;ÍKj;/`ii/ ޖZm\:A}o;,ٓ+b3ovceaz-S#{\\z|2A l ;/LO\ NgUzGo"?_#]._YVH`ctY\+q '+$s*0B,ā+UW,:kn2<J{mpʙjV]AxϬRsZe;R.9VD>xKNKE88Ym<N\u߼N̓=v^Z)'F:&(6N97Ni޸Ggzق7ތa1NS0^~U\ݚ}xoe팳A6-7\w .mnNw2cQtAt޻ ¤kؠ8:ݠ{7ݨx[oT^٨<7d[ >h- 6*ރ]ozˢߍrpj{gr=}d#MMomp7Ɏ9cm0Ʃ̾6.筊oV[q6NsmzxwKٻ,zRS[0ّ&"nQ}npYy8OnQ.urZyݪ5U|+i9{l5<@UuWV'ٟg[Ğc W/mʳ; ۔z;׶nt*:M6\M9^6'.6\o>6v mיGg]vřsd~&ü;w}7s|y||Mpjwo;T[v>ٷ=uS'S;^[O;uߩ 䰳/L?{c;;a_;x/~72ntv'w K^t إ3tpK,1N9SKY.(nx݆kͻ_[wXm]V=ٻ=6NV|هw'ܣѻأջi:m{&f=k9kc[/̵O_ڧz6}_ieb_EO~WWN ~˧+oUc_u%MU[p7fK_vjj)i >_< !/W'\trlЃ|Xz]AWcprP9qdxPg־A#=<q=>~!u?29d:uC¤5{9: ~|-k>x=\hkRl{;$Ě]6{9,{n9sV{ |6|L+/9 Vsޑ<<?6vrYßv&u?r=?T|4uC_}1e|anY=b1[l#S?k8 #ZudrT9/:=\|GoU.돍5;zj>F1;1 ~{LutBcgpƱZ+ { '?9;.9>wpd\~+9<~3׉;'>C' 3wO| '0|N(~} 6N%>"8qZϿI.~d!5= Od;-I;?}xR\ݝ}G|CI}C)t}SfñSƟ#)(Էv~|7ݝ2{OY\=-CO}3iťY{5?<7?mNF| 0k##"ӊ|N˧ÁgTgg73¼gs}[>sێ (~@gt^^Ψ 'Q> Ϙڏ>ΘNWg;Y#yV}c)x=N8w̟U.滌]սAuprV:ωo9sk8z߃)~F?LsN1?B,qN5 {N'9ݟ&;mӆU|yՓ]>:~_5_R_#9}w5Kk"K'!k˪kʵuOuY叭aU;?^V^n #yEw| _/o,a]4yda#kؿ*\ܭ2_mmmxUzwUA_WmUíUY[mmoq)W-8i;>ß+^?l}*3?gޟ7/ k#sS5vkto?Yxf;8U;ߗ&>w֜ow\Sv'mLdrλOk0uUwMΙuU7WMou-+ ?daζ_U m?m{`:mq봵NGkh+zM92xmIچh׷5;O Um_:m݁˝5A6?)'h_xmV V=ںdoVksm? mژG\ǭ{٭m"Ggd!G<Ƽ9%#3Gylm:k#poV}?/mfe3ͺO7j:OZo*YC6 ƒ흝Vio>Wi+ϭr*ҝ~ ڊa 6-9U 媾_o=G_ˣX#~?sZӣz%sƫzz*}v v`ëԿa?m&Umܿx̿/6Y<˿,ǚ}{>tCج|!3^=],sfĎ.m.-ׯx[%tWU#5-; DLVh]{9z ֲx#p0lzVjoY]@5@6r jZ{Ӗo 낪;eAa&Ah/^PyMv3jEwyjö.,yq+ <<Vࢰgma[CtV\h;mq+D|&s`rƦ"VzE%{J?bjӨjiTJr`* bQo`4v=dm6f^b:GLG` |`k&0쪃^ʑbqƉSYU`Q`:W>U q3* BV  e ۄίsop5gP+HXN)ۤ _ߑlj{WI{Ƕ^aϏі ,FR+KJwkW"ϔP7oꨍ ҺXv.H[qpV4=6ɴ>4 htѝVtְ!o eL3_W="%'_8l'osŁ f;|qr`'<]\:쁣 ^A`/XPabmAfKAa[P;l=`4-G-[-: `ͷfbOb( ϟK`w/΢[VsN5 \`[U\b)\o+mmuޟ \a,8_|*v~t7.ܮx;pܮ/pޮ3vN_H1OdAR ) YO va=䧂7NPm-~z^{b5qȰ ia(x.,oz/>?7ErM"^04W3`PkckE"X sݩ1x Sxo|hnc;Ӄ; 6+j{,.ʏE`1VTq]88/x5X8fv.]傥]iQw?+1]՜/N*(=hvgS7ؔ}Sl SlE^LX :R1fcUvW|\S|Wn|f^ocqvrmWcMnEq`OU\<%dGΗ%LoJ%LGYC tK( P9d_w/߭zQp,[%85- V(8n6$/ymI )QIt-iXT<J2,͆J) a_ğp)J) /̳c˥ ?K+v .J,i\ҊOK|'LV}; 6ݭQM }ZsOok#{ = p=9a ~[p qVlΆeFYX乓^Dz ^ʪN.jp?諬JI9C跜ipE91챜q)r9\N)s%drɽ k߫UY: ^C勚yyckU7s;}4Npfyݥ+?|r}Olܧ83\S~Dfvy!/"~$/_ݯ$/+ؙìDnsw;r WVL c^ /+cToq=VGݏ~+F*NJ⇼@EyΫ V?ͫ+O订jyoEīuך5WR,-Wu[*`Sewy]9eq, VVl99ie[}W\5,? lkpr]Ul #*FS2W@XRE1|$콊w2b{_W~ or0o9QUj]ְց۪6dTUqx&*?Wv0oUjwlTSw USNwVSwf6^)W;;̫/WS)G=2rs+轺]_췺':|X]q]( UW}8t3/T/GT_kmV]g!3154g^CBAx|Yv8ꢡx џ;Ur7LL[;C۰L;̎vFֆvwFvil$52Ncぽ$gCU @G{4BcCN[: >~YfG㝭}d{ >nx]< t61;=ɼMB&BMOM1N$to0tTyJljC`q%tjO >?[BcOǞPM=;kvBZ:rx 8 Va{o&߄<ٻc d/a_7nL ߌ_h5sY[3 7=̰K&i.}Lsႌ\1m[p1pBrWD-oJ#ZUK jN#W v:m&&2l); `-pMbv mX4\qZ~gr~+Fn-u?u?O.ԻF`IIqK z|rՓuO'XO+9j%f[);tLOwZ)b&[_Jyn5le}#%܆u1 2o=vZwWֺ~qZvIkP#쫵j&67Yi=ݵ{%ᗜ>vFS];HAWI}6>QրWҙW#}J8܉)y)?tǞo:m[೭x# |Ul >imV%ܓ5C*~fTϮN>Ny{4xhgx~ݵo*Vo݉p_0b{ģjOv?m6|Mm@ezL^1= _=d⧴/#Wt V;cL{O%I8Ky^Zw \y;ua}Ky-{`>otQR0G~v4_;gYsGtCYG"h.l^r2ق:1nr Ͽ.FUq!D};$C_ٝ{2p_.ℾEvվ:ۍ'a߼Q #A71#/g|xyO9f"q`?ƫȶbu0꧘-zOK4 :wTm?Aogk{o#f_o>C46ԙf4<\4\j)QM7O^_-Hm跿l$ZsWe6f_>(Z>|K>:Zu<8yy{xK[SSί\9tqeY7^ ΏVQњejчQ'C6[:Ao۝imMb oۻ#Ϸl!{\ufu i{F;}䋣 @َ{:2'hwo;v ;'}_bckrcT76A>L F[ A:Í> N>[!AS6]Ţѧrh[h;wwE&nW<}]簵Gg56߳agߟgw0`{8ga)8,nQ|}+> >U[`E{UˍtC_ DGDem8t.}}S+G>%%о-9{P|(~ ~h6 6-=PP g0g2Gʩ`ɧDӏ Cpd$zHu(|Ghq/}ȏ;Dzs7cE1džk$im8s:j_'3'{Gg2' ~jz~Z:?=sSdvVlniSj󟉷sg3ŽysŽNg:#.Dkt^t \>.5|._]|.^>W" @t {D"/E׃/E7:5°}qKKʕ/ 3}_0ח _UtxJwzW:߉ J9~ 8JW]廣Ge_+:kd៯u(z mk;I)׾= ~| {G"oo^p6|7ë'(>^mɏU U&BJX6X1:m,{N5n|;qQ,Ts;Cb^:D+~nW}|$V{Xvwv؝$vA>(V ]`{,NLQdn|b$kQqo4dUL(+~6be&|^?a,Vj~ǘm|'rIk?Cb?|O򃱪If=?W?ˮc5gc5YϝYgmZʾ V^˚ɷ6Euì]>{E[kEyb,SGY1Ja;Cd#,C?9mu#t1DqBq;P~cbMӡXS8aa 03Tf0TuX72T9Q'3TuX u~:+O}>Kypիc_'k}&fawc_򳱯] ]M#ľ?G $[ݬyط}C6/Hqi;vcý#UoT=֞#ϑvv|7:Hv d2ʸ?9~2R 06<\`X"6;e*6F'{apc6<=ņѪFi >?6 Igc[9xs5FFl,cq;Vzgc?VUl"sU $65 Z=|!oMLX8{W.\l:g15gq_qc3ǩ WSmm1朹W}#ǫ>8㍻xl1<6^1|l xE݋ yc ^q{vQ~;; *.ASGkMm1q8| Ɵf85OywIm̉ρiڣ۹<;ޘv~6o&ڦ[pLיE {n^M:uo^9ć*{*ߌ_5f< 'دޯⷳR2<(^NH*~_D2!.W#!L96S~'^uδw09ScfB>3x]0s=G3D<-Y&v f Gaf)?\4}Y6o#x`wJ5ϒěa͇Xl?:g K5[T5["ޒXnx+;[x;٪ğ?g2͖ǟwTM,:#?zSڞ9]Ļ 9#Q,߶>ܾ^ƾY9oqi?`}Tӎ-&y0ooc_?{:I]0Wv**f ',4LN|'F[`lZhu|bl_sBEz(E_/Eećĝw3Z|2Y$ulw4w-+b݅ξ\-;n]O: bk;w+K1ŏKtv?̗I [390D~6~u.Qw+\*~]/1[pλį0z-x07z]>=x]>=~ oƯW(l?JRզ9om̗*I Ɩ(@}-TKUOK2!ge$ey"^Ct)bmd0x8$l(2rXglm}k z_nD.OLĉ[+H$rT"L+sW9Z\ F/+{ {\ VΓ(WhUx+tF]+uFpe]kDa\)LA/+u/Q|kᕪ=&W KbUݫk}'Mo%*{(߮R>Q1W$Q^kV(VnƧXjNv`njt{ժ %'Oe5D90FY#H8kL_5s߮U*NbkNGk{sjVJj׉=:qu)N{t3׵uYfu:vٝۺ߭zYg{oz։K-ʣzŊ֬g$Q=Wkb鯜ѽy|8!_c=xXoq K6֑\/%: ¡{_J{ܠ1эijJa&z :LQvoh~i׳68hz76po4 6xoYjb0ܨWFćp&i{$>6ؤ-9\0IyGkߤ$-kd=&S^GyGlg0YtɓmV1;l&]u>pm#͊#)ьE$E߄swb⫄sE>+1n1I7یOge;Mwف};y35oS\ ۳ KΉz?}N nv݋Hۚ a}}os=q;Mw#kG kw%;Um-q0̜7v8g ;UN;γNj|NN5hq i>?⮝Y8ax&A;$SjBjOFλ$ĦvE.']ɒndi[>"eV^, o}b׻eGnW&c {B֦Ŝ ̻GgFmw;n&bw{ Xګ&0Ϛ|0^C%b {UK>ʘ{m^%HǙۓNm7ٔ1~$a (H6v78wƢol wޢg}--$[}%TOW6p>m)lp6ߺZLyo6a C%_[7+3~dp_+IvFC]o]G=q{#L8 M¦wB7x;6oڷy)WUMm^oJ}^BNz]m|}mwؿ^At2Gmcߞ}N: frcn'\&c3_sɛA9.ľr=^ ^WJnx0*rL2;Hu^U2WyMkENWuu$Փ_- ݈\FY:o^S7{˞ß ^6ؾ!|f9uSßi?ͽi+nɺμ>R \9.ű~hkmgݴ5NֵSUKِrT/iݚu87^D.ں7Ђ͎g>ʧqo?R؟xôiD{=E|Z;li+Wʺx,nX*UL?Е=MiGc{G&n[1_h+'G=k)m}?|'5h]ԧ+02̑O7(O}ŕspE7f]B[5ԗfiǥB7{.͒a5pmR߰ԷehǼG[>GIWNn rG~(H[ĬKiWsG׹=k}GqW'19XS 15v&!v..G so;{̽o *ͺ0ו3l{)bQ٧+h+LqX7l|0W&51Y7֙Hjpmmy֧獌Wqlj3!۬Shls$Mf/S[o` <.y.p&희Ckc9I۩?9)'o̾RWj{I)6Nt>y](}Nw1Oھ26V='8{ɨzd'όq|ec2W՟rakYўÁW:6Q+_1jX8X-h UPwiR3u4tyb\ƹŸhڪ[󩫬1R[Fr{̕sx>x틹n5_v ?r({~a_VOݦ3i6rj m]:z}Cߦ;cYGlG|9cnRoW^ak=雑v7K{BE R,3W!}Ru3wB>.s|{&NAxrt5a6r Suڷm]]XgN.^'醌Sl[\gOǐCq0݈1~Ӎgm S"dsv߻+-au{K,ݜߖP#PBqi%z/3t+nt{}bsn{$v}edw[M+||{m-]^J*L/Β+4<oT=]lg91=v_oVȭb xb`b2ƟNT=^Wȟfee}xbN[uuYa,1|[V1sx֜ \U5?"r!rb;grm=rpN3N~qjҿ`GG_;n߰ue?mܖ(췼hlj>uq}a3Lc d5 lܧ*=mv6ƞ.{8v 2`;^a VO8+Xd+X=a`'c> ~KOw;_1=n|lpylp6k{@6>> .ډұq{*JZ͗aʳs+gCn7xE݁WTn=gmzct#1+齪BƬzQzXdTOq_TXh;klosSy=o8rRdREg^e襊n*G^(Hr^C]Eܘ^Ϋm_T5m很NfkÏTfkÖZθ .fuo߉Mo¾ ?Z/,}6QMۑguw-fwaՍO:aͶ;kVbw2N ȡ>~[C Nw51_ _\cӬU؟qzE>um=1o]a#skg9g zUl|]wpB=NIΙl0qfnF>k_siy|S9Է\+ڀϭoX֞轾jc>;ҙt)?>x~p,=j~9c>=YI0zL=>0Sy:L$z|J9m@Yc/aF7[{jd9 F٘`ll*{ix;~&mLr&kqQ'k%j*z75LMdj3ӀwV'Fjo1Oߊ}]?!ZM=a4[0y>^gulo5]ͬff f1f3ؙƌLy\9ڔH,:Cte/mt< h#?y <2݉%2=O %' ~~JYKٞ2 |ʾ| 8yʾA)ofzös7>@[e:/2o e~dlgY3[ڵu>R"OYC;EiC\V=<6{Z d O\OMf~iwiF=q̙g+e>>ccŗgd>cgeיg%llYZ:}^Xϳve^ȧa+t^:5j\& \^PoQ{|2sgg}=gG2?:ű9oX~d~}+5 7鯚Cf_v2C!arpk_4^I6_Թvf_l3uk%03/]dp f1˪df`G/+_8g|/+?/+eWt.(,dW,Y(rEYTɬfY2k=wg62~f(le3;j]ew'd`Nʛr`'0~'>v:uNj c_>a6I|g!H0D6/lg_o1-t6^v1^TdD&]T{OwG3Gol<|Dž pcW^Wa]3NWי{Win8j9:g̿_j۫z7?fWuw+8c5췏.Κ_kYz.~|]yh~|]~EuQq3}?q~.]~|*:}y hboytb7]7W0f?~Ցa?0K4N~M0!O8̯ oS_q,j7eMCo/Eno8Ûm/LGj*oȧZWޗ_Rn߀1ߒy-|Kr e `owۦVC5|C@3@y}~s-ۊKs6z޳mYk9qWlrC T9)sbvsO3y6/;ȕN'{<;`?KbwTc _IAgrj蟐 Y  Rr{W5|NŻ;lcw1k.pڻ9vW~w~Ώ{fNf~Opo֙ԇS:kxO;/6 ,3͗㷃;wV?濍Wm*|.βG>DGGYGkU|oދ/HHܷ;$SJL.k tw tt(wYw33gBfݕ_~]tn_]\۟Vs 4x*괭&9?CqZp 4܁prO8=`jrb_zU90N/wSC/wñ^KT/!fz GDQȼb̹ե'zq>alQ<;1ؘcq跏 Npo>b"G>"w3b)$⬥֞3 3#QZl3 Ϝ g·S; )w63l!~+}xf!_r2w o ]?mmaΗcSb;W2wf/9И;X P{Dq6[`qA{8{ڮ{Ir&" ({D?P>{9]~imAMs^lL4P*. wM0аm*?<0P{'?a?\䏊r-?]n}Ƨ=Y|;; 2g΃ss/A%r\'aExp5hCo X Q{ LQ{\ ?lp[P,0~kZ4X:ޅnw S\3\o՟20m*.ZKax],`gn#-oiqH1H.`<6Rv@R wjn?;Jbw%Ca,x3xbv`m1x;F?#mjk:;VJw1(w݉}s  k)?yX]Oc3>nr(wu5̔o+߱-+wrlk+FO;'38 lGVgw%gم /w߃W^&mq:/k_Uy^߈pڶ5_6!n'(NȚ|&zk2]` = ;Q 'j&g81={7Ѹz8h=&I6~sr=wclpwSlt@[gNVlnZ&N'~}M6=ȘUp? ݏ)+O )&5STcq?/`kS]9թ@+mU8p50?U2t4o9M>p4S!i&?ӕ_Gdt7N}~b9]5dbb*7mqo?ΰ ΰ3C GdMA3-f>`g3ZL5t7nIu3 'q{(=p=I~έV6̲YfkCYvr*x= {4\1x` m2_2tyMxxa*6;#9v42GgNyvOb9~%cv^Y5I68gt>Ϫ Uv?o6?L=W6ΜkpgJn=s~o|4g_OOI~ޅlQM k:/?,(cg K2 zʡ¹ QڷKNWsf_Q9=ί /s^c- Q?/xwa sOXn~X*\yz2ʗ=^Oo0Tٯ<}v+|YeVۙ/`e8;c+g e= °:0ME+ 3b6xuxf6x(MJLyqgz_x3^ZiOYe;Z%enTcnlg :]zgJ^B_6־gZub0Zg)V|װZgZ51J{<<55gm٦sq'{v#5<{gه<׊\p&gֻ|UkյdkşCZ`req ljzΡuڛ8u\$6^}%02[gK{n zWhsjo;V蜑ت;a\tc[;jgP{Zw!zܺzڙam:u lӞw)n{T?nwy ma?{wƿak?;6bwxûYi|?œϟI}.ָ]Ip]u)x`l;]4ݮ޳g|k5yσƍ%v7^d;̮/wbeC }w *|C{{P>髚?־CR >&~g}w}YNΗMߝ:a;|yʛ|.Υv |K֦.冾h+7.k T9cx|KWu_.W+|F_qV\+-s3Vs3w9gv+rn >3b`Os = b=Y¬k@_1?ܵG1/{{kJo/{@|o}oS )puλ~?TMz)}f\#jξ|]7v+<9S|/x_fS#Cq_f_Fz_냿88־9vwXg-|{Xok<,NLw6gˇ68mas[;O<8۾ p#ۈ }v6KŷǷ#U˷\s֦%v#:'rl]=b:>{n<"_ۃعOGħpј nX=W|;댣ڑ8ʟ8a{]ݝ!>g>.0ZcbUCU#<ɟl_.Ψ~/ψ\ξҙ]=cyN* gU;1Y&bx_UM_ Uwֳf֟ Ƴ-<0sŒ? S^쯎9_~9ߐ*:}8wLju^G|ywGt^SYNmb9'0Ay>l3\qAAlr ÌyqUDnlO=E}/]GYݵkhuw6OxѰ|8>k$$<+.OK3?彗Fe9ϣ:m]˚n|dvsꬑ%vkbߴ^އedxEysE@+ױ++3+:w!X1sb8tUy3zUj/ڧ;b\Uιjv:{w*{l-b- \kmm5mcw9M,t!f U7;w6vexkyok3ο~'6ak-_Șγkw%NS=ܿyg8Y 3-3o7vz Kq7'7o(/'7W'PѿWoJv)njۿ~i`7Mo:C_˺nwׁk7iߐMߙ-Mp-(˹햽 ["V-6x*[g:oR;gͲwA|y6=xÿmN3h6w5+o57mqW6aɖO8v?֬9ƙG6?r1s>m;(pijYMWբYy~ȜW-?]b,_Y屻^Cw{kc쒬vW|eڪ /̦m]b}nYAJ^a>鬾2?|f+ߥ cWڍy4m7i+G1#hoYkq) d!gi9%t꺇5].j-dkɫ$+m-ʛO0b@SpӶ3 |U檆Ys'J|%y튙Ѷ+kۭvڪmJi+>yxiիNm:z TF9~x>o72dl<ˌgx9xYq|VYsceﲖEAeUt?5,)+}=ϝv1lNw T9i,r٣`\'>|ӷہrol}.rm]gSk N9Z ͵o֖\0=i~-jO6wV?}3nNoы[u{kr@/V#rs2G|0;KsƮ=Q!C@G >ؾv}(yӸ{U% 3<49[ 5>YyFZCO5Pw c>>[pT|N_+0^OUN|q؎t7qMdk2W\j܃p_7NU0N@9E`: fdす3` lgYK@~$0w{4hw;:sr>_EV m'$7O7i<$u.pI g蛴8,WyT@ߔ.,&Dߔi v2nBߔa2I5.[H29gSLV%mcwbZ|b鎬+#wx]";K9Z.XUW*Q]-U洄( V^xUIt]UyЩ-T5UU ħT ?UM&{"6d~}o[G{ıN{zb`}T5`C[|5E<_;a_Ym%C5lu=ؔqo4cU6vk9>)__]u`ka0\C{1V̧|V3\TCHl.Q /Spl kr`7QS~ fj`A'=7ɼWj&{XMu9MO-LSpUKqW'ب.؋k)'k)n ET+kٝkC-a轖b8lSOmњf˓v m9ocY۰:\[{i`zًS󯯳pȰk ubh`oG `- ܐ߯[5Pn43OC.lgਆ;<Ȥr񮆊9CIC媡ۉ{j/#n8-4T]:TXrpW;.rk$J2F:̧l=IR̭t*I;[#4T5NC̭t=m,<̭=kFnuf)5TmXSy6V bׅycըC DV( 4Q#Mt&aM&]0jjCg3 4S84{7 沝P;|Ps姮Ts :rk0zonqN5cTcU uL[zxa1|D |ȩUCOv_q)բ ~k! =+G >Pz=`uŻ:|]>{0{|@1^ɕYp0j၌!,kx8zP5dήG!?G#mv#dx/<p;zP40==dA) F+4kpHIxk|H9~xv.q"qR0HxÊëf/N_kklxvQ  b=C]NO-]T e]vQ@ Ed"Xbmb]vwةw1. <6| <}Mlr?nQű|ѝpcmH8QqQ6bH^l39.#!-Gbqv=8~\9f$>?`gOXCO,\.t8'RnyUnyB\| Ղ"ՉPl< R ql>> <Γ " yIH#v?&IEO VIՙ#N|V#r{?i{1nGd]Oٹ(}S#!6zJ5#)Nj<}=%~<)~<-?-<ܞGO"/O xZg"/bSO"oO"wGU_|-?bK8{(||FV[t|e;~F~9ғ=ck5EطK];TtFaϊ#YﳪgFcn*O|g>kzrdlvUYvs Uq{d5K}"kKSEփ ?1{b#\|bs3Y{L-ZvU{yd ̿l?lb 2+'u=^^Q~_1>bovO{X4}b_dmbnlUnb^}«3]wOϯw:~bWtƴ3[)/^3:_3?_S\zM#cpkquIxu󛧰u%rx{zfG.7T\_$\ P 'aǶ7F07t6)r [{|5pȿ~k37Uoݤ/雪_8i׳9yΞ?%]GiD[hz|Kz eFzKuhp؊mwyEoæޖ߉շcѼ'Doo뻶h~tbhd|J:}G產wwD w"b贛l'Zv{&ffTSfnv>čtFY\d|D$kQK)|r]MQ'N{wEj9N2p{hYqz==9Fo߳m{6~Y?O9?ptF7/O6±S.C>T/陼 U++FUÏWqxY}-BLh~O0$k@h F |b]`hyChEŇ&zNо5(}Hڷ5Ҭb UGījGhu#/DkSX{Q|hc^6"Z~X:o$=?XK3Ebw2'[?^#DVH&FV?JO[_d_5~5~j5}jJ` vַ8kTD 2~cwspRdLL6m?^+tW|^ž6?W^m?W-ښ1?7A/+v>cm8ss3V슍|aAY9<7B2vF_H'/cG]_ 6Rρ/䋣/E_h8|Η7,KƗ#E/D_a_Z2sʾ, g~U֞a-_ƯG}y]7W#]ZD8JXAl+Tr# X+Z9Ws_˯ŊƯX ytjmkBԒh%VF+CNbX9Fs^xq8ǩ.ZTUa*5AߪܾQvboUu!̿1pd؁wawO?UZ+^uw_em]C%]{PM#:Pl{lPlNzo>[zغc=YKqx76C8'=l}_=NسjgO;G*~'=1tO[@S]GxɱAȳb% e^&aȿX8i+NG>\k跗x#6Rs*R^Lz]wз>l{֑lV?`݁,p[5l⟘sbG6?wm?i? ƶB/v]豿Y=7[>Uzll/\/*H&C~|&sξ-H^bTF`I mqzi۽1y~bpߎƄ[{⢬{v;̿hߋrUgr7?|R/6> 2Sc_?L~1'A2;,΋|~0A?عV}Q0~;؅x&v _3Pz8:X=vDn?*׈B?OcG?*~oCv? nmG1 ۋ2^:O6yg>k7A_@l9r3X5 `~[!k>XwKGX:v ߞ+]潃Ub!cױ!Ʒb77v 1b!zo6|ֆ'G;G Byd U/Cċ"ۡsPq`}?nP7^9U>/  {]1aT6&_~!k/cS<^ Swas;0._6\{:1\xma2|6f9 W^!iq0d|)㇚ x'U'(~?崕ǝy'KlΙ Ι /`__t&×;Q&2rLO|&N9뉊Eu~,:kTp$[˛hB&d6&06dGAT'+F5Nf}8Y(8bqPy}_M7On>n6|H2CuhŒ6֦ a>>:sk;}oý3'̐O_P]1>3C'q 6fmδ73U+ξfF52.'űY'=fc;? W9'?;}U'?w|ddv7KgRM8Tsp}gbssYWl]erKيKl /'_Nfۻw_fW KξlZh:0Gs?s9wΙ9{las۬Cp`|3?KX~Yd|g]pf=`g:}-NZ챟sUO/5]\U^?*Zly5gi+~S)E5O6NVȃ/'\%n#.'\%yU"r/'n?W(|+Kou0qx/[HoUIE>g`f_THÎ~=_sщE1g/[$q/@=Η]7KŁfRFsTQ%[pRDkqY>kw._HL5D0|LN`fWزu6Oya>[ ]ZW3Z\,Z8' Z.>L<ޗw$K+J<;P̖xN˘+sfYܞiF{=ͮo'gUnkU/U%UNt۫ߝpYaˬqxor{yꊮoj49ϫ.^h{W+L|fV]|f֔6Y--z\(ĴkLc©կQ<k1{(H fkw$Z1 뵊7#Z?1X+1gu :|Ι$ u$6b;/ƻ&WJmeeKۉ3 ^KO%$nP|8oyߠ'ql0l\¦65~>`>:7o7㐛7%n3f,t 9p{$`K/Ii̋ %;+KpW,Ȝ7'%K0j k(%hǷt|z`iS̞aMVozўa'mj#Io`l%`2NQ?dB2N\jɄW~9d)nVnL#͊9wc$oe,{OV/'Ʀ(oMVb[g&+wp]oQolvbze EtEܪ/Y]l'kvuvwAwޅ̷$3mwp=nәdebdCf^T9oSln=ܶ]g۟yן&~lZl4@_*NpDG*N>-)lɻ }ʏ6vd[b&۱d{tx8+Svh!ܡ`~CqQAtC\|aمz8[/Cgi;v3Gk;y;ߝ|Sfֆ'wOa)~$4Ng%Mv_K1ܥsw.]ڜ. g2]wŎv/ChmtKXUsw~kcG&_Nw~߀v+~Ng|V!-\%;vfo8%6|QGy\}]$?@{t(!ܣ}G^cW碓wO^#9{{u!{k%I~Ƙ{y1xf|6})nI~3 ]3"}Jv6>}׳g =~ɞs엝v-vy@: "|};pj=A#M@߃:>~DmCC{jx!vR99 *=g_:/59xf$r(̦F:ûOa8tqXLr<}+IN[<0'a&L߿M_SMS|wr:2jI{^6}8?/O:wV1ۜ>n<"Q|6قgfd>G%U4><86?*k%E$۬1qcf׋c$E.b{y3}SΒ|_|t񏫆\]!nG '+6&X=Br%:n^nk}u ~6!'yFra3vzҾ=;#OuҰ|`jAɭ`mI?ᄓۉO*O@'UO:gOII>S:KS-'N=O9z{0pj9V$O~:jFN+|N[| ?hӑ< O+to=ڞG-<Vɧ3{VFI<[E|Mk3:h9yދ͞Q'{ 8k|xݝ]g3kΆ%eg6x;:|2?ڬax;:L*T6㟓_H8<zOS|[qNzO9ϧ~^rao|RU+fHݎݝ\*?> `l?U/ ! TattAXM~tJp SXE{T sQMu!U\TL*.Se;Er\8-%|ʋ /|KʳR~|IgQRA%z$OY%H|x@TKEk.O˶沽7 ]V9/\S d{YH1.9Ape6a W/`Jzh]Ι+IS+ʻSϩ HS6QWmyU'\55DnW-⪝_8W)qC6>CeoocSO#ny3o7/RO7T{L=o(vM=#?z4{9T^z^g+v0}oGi^3M?:e2ydrξޒMe[BN3>[kl~$YTK^]yôiChS1Nќ@[%{Uڪ>~Rz]SV.ػfot}7cpm5{h&Uf#S=gɳ'ckz}jhVN<y͹sss6+mW/?mo%immd{;R? ī6&׈ZY\elzci۷省1Wm\Ԑik|yUI CVypƷHA[xj$k̫sacJqyvUD8msYn7^nW1mũ]yqj@ƍӝ&597;I'msf?Ss[@|[@u/6Z0sDGX{R +`nE׬|c5=btTиq ,hܾtm[]|5 d98/$:-hrSHxNL[>= |Ҟrju+ì {jSͧc테;}7 BS#;Bcf/Na#򼣵3 sC5Ԧ͗1fdxwl_R[?Wָ ;-8-'} +LmN .A=̧R{Yca~aۥ}`~#"^,-K[Xj?z)b:Ⱥ(L_ȼa0uWO/bʏRW1חb_oq__\߽⦗`qȡ՟oŇmqqTr諴83]]V&}>HڍmH{2i/}}ޕ;}%Cxd^f}Gi_ s{UltU̲QR־9_yoYߥcUY2Yj} ;exmń2S6N;m])rtީt)Lo9tbtE_N5|s U9oJiel?RNte|nt%Ư 檞媎VsUNW'NUΘs7sN69]ul>ȭzk":ukDnsv+NȺUϞӣQv16

O[t;bWbtKYF:֦OJwf->N 6OS/{.1Ov||3ݯ0 z+gO?D7>|¯3GX GQ%s8ǐC@|~eLF?I|_@5-hw?Ç* T~y π_d>Ań)'hu9IHGe*gCdRn~9~,s_^B:Ә~ )I?B!-IM߰l|(y#x&bv Ft;ۉ#:g1[U+)xʖӟϨsUDY+N 7Mߘow1*&.rMC17 ?w̷^c 3͸tObl{Fq|Mr_OlWܕ@߄{l u0/Ξ$" A?i~0Ow Ŧ9ކ7U>S]*!=SNߔȲ7ݥG?dr6eG%m@ߴޕZzWzWhz2~$-JOqao}3#[O1zWz6z l6cg9}MM:vt;ݥ+]?2?;ޥ=<|]|pX^uGz} Fy㮅-o>b1x.oP^1Fz)~rVP5UP= W]W+؝9cTbJⱊ6*RѸh5XE5d^*XKEUn n{Η7"Mn{` wk9<ܭ-ΩdƬ=aƩbc֪nU⥃ఊq!YUyP0>*s_WU=T5;19]'«9Y\X8G5u*닜9 Q8qZ5'jӞ$7fwF>,Ǚ?T7֪= 7@u;8UW > NK{U|^0]4{P*2} 2.ki-/remֲgƯ5|jo2f-2mt~k[t 80lk2pumLP[<श _[kϸ[GL^0PGߋeѷ:uQmtv.Sudʰzweʢz2w@&Aƍ.N~Z_XK} W< GW< v~"{ hs0}Ⱥlf=7n3b6(m dbȰ`&N Pq&~7>jc:m3)0p565٣^& &3H42wFݙ୑ Trc΍ؘ`cźZc;e 6V^4V,4VM/S.m8S6TE/wd&6襉Wzix.6O0dl4gfj2~;E\ά`MMεTnl]SqWc6U=*S6f6m+]4~D1})4!m}LS6SliƺlLWx˴3iIʕ2ysfZӷن67 &<gӷ#2l!=M>N źNߙ g |Zؘ2ߖa2c-m"_}-G8躥rC` {~0ƙO#ć e/R=$8ouޅmm狆"ֲV&6km{Ce'6d>mTj?72ȼB{ ϯ{ '^.2{2o8}dd-4[mg̮ߡo;nೝy髽{^T}lC^5G೽}+k/[|8u'98i/jo^qrg2=癞bL/ߵt0]t0g`:(v `|36&X1sh|2wN2CRGñ;?3 ؝QplGѼ$IxL&α;]N)訓if'㮙̧U'Oe 7O|=kmvb/h:xsҠ{afN ^@$%@@ADBZ Tw=gs^Y9-tP,zY%OG{vNǖ;Z\e訸U}wNՇ}GZ;I<<:SOu*G:)78睥 |2U~;5_?m>?\⹝-TNv*a]nIk||?.Vwǭd]ՕU=*sjxVWflW;C] ‡k,rv&*sZ-TX.lDdݬg[E2{CXW7m4\f>-Tl!t:1߇C)G-f JąCY9CUOw[ Ba|T(rt~~!llV\@= Մ=, ={\:aue.:i1T4P՞VW¥P#tSMgO˥CMYWO誗P3t|u-~WO誗ׇړsP'K>fdž:3ޖ/Xj >BCX*4>|#4j(t Byq },M}t7l-4}#>a}7CN_G:>ܾK -<98k14r|Q?V~$ =?g~8*r~VVcS,w =MZ53ZwGofCCgWC1t>Z2'cCACWY UC $t\t?\6|unt5|ix2j}w,Ka-_ u`eW}Nly]08- kytw%c׃¡soax;Dg_!p'>uwgrlyB8;k5yd9zet>rp.bw0 ^A.\jhv1μ j{nZ 7f-Cn¾߰C_nOZ?6܊18nsZnw|l680͡3f><}, w c~)ܟ}f/< -7 b-cwÍ!p`܆KSp=kj ݅_Kx&>j?kA³;B{aAj /bF=_bTa*} #.K猴sppl7 %Oi5c88ig-Tml=v0j޸H¯G A.=r|gu8]Mã;QǰQqx5'([O9gghhq%|h˻¿7FKmWho7~>g[N[܉NE$LdwG6=ſ-`uS*\`@$,Fj&9`q'o;fR> =7!`Us` "ͱ C{D˵"DuNkܕO)O# 8rHp?r 6Q M'2 y$"cu~ld,{4I$;L`> O&YLBHF)yOa/-ǎ< NgƿM"G9Es~N;QS,?l@Sį)VO"ۄO5b0KԃSylUטσ]u)rg[=h$:z~|c$1UMM5yNxy}`kₜyՑ]iÌzY+ĥvZg|0iNә24["i}k8ni [O\%!kn1:2]>m]Oxt`f/ "f#oM;f7vN"_̰ ΐ=Y3셷3=igq LNa>ylp>\5X0bV$8W)lgc8bm:Y8Eؗ7(27G21t9;8sOεǹ;^`Ni՘N9 |;G>b`]XTٹIgש 漾yV{/'3:zq;.ٚGn/{jpgf_NU;N5QwN.sxKN-|GYy_2Nm*Ǭv:Ǭ~q:3^9|Ϸ邟o K|;|o\uz+^w7s[`}$zN?0: s0[.L.PYhzpap_g8Zh1^/Zyq8lqߝqDqM3=z\ky\ 3Gg";Ls "y{0vqg&i"[bCp:gzXl~ۙ Qb<|G~X0'ʙYlqy^l*1jgzXb9(}^/y|ɝoKē%v~,K,u,Y|_=Xw̃KeٯlyA2rcqVåSw݉uKvp!YjSJk,:Y*=WKcޗʧ.i>k2 u2ˬg]42pLg#z[f~) x/9L~lEنnw[[.;ݾb-߉N>|'uOt\>uֵwj '7>- 'Oh!?!ݾ>M}',qilbZay)bt'^+g; q~w;'.}Ǟz9 ϟ\Sw7?ZO~&Y9ݭgsy>9}!7|j.7.kww0v):5͋Vxr~9 pc ;/|ݦt2?u:1;qW_0sV2ymmf61ͭ 6[uۀYE?v7[_z]hnh5x#ܮE[ϋVv`KOݞ%U^}X7~μ>}iL~ջwOq1ht2-dK|ݡypld]kݑzG;X;n3,w,>poߪ߲Ѹi H[;ǭYN&fwP)})ArmVCS6i6˗g3#+?ink{݇ە<ܹ]EJ,.‡l؝ K?s;%&1a11ylpbTG;?w N8Ws&ܩﴺ2Az"w1>ewAx7sxYp :Y~` \z⋻{rw'+w.G;rWW.p݁b}sYZ}g4z 3pUJxb*`jUxuk]6_Si25]kvW}zqko_vn+m[ r7c/[=辈{]|{)^O&7V%wxPئy/o|雖_۰7v07HMWX?Û9uһ ތ[q_YoYγzO2z8ɾ--mmƾm99m5n0|vM|$  w ߑ|ec8 |w잭KqKWAC'cٚeg.afߵ^|λ}ݶzWS+|Wq`k@+ޡQ_c~MyOzOk?g=HxO9Abb[~fY{+e]-߶wWzq,qbb bIblz-?M@ c?P9} Ś|Gwj.?=N>o >{`/Zh{^ P@Ή~~8}P>'r/#)7؂ދ-|d5s>R-|<7lc[Oս؏[Ə؏Ϳb'VWY'V|Dܾ>Q~oObO?U{ZaO?5cmnLo|=?3}9|^L:'o^Ab/:# ?xZ+B^Qx{+Nrcm]/6ƚ z%_Oa{Y˗Vy1K4~,\r`q+ʼ cXK`m%X/K¦X_"=H=VyRk}ԸyՀ^|kygZmev۫~ʫ{Ypf_Ɍgws,x vO.٧w g!ֻjX/3"+|=uW_ykb3+(kroj0VZޫدּYI6cϫ Z=D__f^mlg5Ɍݯy?~d>ﷻ^C|~ѼF+ʩsQb;vOk37{Zo__aߨ6b׊;#|j>hu:hkXžZ1σAu$:h1ڝ+ [;]ZuG?}ZY'[X?C^/Ch-ĠCޟ#}(uzY^d|@w y*`tt~g=X/xw[z{3x?[_Ö[zcaXrÚ[psLo{z1zX؛\Y)P4Yqt{j A|ňGeSӈGSx3Qݷ ٟ0?VRaߏ}C{<6G!^`rcDwxOWOȿ=9a83az+{=o9>?i?iy'e'_T39[G,;eX\ 8vJg_YWo/y=Cpw ֋3uğ !g'IxxA~~`.C'-7^E=g uQ s7E3t~Qٗ'sl ~#lv#?)Iy l'Mtvtx_i~jҟoyӟ-?a?BwtWz sI /w5kr~/K0X~YX]gX@?Xn~\¿Z/I0WY௖cM~)~pz8~Kǻ4Mk.Y[.%N-o֯oboV7o{$x흟s30wc㧲׿[OcߧJfgJc{3~e ~e^6>0q޹W3>+g"0kbk?ﰖ+V.zbﱖ+g(kUjk:݀iZ gcG[ޕڛG/ia-Z碇?m~Mg-fS~m0/Kg?Ye_GlꝚ'cZG]57`WoOj}31r5zb#׬7Y׬'7]{{z~3?_ۙ}-_|7kcNn1o MzzAu-߆gc-tYؙ?I?N??YuY7,?;yCg~kyþ߰\?_nȷt%ݰFxu[7:wS x5e9ȭy:VUz"Ө<g[lF\o ş7f#dŦJ)?Y9̟֟F!Ko .}-fwXܟó;l>#<g^/dG#ȊMBٟؼK O^BUydEͫ}\;O|VK!#E%9kɧ8D0Vc[?^W|"f|J7ߘ?8СzwZީ}_jYwKB><)`~_ k#[o<C.a@8{ݓ@A"󬂊yV,hg l.8EUDK-d# *d]I!-ds=٣BVBVߖ< +k˺ K'fq[a /,0dWfߜlg[KSoBs-w1wo" `riv_D>Ld/SXI!ˏ};c̡=Q1^s}E1߁MSSS4s5PjISȊLqV[?΋+vP[(n~})|`r#̳ X;Ӿgl ;Ù֫O0DIt^BT0/&k}T< ܥ8uvd]v!+8YϬ./my [[ ̻eWN3-F,GJ ƖTVQl6Uzk t[R~k&-)w U{=Z{ D N >C>;#>--5>GJ](ub:Z?P(ubRv7&z7~WђX]~X/͹@ރ~J뼵l3d;1hiƖ{2fiGbץ-nF˱_!Z[.c1+Ze,Gg1WM3eޣ)y7\˚?mY45wemYQje-VY{̹~쥜y5"[0C,ghM|f9ڬA֧!3m Cy;/6;{iuǣ9s.ohs\M1޸f观Vі趂ԊgU\+ښ5V0?m~*X?T8mpiC0Vk~_~vA?_cF+M9h ?,NE1M6ڃ9'=Oh/4h4|x/cGOnShq9ڏ$S.6͎yRd@l'I|Z6J_%\t(kI26YZF06Y -NEGd;el RhtI>Lt<.EwcStGq6EFc?NZRMoIqG::x*9O5}H54qj036M: LƦcq>:}IϜ~Y EڗGأtGGRLjkD_wE[M]fFL{!3C,2tAx=gX]ʳ24e<־9W<<V!O24ܨ$4c+/Wd+[I8Jv]UL|i]kϴlt+s^g*<25=gYnH͒O؄np5kd(KݒVE+.6V>Ot;j;[Y62s,|V6?}>W$bѷgU 9UˑmU9>5]FwÐ1lcD?E!gl!s"%;,}af Ssiv7#;9 kajWp)bw3_È%"^q \qXG2c05~}Z\&| g])Y9z<G3䱞]LOYǺ<;/__F|_ #7. %c"/~-{KɫwH'&nd|dm+6:Y2s.MEW?N'd:db}dƪJfU}@.:]28UJ w%3Ϫ$3ϪKfL~&j9R2IW["9r3^B2S$_=*M$_X}>V(9;HsQ2{]]^/_C284_pH28 /Jp> '?&Nd:d˛|dH?dIFWJfK% &^d)#A2{}[2{Qy dyVFyVyV&_Y5HY5>̳j!̜ryV'5s_?gds6K?GϺoWgr+-%L>u%ΒynG%M}yn8ɬfdkYgל%`XܨW%ÍZE%ýZSV-VwO·ZԚ/9Y'9@2uRr`Hfn3%Yd0k fm=I6̳3ڿJdг@/?0E2<#^1{DrBrd':#=3cTp*px T2sJ2^G=ƾ׽K2uL>5Py =7\&]5T} ]5|WYK#U#櫬Q%_ṍd/F Fc%H>0FIf.2ko\@2kogד ~co~o?I2 ~{]$d;([ ~Yv|el&blgU0v`z̭ṋṶtcD2[Hf:*_ Nǵٗ#+GπIqds褸9?\\~s>YYÁNʻd/=N%%3Y{H;+t^-tOxt/ve:}=t>.~ҒCW򁏠$L*E]#e]Ue]2Ϯ%3n̳\Ml즘>6^2M2s.8u׺f1Sz(bn=fm$z,CyyP2oHf=gd=ogϞڻQ̳5yT1̞%Sr=US0[0O&Og=Mg{-=}z)7zi>C/}:zx:=~/i[|Ն|4{4 ޚ4{k>SV25־Olj*UO wI5)۔s)zd(^++nL}o~_&W8Wd\C_qrqS4~WcC?c[?5c[?|,|'<~Wc_f,7+Ü+Üw+31h_<͜09Pa4s 9P<͜( m(ȮG?@|+Ŝ)9Mb3끪G¥Ht2%d1 G?H%8?$_1AF?H9i_F?dF?Xt:o::z88 ` Vn܆KfnCK gnC! CCg!S 07cnCcnC哇_CeC* slp(C ECeCPCPy(&3(WaS e0s<0su fdw0d :.2Zi u GJfUS ኛXp}6d6"M2sQ]2#?B9RG(Oc?R9aG?R}~T~C?R~To#e#|(Q}(/z/zxQi}(0Qf`O h]-;F'Xh=^A/w zѪzѲk$1ʫ{215%31z21dO?F>Z#`>c@cgzesǪ5ugl{#?=Q.qaw9N'Nvc]3_čnmqqu8mϒx]xC2ʓ2ZcW3^ /nt p.Յ5W ZWgoi ZoKpfin-%]g3-%Zg] lgpjprpۜQ9#jzbsprf`o9asrf\#I1GAߚGt~ݔ?y}8y[%9Ol>GՇo?Mc[XZW=6Fs}5sic0+5 0U4B[Cy#0_~z>@#0_zwY|Y*_ ^=]:*sXz*sX ۯ Bq* #PzGQ΍P~; B( E|hdWq=q:uoq\s\\\z/R避H끿Ht.避H>jEx/ҳ_~z..Z b bN]K.9/7(F8/l/QD%KG𗨷 R.Tg\#Rݞa/Yy8G_5L8+212C/S C/W]z!k\<r ˕UTiUB1 O ?2O 2OȇT q2Oh*U+Bs+t^ ,W ,WodB2 |?) A2R5H&O A2R~2'ՃI崕| +OV)崕JOOi*?ܿ"OGUiWEVܬcWiފ?^JO ?fO2F~(_2Fz?k:(_M礃RJW:+e௔J4W*H+ eij4WfLa?LjTW>^*TW "U?+ߞ !|{ Ϫ[ /ZyB u/_~]2ϓ_- $Zg7z#??$YgϩsI?''dHI௉aFsNt~"kt 'V՝D׊ U>Z_,|%H_'$N.u௓_$um<3ăN ?VyŅ ?/Uy'^~^ ?Ny׋_/YHXeʃ^O2ھM2v'7m?$9o?/9.%%#M2;4mGKdxD2;o+9$ͮ3A2;]#%dwN NLdW'!ė@>}䫒Q/= 9zczv s{yȫ%GB2{~m=)Ǒ=$C;S+1_5y_y zdT77qyJ΋dt:EN^=)[k#(STds&3VFֻR#?KFA~_׻Rk#wTu>yɭxvڻ ~CI톬B=C;S_ay xBޥCo|Qۛԩߟ$/G;R[9/FK^[zN*䅒 ?R#-y ޣۻߟ6y[xI݅wFߒ >#ο_2'M2<GA ߉awbpӒITxdkd8kd8ޙwɮ.4 ο{d8czw~WM7ip]0 nÇ ߫!nS2~ap{`~O"NKipLp}H|_W'ߗj4x/JFvfA[|HFv-zOZֻ48e?>0U2|Q : n3~C- n@2pdx|Qګ1nc܀ ?$dip#48~?"\Z2X/?_ ?>*;ұ.tl3/v:L 3ingzOo:-|.-|H>ozs:\c zAps.8/r$cS_tlJ؏KǦL26-M}c _ӱo?.[RO!c _y|R9C:^%[أ =R:# ڣNtWvʎ^/G2'p~ɓo}t8OtAo{$qp+ 8bz<)+6+Ś x/C~- _Wpף% 87~V>'7^~$~Ņ lazOZ_7[8Ie18K:K290C29ҏnKf>v|w7y72Fcȿ7>6xP<⹏ dqu>6xP^<*opNV[@66b}6ߊ`~+K2v}($[>L2|Hv-=q COl|K6;->N}6\;㲱﴿wO66ےla?=(?(>,gcfcˇll]V]Ɩ(vgcGY llc+xq6~DuJ 6~TqY?w&j`Gj`Gj`Gj`GK*wӻk`G1!5c`;Ǵ\Luh.=岖c\iZo$|x˜Ws?sbt.=y沮 %C$zOZ.:d~\ze]'\u"O(vN('?N(?s's'ck?TN8O2E]~b'\r=%nG)<%?/]RA:?Ӫ"$Oz7W~˧#mE3IH}"=8>#{3ʅ"S8>>*E{gUEЭ糪#.o!6gA|?D?('{s3';#s9)G申E7#s1L9opbqr>&G|㏱y?TO/o1?<_F2{^Ty^Iz>['%?+~E")" 8_P pA/?Dp3.&sadl|-\TmܩXz_-\T`#?8Ew_ԻQ>-bTM2I:wOʍ'ISz2bu8g/ԁ?}E| 8`#(:فq/1=_9WٵU_?_I}GUu9Ry_w%x~I΁x~Iv%O:сÿ 3F~sc|.~J2v{a/pHpj1>_=_V ҃RR2ܾ 篨F>]Q+O]|Ey 篈.Cb t?d#.C.SNՅ(Oդ.SqTw?U+ΟKƦvԧu)_1b /b b .\lڱ%\lj%U\lZ.pUyuUٯ]\tkk.vqM]\Snbb.?wck.V^ܑ[c{#\8|]y ?]8|]}]_W.ǻ.tT91;§݌{w&o*M؃)x?>ƒ{=8rH'zpRߒ[m<|Koɯw>o} >ߊ;};[|[ϷCzzG:Q V|N)syUz" C.#7C?BV>FxSn"K?~d$~^d_YYo1j"d~ dFHoK#k~yd~EdOEy,w*#W#ߡ<*z& C9[kC|zdDWA"ɫu% ̧H;ܒ`~D_gF [&SNFUS14Yd u^Z fU&FZ趐H-0 .j]览|i"z. Y~/~)~H)e<{WTNȊݐ[9̹UT,\TY輘[LX:,x|GyHcZ9,|)'Yq<(^P{Q\1((.?YɒKK䠷o q5yV 05yV 'Q-l.Z-l.:KkBw)eûb_Aܻ+caw5+jGwoS^ܭ50e9ni))TJKJWEKzܣDpQW[dckWYeY{]1.F3>Fe|,.e_dGVso8,{8!_z_G/O<_z8/-%,JoY>*)dCV!K񬫔.=*-})1*ÁWij5xPZg谌l'Q<@2~jIȯI,?967|cYq ~rO=cex^V|geY{95xlbk<\Na<[N~˩Ǧ)WǦ|0-tWk+FDj¥[MTAZMTAq&\^AMTATz Z*g+|$X%>G=.W/M =MN2{IP/&rdDłpc 'Δ 58g+ȁ38$8$QIZ q9p#IρI;rOj\1$+d9/ k/rɊ9;WɁr@]#9p ERHQ́)گ8z' 7Rs')1+RufIU_=ߒ99Tc>$U"ߒ$Uyo\JUbntP t`l 4͹8ioHp4֕IXoz8 '=XoRkI5cXWz:Ɉᣫ GOLLm8Ro08?%I>%RIVYz$G2W2'++$O~T&Cљ*a&~ISEQ&9O3!3!dL8R OB}', ?3[X5H& 'gհrLQ~/Ofc#Qd{#LsDGT/g7G:WxxeOGuDzstN\6k`n,ZGW9yjO+\՛5YWR;jbמYgyak<59(=E|r.z?vƾ;ÖY?~'6{9*ϣ"ʮ[TY"*%2WrDxUU1"^Uվ$U %Ueˉ{UH"|=TS)gHWդDVMuA"zx,/VSŞ)OHD?եDV]DY=,|]uq5X]}D^uq#W]~>~VOc3+$N/%Wݚ_m"~~q;-VlMf_^H<ʖ?O٪p`6;6-אH"о$a5v5$Iʱߟ$^ IrzIq8 ?86Ofs$l6GhQs{'a [U.su'* j_n NTUs/Ip<'ڗ$_SgIptkבkjߓ|Mł$8_Swے|MK<%'Zs-K|%_k7 nRk)J۵ā$]Kk+N۵?$ڱ}ϵ?$[m$8Y[hz- >~@: ?= x@@|@9|~@|NFKFPLFꨟ,# ։;<?5Ѿ$:u:pbV2|+ *.$*$p2; uűdx^WT2I2-Sޛ |=9zp:nS K?B}Q w 뫮ON닫#%pt L-7P# _@d@=v'prdP)Ɍm97Խd쥡B2vPw'F&c dlrdlQLBFrd좑{2n<<N6V^ W\)7cQ2odl<$cSߒ&ʻ&4Q>5Q([h<67h\%h"_-4]D좩8-4U*7H.ʗ:JMuv~?j~{ oN͔ۧfäfS337?S|38\+Mťlg om6M깥k)l6P-]N-d )xBW |n![(+Z)BKE 6R1.ݥ`G-cz-cB-U:JoRlu J.ηq[h?iV{Jg vJAj޵bO[KYukIdlkZ36YlGWm|FGmbwMC衍z>zk룓>zh衭a=g:GO[۪ٗ[yVOhΛ 7||B;Z\?T{}bUµ~k 5dj~[nӖfȻaZڒ_y7;õ-ߖ~;\XokoUB.׺\BW 9[^-'KrK [gJڛ#I 9;B{rv둳#TsJZJH{ G=#\i ɑ]%poyH'#txUڞ*TCRztTu3.U(gRju:\3pR\MKpR*uZ3JG:k(q>e֌]:khq#f:khd2XkFk ʀcoc|#ndմ@}h6>0?hϱi9_cA6>ϮXR>=|+Xr9X9}w>>4qg8P3&?N+5qq8]W Z~׺ WoF^{vXe:π?T3=+& e=a^&;OZDՇ b.hgBrȑ@92I15I|Ρ^Ms9ԱIR8IkGkj`5YyC~M?9df0Y!&)NV))vN=C"XM)pib2Ug9jb8U4sT9puéz/NN>+Oӽ8~^jJσW<}8R#k$w扫yϷv|q>יay1_9/ʃyuz!_'yyzx+_gZC +:ˣ_/No' :3̇7h u z1ܩOT_Uɋ* Uʋ|8_e\X`Y|@[>\`|8@gȍZ_G#7;7jϕO.ܨ=W>s|r&շ|r&)Ʌ?'nɅԏ7k'/n֙U>p|Iȇ79|rf7+Ʌ['[,ɋ[ݻ̇p}­Z!pVC'nUOOMUgV;VF8Pkh<_/Խrp]>u^ެn/>n/R-ۋtVt|^$^Z b?*>x\38X]_38D#Kd K^:Y\n/nߦOmM+y|jm o oYY_|R+ K. Z?3KSRZpvv.ȋU3 ȅ^mppv=R@^ܮZ ϗ2Cra Q\@.,SM. ra*tW@^,>\CyW@.ܡ wp;.pr-Պ ȑ;T ȅ;Er ȗ#U ɑXraG+$_k)d;#wYBrN˝:)$/^|ӾLݩ~SBS>ܹK($B.#wɩB.q|K|K];w) :;-$w~|[}l!<[F!p ɑuwkSQl;z~V蜡;+KY!"j /ߖyYa=d1G+{brg=:->`1GŽz桘ܹWϵj].&/ջxŽ[1yq}߫:PL^k/&_S*&/S*&S ,&};Lg#+raC _ίԹA 9RKȋJӦUU*=VimJçÁUV)jq>:ZgA_SKW0yYzN^V1GkO1ko{G]g5:I5ڳZ#Kz7 ޮ՚Ƶ}4wz4ki\:i\:Փ4|[^7 ^:' yKqXE[ W}HWukKWUzqӘ UAkzqޠ>YiX;7Nc@O5MII}l:k&)^lҙF8>FT>QTF<csRs4jCip!i؇t9 ?yl~>ZnnVnVLz79@GtYtE߶h}Lo[tN^oљ^:qޢ{m[ҙ߭:KOg{ pim:׻Us5n?3VmyM50fcɝmʝee=Z>p-u]9\v*]=F5jjvSˡFmW]!_vhsQ;ԻPvvPv9ԥzv%:C5?~P_CÊg|X"alz"a }υkyDu q{DD5cQߌ9zDB3ݷj=gJ}o)*EQ=U:(eNU,eN1ꬣ?՞Uo_ *J^ծRxW^JU/]JNU--%S--%Ӽi *Wi?R=9}LR1W)\}T)\ǕKǕG|)sju)sCڲ.?-keMyBoZ} fmz.-ָ>iuaa]Ɍ.S?k>ւ}-O*6ߎD~90Y9گ}}9گ=x9گ><T͏'D'u?OZpIEn<܉'7'՛ESa<=ES:ÉFDS:{fES:"t~a?^7ºs@7F ?D=WOPߞVo<><-:P9@4B]}ZxzgtO?B}F{5Մ5=oag.D3#g#zguѻ>~2B.g'GM(9)Q9Q8(9b%/׼D:όuϋQGZkpy(AgwQc>* '_ߢpQxX>:/k/[Q(rH{(End헴FKxp >dy_RmQ_Vbpe1cpe*1xr$_Vbe/,:_VGuh(cp*^QY|Wt/5?_Qb˫>򪞽#ȝWȅW_#Y#^Uckʻ9._ӻ181nȅהk1b95uեh ^5F.~;_W UocyqƁ|9sytX5[:;$3[7eoiL88I^N&yօLDLe#Z3ʄGt. ȄGe#/ oC3cԴgf᷵_$VɄof&yd2ɵgoτdwfwT3;2;z>?̈́:> Uo ?չA&}~WպI.)\xẄ́*2Q=k wD3QYeL}Tz2QՊL}T3GgZ2G{dcL}Lg1x&?I};^:SnfcZ#29tI.>.ο3xOt&yr'\xOr=T{ZȅKGɅSeWیky_ ޷ 5Ç~3f? >nMV NzCc):wM!g?TBn~2P"fpC#g|N}d '?Տ z >m½ 'z> Oԃ!7?ܵ!7?њ؆\~\T|hC}m~*p۞mOu6ކkLyچkLA3lC|>t4E\gI⊸ϴS<\,Sk.">{& y֗"s{~~nǂ<(ű6Ա7PǎWmcHc߮gcdpxp#Ȼ O .+<Xs-|3f Ϊ?/sL oP[WOcw _ yxp̑ }Y]?? ~H5p_e xq|$ O?3 .DgtHzUPK$WA'O ,rV6 xA0>\ɑp{>G~yHxZ Wkއt 3_="|&^"|ݭ&_W *<9U)~=5G4p[~<=߷_aɡoԌM}$O³_ ௅7~+Bx~ p~ Jz7?ׂ //xW&)y;{S࿇9s 371^.›7 ,Ap 7/n ^$Xx?c?xS OZN8 _%pSoV^_eSԩ,_^zػ8{Ϥ)]@oS7 y~'~F~7] [ f)JZ+;|'x0s}j]֩ e}P=@] ֽ\-pj^Gϑp+#o}?_' ~^T՝/sPiWr&09_ZM7WƜ;2/toir[z_&_&:<7ܤ_n\rZ9Xw7˸ 35t9eoe cKn8>u @n">gGuۯ5<.JոL^__/pezz= \)>^?z?st'roVY|#V^ V^V. Vx5V7 ܑ}ȷX^qx[y*//7.bjȥ_EuyAGM;$)v?ȯQ| |8p.`}:#{ի`>m41?iF`Oǟg>O ݡoةz ~{A8}osA~ O?'cY`՟3ac_ ֞Lgab{'L.?3q{ Ow@~OБ9r΄KvsLt/Ϭk^^W:|#p]|{-[ Wwk\;0Q0\N)}?6#owoݜ^:緷ero9} J5SuέmZp v۾o+owgĿ, \6M:$<ϑ >rt^qt>|־sre$5gQ=_e3g¬^`֑OtZPvsߑW9-rK99xo4#8UuAsbuDY^T5ƗCY0{fqaT0D3싛MtSр=iy|#rZȗ;[~q{a⸮k8>^fl#?uр}z##݀u#מ ){E7ґOt3\G>ߑɩz7{AQ8?NN|χ_p~{qouך6iP&MrI3v&8M"o;:o9v۫[z&İɵ5\j>XTϩ 8rqz##ac#?ťs~y9,.Cđ:r#8lzsć=4 ΅l6&>?jʺ0VMyOt NRБ9+XG>_񭟦)k\mVW4;W,|kyzw=Q ˇqΧ`Uyw-:2G^+SLG>ۑuUfGȑ/u˝Z:r8,߷1&#Al(;{^ ӆĹ5<V VL Vnx#UOE|#_֑W;zgX pzzS~[&傚Zzrpy y_qh+/oʋFpدtcDlG>ב3w)%Ǥ̈{+j)3Qx6`|uf؈a#5ZY5![u߈y|#\7^E|#_֑W;r:eoˤ|L+& 1WߘҜ6f[t֦i+3tFԘ:I4{8эU.یeRۇuLjGt:K Z5fm}GAv`1ߺܑӓ}: ߪu-Wq]/tvp|G^5Ik];溵vp5`UiR{N [y<c'*>G5,.f\}>G~ܑ6k _Mѩo֦I[ pSFoϒo_ϖoO7ptR=yoޢyovKpGGwl~RQf6ijyK4ͻOjM= ca4̓N_ _$"jFڑ,h06ӢKAȾi38Ó>f\p#w䚯~/Ckn?|˰vا|ʷ6Mˏ^~9ҙD4ԨlG>בW QV>GS[9=LoZoct-Nae):;#\UI=d(* j1WoZ18uZ>FG<#\UIo+ߨJֲTʦiݛqhc9b,zstN`yq-E|#|v2Q9UoZ{N\K1EU~ّ5_Kc:E_S:4ce4˸KWisgͅNtmچ:6c1h{:rb:sMS:`l#g&[ĵ ;x{}ڸՎ|#܍{Z7Cm)^}kӴk p‡aL+2iWXrtI~5-E:OKM;k'q^<#W͜tX{Iր5M/8?m$.63Lڬз@GJ:ϴ XL$':rIڛLWpϛ|kӤ^8>ˤ LaG3У}.diMsБr䪱L촿yYAιȑ_|] V/4:xu`j[[Ռ{ƽ{D|kD-+ȷYoe"7gRGgtؿ!KܑpK^eۼyom\o53sT:`c Wls該p'j9?6OUrl|߷6M?h]oQ0,LG'=a\uѶ_˞7Gy#sRsg4[&ce2Z\Qs[C](ZAuZ:WRr^Km ط6Mt̑/o/7L|a5Q=3az^[ y#G*\V^BU=%:(&S pwзX72CĚ8:1Ѓ@`?‹Z<ۑuUM)`-3η6M 8?YX?ebc\GGa\kgU >ȏ:^mjyg1\}{е-܉w!͋8,Gz!=vt`B?[&=]q3-'S{:21lhOǸ&S{~f=ݢA5:\"It1S.b-;_a,wo2Uƨ|=9^kѝo\s.WW.i?[&L> #UVC[?8:tN[:\8r'=y_G{1{|S-~\^&ʑ&f}ŚZ&p1Wn.Oȷ8rbhzu޻7,kom{TF/><ƇL^g 1GePo^N`.a].aPPF^;G~@gSKn+g^}ZխdF~<XG>ёknE`;FnГ/ 7jwW+2cX G!PKmN`Kr<6@^z.#?U?h)1.P.) շ6M7^>G}/XCMQKF'zg:u_rmTG;rVPc +厜coڷ{+oXA 5+SwU\sTX-^P9F}kӴ̸k+hK2oU|::Z:51\I): ?qj9Qg`JFcoڿ1\5)7W|GёkV e/SdT4ۑ?·MsAЬH^p+kw`SV|`%q*:ȹ)o: vSz"J\D*f+9־p'>!AdV1׎}@GnUԍWwّqx·Mo^jbQ=[GX ;*ٷvWf4W<-; ȝ0wdX&_:f rŭyſ5wkȑbWڵRpܑ[&FgJ+c5Xm /ȧ:rך`š]kyYdzW֦~qoѸoU| X&/a|dE:i NtߵQ!G#Wo6ڴ}UjZbYsxor%v2UޭNu#ܭֺ-Q[K|[&f)arX1mƊLn{GtsIݓ㹮-rLp#ّ_u6(us/=|k1\ :J'#ܭy֝uCMomgs_܏zOOŸ&Wa%V \:_ёjouҹ|c˷M^ |[x-y5;+Oד +ZG[OjZu&/J?14yĽz^=߀,zKX&bE]o舷k~~xrO:kq-@g9l[&f279F_b̑;rֲ6V _[&:81Np0>ea,tG? #nx בs䪟'uV.ĕЍ`|k7,Ť" FԊ=tЩ#o5wȑN:vR.ti LJ־ cU.calptMg5`'uَ|#^VX}/X9X}'x#([໸ĵ'9՛9(^aG~đktRX|[%n-o S0)svutIZZ8< 'pccߍGU?7[nlVnl% G־)dĵ_ɢFH<݈/9\sY}Fֻ:#g[G7E}'-bZ䢯&\W!78rbRd:7.OUM?kil]YyWGnnwr7XI;M |=e!:X=!t"V%mSMՎ|#%%a|˔a,SwtK'"엔%pW;*GzJp`{9{oJƽݺW*9٫vZ.GM>s=^}kӔ¸Sr \Fޖ|>|$o?: $q֟׀yGG~qz׃`%֦)m_ }+1)$:;;:eҡ-wbÒǾwkE|#W_oX}#%ݏ85ܷMĵlN>5fO85.fG׃tom?1t0>q7X&&::ϸ&{x&̑;rAzh?"nKrƺзM|Hۯتc's8\s}zg~{(?[&7|tS`+I2atj}X5>l`SadSs$ y#G*Lzz=]OC:Mөo p?7}L'}LY ҡvN`A-Izj$wzvsy01^!`A~r)7x~[q/S߄u7t7tndK~sN됫zȳy\~r7s"|ktn^e:e:/ptE5ń{Okx#_ȫg/;^:Cx^4_{NK|tNKwt:"^ tyoO޾}ocwӾiSo߅.ytQXKo3oLM/7=Б9r\V^ W{W02ͷ6Mq/ .O7I}^~Gu?w9,OެGב>Z[D8盾i{z&з7I EN[PFddGGާ#oS(d?GG>ijk̷6MWGҕQtU2e,ue\U_+ODQَ|#Q^ 8 Iʦ|;]ϒo_7I?7/CUOsđuDž V^bGٞ7I4ݚƽw }QQO7GG3w4rrَ<.?}?җxvZ/{'}c,m|w[n$}\?V|#W? ֦}_F=vRQF˸~o|GP.r#\w?iO}kt_\{uu]b,}Ox]e?S5isWr6lG>בW okN+1n?rKi+9p`8Wo~V!{{I7%ȕ>ȏ:߰fSP#ͷ6Mq/=fKe,C2qstw: wp#vqab_SLZ[ERRGܑk}(ǀgOWizۓa|zjme,Sk+cQGT:kq`g6dk~қޑuӐ_a'}kk pZN&At44[G#z{iom> O \ƧΥѹ4c>K3s~Z5[=y_G:z+Xy]VF9=p᾵o,{N\}1Rnor[+JʻV0ni<ϸFqjG82}c,KGG85}Kد\RF>w\uݗsCw6u{:7}^k)91x5DU!cDG['>c~cW_z 4}`b{#$O_ݧf,W}j5}u:a},z!,!!G5Nd.k#ݷM^-ɺʔY׀8TGʺ,x^FiEW+=~vc~vc~1ҡf+<2o~|G^U'ػU ?V= 1x7{N\Kur EGG#|V ?_}k{q~*>:Se,Ogeљ*~:SMدu-\ۍ5ph#U'ڻu[;yy?[j p bo_`,_2;9:۔koS?9;t#_UWĊCgai_?I V_3_}y5|~nt?ȇv7XyGpAa5p~g@ p#U>$xp|k 587 7 Jqt-t5-n+_:r\GooA`9(۷6͠qΔ:/$n0$n0tT:AK',~!W#F>Bߟ~#R׈ w֦'ӷ2= w0ŌeŌeŌk Q 厼ґO?ik4ω{|e`}ǀ`}ǀ,GG03g&?n0G?Xy=?§sp74L_|eM2::zq`_ #UG _ț8rqa k}k 3#l'oeXfgҡtJ}H rmߑW_#j> M3i p >D =A2CJd\3DCjO2R<}'\؇ʾ~ pZjטr.:)+JGڔ?S.+O\ >|kӔ&MsYeU[1)}+2emlJeE1ςO85JL?VNgY<8}kӔM{Niv|;EQnutO ~}Jd/Wj~/\U.VW*O/a_<p5iĽ'g?{|w˔]<2e::zqMKد.J :}\* x˷6Fqo m6TQa,3TQa,34!C^~CFBG7n+OodQw޾iN{Nx|}12Cu_c\3Tk[r7rKuߖӣKKրw8=U[f衸ĵ\CQeԄQGQG~\R.k V.kyb4COĽ;0>S|)>ԇattH88- KO5A8:ˑg;0eme)F~omaocaca::a[~ome;Z}{X_Fٷ6Ͱq {3aȷWakz5ԫ$}w!}p'jc<{}pyL}k g}]3]3qt^z/#?_p1cNה,_^l՗@﫾7ty7`&Ʒ6M9kJ;,tϋLy1)LN*xtӓ_ oj}_<ۑuU``լScg 4wƽ'_^'7I򍾱GGIf\S$'쿔zkOqGqacz͍`x[q/#W^W_7om:݃F{eF{eFvwtC5#G:#_ƫ֍էW^ً'#+|kӌ)8rym||@QGnrt׌KWjx80=xm`xM3z'Le,SQwT;ߐyT7:F~ &֦vYo37TLqt s5y~oo _&o 7'vsyazÛ` xMS ^O_o7Ik_񺣣g\SO8cʿ8:θRk'od #?Q# IkFФ }kӌQy`QdToF05:  W1@G^ȭ`~sX4Ž'_~T>&cQXfnGG1׌}̄Z17?}֤=|#?(kzg&IA<֦ϸIQ22GGwe\3Zw 쏮}{dw:Fy|#yC{!ӇXO',4WŽ'}|/c0sX:oH'fr 7Gݜ>ȏ8rmfM5ՑsZ6S+7{:r;_uOUmLeԷ6Xj{㖃 3vz2cga,3vstcoN`*9[蓧j~P+nr[onA6Uyz5GN3vo훱ƽ-zohnylOj9rigN-/fiaq1[^ 3y2ZttrC6.W:íwi~W':r wlW:򵌕[f%qoVMVziǭ#|m igvp'\͸P$^ʯȦ_ț8rVzo[O /^|kӌ?q/=xXfg,3w׌; +|Gnk+X#=>a|oWNcpurm1~ԑ5wuځuxkˌj3co&4{[3y-:\ ȳn[wraƶ` -|kL81$pp&\c b,3jG6鐏J'{nrm۝|#mc͝Z\6tg&,}3E|&S3&s>#k33n#wp{07ƽZ;}#5w3ʋgvW֦2;#|M:/2 狱oS!7'$s)r-|#lVۙV#g578I]c8Sz5Ys䚯Y{;;$wfO[fnw 3I#xV f,3>GG#q$Z#x'5cw'}Ӭ|#׾o'},ս? gu'}3 pZj}{Wtk؃:9r׮߀UvYvQ.!&Ƿ6`ɹa|&T|'R|{;:ҡ<* O]K4؋]\}y|TU*VԱ}vTTjZna![@¾}  l!@f_A dqds}/}t<, jذS1N=(>Vz$mRw"ĭf5]Xҙ{!t>lwJg]ۻlM=9ޣFS'ס{u^~Ϯ/0gυWaz\kW'9_=w{ .YY,k"|CK>KT6=q3=4 {V|S'>fu߫Nkkg_xs6 6Ǵ|fs4hLrODgy Dy%FbIʆF;scPۊNaYw X8_"xN::8M|wfObO;Zqdp$ǧ>lP6MfF~C`f@${s~3S|kŷ%2c00.pţO@F1K7t 3p|]Q|e<͞0ao8{\S<s mC,}KP6q Lyoo&wOfߘ ̺DGO2ҵKdr.šc f=fzN(̾1c4Se|.#.ow*bIW_E,zUĕjw %NPS'o¹ͺ˂ţOGoxX~:Y `zZ ܤÊ|e-q>Vs "Ǯ/]eq/a9l=++S|{soY[fuk}Jz¸_p,7bIW>ˍXfny +Cq3>ds6_ ̾oه5_e]߃X-\_s 6ퟡch^ڌ5]ͼ|mFĴ%ƚ"}fbp}/nl溻h8>8>ge:hm mc fCbS|GS'q툉%F]p휍b?R]_l hf +kMQ<+{0-H1wֵ>ow\0nOw~K;%X!eg*W {7Pr>pߜoR|S's>fߘkt_3+^t>s ez@spM|`Rrp>0g 0]SW .Y#uwyK<%ݿU6.Jw~]\r~s]OEMeߘ{?0.5կU3:Gz8/=f7K5{`zD\U?}8Ri{ ˡ lbQ/&(~9_Qr>0S*Zcva9o"hKz|l J?:yfL16);sV>0}`yqqµ9c`ʃ^Cٟ>0u?rO!ⲷWp|zĒ=gq'tİ1\ 8EkOKf >0o=pkkK2䶒vo9=[W3 RvvSfiskK+CC0^ׇe+Gx;_P;7֧z q>]\/~MX]egWzYwyG`=v(XԷ9q]pVr9ǒ: q l|\CWq |3]Sz}[DC,bXu6~G9t Џ ȸSp'Ē(XLp'ĕ(c>[ ?xd}=vh g#pqݏv9PI~ rذ 0?[voX bX x#qMO}?~"8>bIoXeýWzso[n=|Jgɭ'n fm G ֧/y g=b]3ſx\`, 0׺֧`?.–o%ٿ!&{{"DsoO?1,|%{1؏3Ӈ^K bI Oؽ9E_xj#C7a7uW4qF4C["]_zm9>a./Z{cvGvo,Z̺+B4>]\S$".L8o#Kd(~q]vyg9X'MPSWq eX =ʺ+F_:@ňUZpcX6M?xW1ƾ=0ъ&Fb"\_bE+ٰ0nX_Еa+Uƾ=0ъ_x{s/1X^+΃ x+|')ގ!sc; Sb7qѫϓ/ bIyX9N` 'CϥkJ wᜯĘ\q|Zv1KBǰkᬯ*n8Xⷀ(ֿupJI/Z{8S?>*Y=sԗ, ; %}+ Y@\w|a,>8R\Cc[+&sJqm}`?_R<}]_9c6t K1~RQQ<Qi0xnwm/{´6 c_xW)X^vD+ӧ,8G6_vpKmQ6մA kC u4-1#Q|FPjۀ;)ב~u//ͱ6t PG#X_e'(~9_eԷ2Kه9:/!C^†UmѤÊ| t?bIX?U5k_:HWexW6/0CXE//:H#Y_IOV<+>j$-0cSw)+\_9:6*( `80zX4õ>e@?3FhB,KR6| qe=U9*\zO* 8U&pƵen)7 r{X_僀7)>Gro8QÀS<]_En{r@qY9_І8sW ~xk}7qq.CsX2phpKS6Sh86yUP<k8[q*^x+NwX.XnDZ*Svs*qԷہy.}7֧ <9g{P 6;GnlE9ĕA|NtV(~@(#Ƶr4}]#u\_ܶX:Q)uV0@\_%#a}hѬʫ+9_ж1Է_AXZ2 "8G%nl8׈+9[Ba=V\A/)UVy}]%cbXm\_ecX:BcxWjm ʌk(]_O*~v 4|UoPu/ \SC #X2{!o s29 *񬯪J`wR< cO}jf_Wx+wrr CCxYkU(ݏU>xC~tgs"'BsF%֪LImϹ&q$xĿ~tO9q_B,/Ēc<ڠΧ tN7gUgPsuX'$g)k̡ ]_ 7;˰16ꯁ+~9_՘j]50=^۪ya"~kX{s`Z(5w,k`jWQk}ʰ|>8GEĒa"bɰHe36aic ǚEYk5K(>QXj] jߎ (kaC]_xN 7 757S<竦qQjvǫA2UQXcǵe8Z;|ZfUqG4[*UO}-=\sx8zWȁ&yX`;)UԫڽIӵ>%6q'[o(!ĺ9B,KpŷU<`10ރ!)+Ħsϐ Ė$6lv/ic Co= Cx&$:8=^= ߄X{]_F\9c1G5Uk.Q<>`[c3!~:c9F/#C/žUOG9_c?y8uO`? 9!wKFT6[h86nC>Y`>>{!w%#lHq!<=ڤW@`sh̾54)AkgG ÆI"^ Fi|5,5f_װ IXc\Z2 9߇6<ǙܲJo XOf_P\SFgGސQ#dT{e;(^ߍQamp~e/qOzv_BnG6X)s5u1}k}JzqGs?8XǽKf*ǽ}a{0p~w )oRp٩Ckv.wdt ~^ټEߦ ~'t wet ⲷW߿C,KFT6g6+m|CpvwiV{NA3}wcq 6Eue̽c91Oឮa=M| >pi@>/)c:!nW -8>cFq|Ï@?njV6|qe ߻ _g:w⩓{Q75s:no  buS1_[az܋sjzc{;08 vOsr߃{Xop|KS6&J!9ȍה1acHlKkG=@v5%}^\Sk}Ja4qXs໮`z<0x(u`0l_ Ƶz6Dv֧qx-X2{ #Gpoaĕ[s~Vx7x(S'̾c'+}D_&N>1_ ?R<࿀7D/:Cb:k]S&b}t'~bDAX2fI|qea4'Aq x⩓fx6uwpGţOµe3ȍuNw lXsyx~ȡs_Xq9ܤİƟ:n^:̧BO>}Oq}ޘ>eR1roICܷsA,giK&}l, $>K{λC8{oxסj`v~!_(~bwro哟 C|ס#x;_8&<1g]S&A\?:'sX2 Ēɉʆ!L>c}=_@k}TS) d F,m"_ Oy9t \ {D7)>G#WoML}<(G c?@ɣo< \Ⱥ;ŧ!O/S?>S ãЉǣ)~9_Gs-dxB>)E]}58>S-`Ē0bxeo#L巀}a>V{ DZ?x}1h"1"ֿL9Dz?t [Kx(u "pY>EO=Z2淪=Ēis|Q6/9EcxES);S'Os$ǡQI3]ŷCֿL[x1<9_<} `aK2 |p|x]F,2bɴo ˈ+x]]O` 8'=I)_xoa,uc,{C a=p:1Ɠ8Osv_֧$q_M$ĒD׀Xx+O G%m*:c`?fZ'$wI9ǒ:? G Q|9_?wZD\5ڏ%X%uOIBܑq $@?w)f&~KX<-{ߨx)RNZֿh9n㌻C{)'9_R{,QA?ֿ9x!:,`:pg+uc`)K}\Sf,C\&2c0o_"/Kf*]I6y]eO~ Ê?XFӿ̬Bn<{ѧgC|S/2i% y9Ƹ֧JGLźLLJ#oĈ%v(F2~#/xOXS/o{Oi0ƟpXκ  ֿ̾s~;׳:?M qOP<'i00q}ε>ey)18>{dv/svIhQ1B6߳;Xɳ]l#0mFֿ|N~vEdzS|{sΞfx'`g/>ҵ>ey>wN 3"%snQ6W3焽[zn!x94`+x94+7dr]߃Xֿ̉s؜cxx.b3nS8_ CcSn`}4k}\ |.2b^K*^W.Gϙ==wTa/sGtn{[azvk8ϹeOìf]B;(%s.FWS.aW't0'ӧ̯@\ޗskĒdʆ{$"=m1ˎwR|⩙am=eIeǁ+> ֿ,s 6DzU^~9lXk\]Sbs.oL܌3{1k1 qOYEzyDp|~)^t'ʦ/mm|Crrk9\V⩙fykkMȍ}’1q=*mm'0 K]S^5H Ϣ6A,Yt++~qe `/z(t #fF` vO81T],b=Zrc6az:1 ?xWֆo&Mǂ>3EC]S!Fź#"SĒEuA,YTlxqe ëo6يx8OSC^ MJ- NkK9Wso~6ǫ1f_ F﷎=Zk}Jg$?1SgRYgv^??t [YmֽOlzYV8u?ֿ$V}$)lVQ4ŧ+1`pήcOʌ3JI]SA\>n`/49>U6 4s+ů!tiVE)CC9uת ',~͵eTc N_Ni7wW||fO0{VVZȵ>e˸tĒ=df%-i\rm! Nz\+Ҫ_xoe`z KvYs 6Dz1k?n{G}zzVZOY2qy_}d`3_88>%KdReu |Ycx9/NPS'[OXϾ5=(}’M/KNx\M?xW붎}c;^k`\tOY5]Yon",77KS𛛈+KMi77[m;(:Z}cAÀ>Zk}XwNsC,YܠK+?3/xj\ߵfݵl3ӵ>eg?<@Ē|7dfV&_COuhmVu ͍ƖAuf0 zk]S6^I2t*FhxW{}܅5Q:pNwN`]X#Se8g7A[5s , ,@D=ز޴1CeuqOPeϞcs[qk0L>bɊ۔̓x6O p'G*OS\k}ʊwiZ |qO9ĒSde36icO osSXSu$`pe<֧9cn zbsخlP84gjSivNgLuek}Juc?V`n)sC,IyAST6|q%)χܵ]S5+uS:= k}JJ/yRpn<{V)<7KRxn LQ6KhOYJ?94,{iV+uɌ2iMoU [%)'mV6meao< -۪KV X*es mWK/a#O0%fKXoxk}*W܇U%*ĒUݔ Qߨ}e仙gŊ(2i3{:N3ֵ>e#g"ĒUnbɪregWVY_y <7]ŷS<_eS_y،W)9W`nsC,Y};sC+Xz+?YdS_G?ݤÊ~q_L7Ō,ec?zbn KV7@,Y}Xٜ bhoPDniº~&wK)k~9o~KA]ټJhk^oAc$+>E̱Lk00s)kFx~[sYܠk(1Wp m'[oɉhsZ*6ro1ZfgQ`6k.s1`n%k~nY[Wsx;wwR|u##{;w27UX{"}[t m7Cwq9Ŋ(oY{<{֧976AO֮cniʦ6EAqXoxsYSEkƳĵ>e!SOWsK2bIj Omln ?jǹKpO˺~g`{s1֧s37I Mj4m>A>p+A䱮?(P l3Ƶ>%=|2u0oLKR,Ē-ʆB\I|a ɣwy^Oc]wDGx:scݕ 涎6K&bɺ FC\Yǽьu}ȣw%+>EПԟuS[ dnГu`e36uhcO#S?q#g]t%0#69ŵ>e:1?W̭&[k!S6i_w6ShCcI񑊧s&u1֕o6k}J՞1ߦ{i|'$D ݣlNJ߉0މ0|.V|@1L>)0y>Z̿0KK`nГ 6Ņ ?mA0,*̺40c^E)i$ s3~%i|$[egW?OS?v)>AOYןS?`<;)sl_`nܠ'ܠ_R6CC4<-hRaS;uNどNي\k} c1m5s_ܠ*|@m|[COv^One]V6YZ|ן;(b6XʆkLĕ \cͿ3d+xg\;CsR;b<7ZU6|܆-Ē m dC hc yF4-O%0^`}f<]S6g0?xs7 o l(~qeqAS# I񑊧Gu.G lsk}_y&87"_ 涑bF%P6a"7G*,V|@HhQ!:}]!?qL֧l|lf=8A7R6h81hWEn*rNn蓋XpQ\+29ٵ>eF^6bF~Xq= ĕGr,3pOu"xqOIs 6;[} z~?s?lg>J:7ۇ?<&V<\)f]LL޵>%'-{pt%-K'+>g|KC9x/+=EŬ{=x&֧{~dn!anʆ(WyshQSV'+>EU(;4`3֧dc?A2bIB,x^pO9ĕ )gg)mƓ =/hKZ*0:c^ByWk}J${eܸMṧ bIx>SqRҵ>%^1p#s_% $ʆ!d/_1RLALhe~W|S=̺kncf<֧d-Wr!d17V ?6-%+>E~X疱]CRfsk}Js:gmMĒMXa=)"@KS`]ǵ @s,k}&sc0gt}aUW|S㠗`\03Cc$rOK)bIeOW?1XUP@ +x\_*Xcp]y،gk}Jnֳs z}A/4l3+[ћUPяUF4-OG-W'S{-׹֧lysMnmmdS@tYhcQHSǢN+YcxntO2s 2s[ܠ'[V17ʆ=ǡ^+֨,V|@qJ8k*N8Nɳ>e~|6I`>gKrlbIhmϹ14 跫0U)?\źs?a203&Y&s΋N07Ē17λʦm9=ic S'֪x$Wz*$Uf<\Sry~37I٨lJh)_d{U-Xu=>:isx\Sr|',0=ɽAs[){[mS㼨nOǵu=}Q5:j{k}Jsc?Kr?anNʦmic4?XS@'YsЗVS69е>%w>+'17~7$ߍE,U6|q%}Cw<ր5|MKSAsjX=5O|33{A[qR L_03{~Ж07j bI$AHB_(xbAM/~u/wZgk}J21c̍{X!q+ĒRe=W򸇕?lWk׺oxrl-z9ҵ>%, -#`Ē[ @\;<qOP<-USWȵ>% Y?}$?A*x@hc -zRۤÊqԱb[G_oq)k s\A!pWw wK >W6qXφ!lO𻙈+[Lkw30~<P \0/|QpR5_nX&V<u]6!m\S c‰- bI!O@,)\lJ!OP4k)ǀn~K an"٦z@n Ϳm ےx mۨ%a<ϵ>Q)aP,0{7M/;Έ+E|5,%=R}1E\Sf"cS{q*%EYʆ."qEؾRhNT<vu)۩=xV֧4_FD,)fXR|aR/?ցm.V|@ `faDIR5~i̍/#eĒ!ʆ"Ue2WO/umoÌTb_`nK? l? hyS|XNa}J z?B Ē%%*>へRg<Џ@-p+sYׁ`s`g )%Qȧ T37%%-KJ*$m|B󯀾}NN~^O~~κ~~N~~nsk}JITP?KvSK0bI F,)Vaĕ>?{~'+>EJwJs,Rǵ>n1_J bI)A,)/+KU9Έf~gKS>f]WAwR0';1֧*U: k; o".W6h/L?;,^NTS6|q_wj\ŷS<.u5qˌc:0bIF,) (>?R}aujWOcƙumZ]]f<֧9{x ){%G, U6J53.>ɻX}蟿`]q nOXR>QpR5qhp M?#O?nۀ6ĵ>s |3sĒr@,)?lxq|avS+>x1供u}l0_l|K0sWCټK{AaoO?5Ȟx_SObYk}JTNbI%A,\lJ%=so'NV|' a]ıı1ZRs ?wvAO*/27fki6_q}C?>aoD3'?e]DxV]ZRaPw`U|gbIʆ=*J{T??`&{;)>R>f])0{1U)U<`?9D,%Uk D\O \FO|ABc,v}zs~O!Wm*8uz ԗk}J[[TCp|ٟ T?A,~NټIK~+t OG8sӰuz04կ mj(?7sш%|?zI17~37*Is;׬3N< lsk}J5`n?0FTM @\>Mx,kOoeuz?0,jkgU)5zYS0;,%5|ʆ ;,P__~IOVjk9h׬sВ15֧{9~&xsˆ%5C&Epaĕ!C9x}?si+\<`?oan?XRcf:i7x^/`֨NFkd]_ڰz~80Ƴk}JccɿrQ[Kj-%o)R}|B<W(XW*`E8a>>bIG,V6|qw;nT|ӎu?Ow[7ZRs ~5Ē:XRWl_UuhA[S/^˞f]_fnF_y&_?̭#|Ē; G\;};-.OoqpOoq%0~?R1֧Կ9wĒz>ÃXR?Twĕz{Xp̺n1b:i)X<sC,v4(&@뿡04X|'S[V[bmxr7C) x&냹5Ē>ÃXp3<+ |o{ _xU*_U893ܸbIA,ilأ"4G#8]SĺL`d\ZҀs`?hgnĒj bIʆY#4=k;ë8GdDhr. 2umiu8.k}$,@_uOGST>{l.x8:< | /YlpuX |Z.+\1Vw~0nWO,Ys]_T漮o7nY W_ 9|?c d kTl5g^|w3L`Ykޭ[ W 46c-Zcs+rX 5 \k*?/wW?sv7u:jnqk>kTY[A+8< n&E:0  46? \冱5oFk[0nLAY[c^`Xkeck bAk>Z޶5eoµm1V>k>k 6+.ïrx69\goõ͔EϢm}-`p-`p"G=,7\=,&Vm d8rx;9Q}Y;SyN`y1uy56|+sBO/wW?9;>y`}<7+3\w.h__ (|c g8q|@_i%xN3{  }GkN-ٿ`p==Zsaq_L|4x"g _ c뿈 q|>`p=X\GsE%Y<9uh>n@ϢC;6 `n'27 M5Fߐ(WwYvkO` Iecn6<冱 ˘ͻԠoxwp/738Rg^nXe^})3܈'!>F~ c}'n 7?>x.wW=f >n<|7q 7q 7u4mAԎ(x#A+8<Ow9{bm'q<7uP6f)|X37X&ܯ5W;ĸ&4ۂg9<A^ƨEY{>^ecЏMs& 70VGGK -[y?+~óAy~>CܦlpsXЇ3΍>yn`p3 nnhRyP7._}g8rxs9f`{0! 7ϏbnEap s= n= Co{9Y9q}/+393 q8 s ㆹ_TtAp(8p:y=a`A1--b ~gKgܶBn;&h! B ~P /rxAfXG>/XSnY>ۃ!;$K_|_k<y)apDZ@c37p p s4DŽq-d{"}X3k =#zti9O٘z@cVGܶ  u4ܫqíܫo_6aX; ߢ[>ְSˉw/<"ϭnŚdo=Rn{+{7HM|=qO:|}ᓂp@s0p)|S٘5@cvs;rc5[{7U-y}1xlÀ9OG*3/hߖ hl xs{|F1n5U6$Y8Ǜ:|ó'1q$xlpϱ wvnu;yc;yc;8'Ǹ.'wy?'-ˉ'ѧUN٘Nȇ#?Qn w h w {#< \sxԆ 8ofOmܵ@٘{c&'27]|?ct4|ㆻC>>xɍ;|Y'朰^k'X'\;W wtNn嶛h;7Aw{0 x)'9rgx%qK`)XH٘A` kX`Y dl{WP_Y6`my$8ϗOE>%̀YRU w? ;_7.v +o,`pHqݿPZ6ii8K8|óOC^1(Tw( Q7p4( Q?贝Y+Zp`iq<;+3B>܃? xs[PO/cn;10n5g:?kM>Y8#ƹxޥl0&/ؿ`0 t4_0nXdu[>Yg`yr91֟'Yg`yRO/T3, ̵e`P0VX E/| ߝ^XgrecG46o~rXa_p00/,W6ׂg}2_o^I|30ۀq< +3,l 4;~+,w0VX8;~7,wL|;~skg[<:8ϟf[8kӬsq>Y8G٘a}`.> |c|co9ÉqBi{pΛB9.!ޥx~l̰po,}X ˎrS q4ͨAӜӢlׁg5/~óǚt1iNxP6f>A;{X1Vc{.w47o{?{)6ciSpx1◁Y_1=łl0wT0VQX? {Lai{QYs·[>Y\`8JW6fq,X翷Qn{yoc{yoc{9Cqý|JCΣ\sx5 Oq<&EϨQw d+ 龜jP~iLe_~ax!p>)3܋5B޿ڋ` yojbp}鎆{1n{u}/<;<]3+ߤ>㹯1}ӑϾ(}37_}|cnt4PAjt3l.=ϟ gY/u6=Y v1}M_7(Q+sjsjuY/xg;}O8@~ee;j= tx>7` Q{ \JeE>?27p|nEG:|Cb`~ axn ⿩lpX7p}+}+_|^s{0nx{t޾_w3.F}=w]0_0*3<7h?0e}+<}+<0p_6 p_ֿ|KPέq k%-{8/8(3t4m~%˥݌K}iBt0K1ɗ&@ѽ`TXZ̭?piMM&z5yqxX?v/Ns. yx:0Ad NL|^s: 5 ~j^~{x?xp×x^\y0`1ÃË30- uVVD"h_dA|7o߀8 {#K5ؒ',V6fx=¡>EPOen39,C  uYG|7.9 חuf=70y  .^gn'`n+t4S jt|AZ9:|Cg_zŖ7x;>_)3<5Xo`nw9XzйtjPjSEw9>y|@cG@cG9wA=.5:{e0_snXyB`\lX<07#'ÑS5GQ5 e߄UM;wM9O7anV<40Hy1ã6u?^`S6a}tsC}8:\J G^ zlӋi90馗9O7ycG|xsuQn+<sC}8/5Xc۲oƺcft?nZf+qnZ>E̵c\'WfnXoWanUMj.nJ 7+};<׹{:zc^9᱆)nlxB,}"([C-Ut3[sn-޳x1;b.{o[zeG5XL}kt[:x}~tx^<t[`ş*3,u8ö̍:c`#:1: ` }hR:jteߎs 퍁W9v'U8O7<2HܠlX7fnXcoP7u4]A~Ɏ;Fy1bpC[{=Vxfz~ajЃ5:sRyd';oHU6fxXy;'0v|sC=9w4\'`8 &hy}߹x:Nn u㉑:A?}'vtJ`UCyC3@9<>b7ax} OX `a{}Dgϯÿ59QC|\B}c|J٘ɯc>;0ddhx?'y?'@ s]_P's^@o^-x+3& jEu[33~óDy}:AxlԵ )Y[NX)+ T'3 3iPϴu4A?3 gͿd:xY?YKfy]:YuA \ ܢo3w3738A? 5:^~tx%%|N٘vxs+`n'g == ϰG0ϔb'/+ӫ8gŚ;(#5?2 cg34jPN()/rKT0|`S;9r5Sهcpy6',³;<4QJ_|s0i\w9gOc8|)ڥl\X~19״l˵yo׻M>+ #9X:x7S6fx=]iOW:Ǟca\aOqsL|Kgmi]oq. ǪrbԴڜi:/=cł4ִso^%sFCSQ6rX ߷܋v[ _,:>*3<\\C8zf!AS ܌7w4ݩ# =_:x>P x [sB[1%P:GOWscO$`O$pݎq%z\^~]:+1pV'z:ƔXP;G}؃mbnˀ73 5oF]Y v>NynpkwnĨu9^WƔVR(nxOcIa,IhxOJi=J峹J՝kwB\U:6C٘7䳋?ƒ4>X}{+ioo{*c]*+wc^xR6a^V_ }SHy ƒr|^\-Gӊ[ST W 3 z1qU_,F٘R. /78E{*XR.SǒrW:; |5:ҲWj[>Yb.[NyZ*u=}HWf>cJ\&@OV sC=)ߕh81{?+MK sxVdz|1bFf-z'_%dn9A/"5:r/Y=feYcğxlL)܎27ԓ |vq>U`|<߀Z88 _m 0gP٘R,6Wk)N!s*6bn'37M 8ƕ:~neِzM>Yk] #1o_F`ϊݕ)(W0k0T6 cIͽԠW>qxˉq]k>#_P6T4eU[& j y"Q@uB1"s7DǧR Uy|P*|++5/{ ]zw{,0^o FolL>EQR3 0TZP*]hnf,7Ϳ>zFo /sxc~3-Y٘RXP!s[ܞ>T@͛/x^\ƼRףƜ? XƔ{Q>6TcIe1TV&$=T~#įܿl N?yY`ӆ:fq`)ł? N3[ ۘCߩ1jtuc^ߛntxދk 0u׀ ecJeԍ/2U˙::Sy=sC={}l}քf:|S罸f4n8FQ}<(S4͢} R#pADncIMz,2$ixnjx^ߛc}Fy/9&W/'dzdecJ;cA#27>XRe0Ty ƕ*|.c{e2mx:<ֺM836#;B٘RƌV pΛT I4_K zFǯZl<~ó y*ƩY1X*z/EƁ1}XRusC\K /G~i_nJgA٘Rk֏2![q *אKt4\Cb\5!|n3/=7co:ߌ-f+1Xl6hi[ȵƒk%asG{WBC`Yp95u; {)SB62+71;Ix'sCr4OR>E<{nV8u{\5iecJ;w6z17paq%dh+V 9VM%<,/~V(4 jAVmE(ˋ #=oh'"ɋ\ozou*"7)ˋ<o}z_󼍠`וE~k=oSh8_,NY^4M#o4엳Z,*)K𶠷E=oo2XSjXdϋkGsvKKڳUϋKsޟhT{MY^=[RmT /wUoyBHVwz3ey>ޮN=u'R}T^'wq_cR]K7z~а`TMY^jFE Y ,/5z;AisϬaKRc!C]ycIeRׯoyޑYy(?:xGқy#7gkخ,/51:ύq5`ύqcGoN&8nԜ,/5w"x4ߘ2Xj>,/57Aw4~eM1Xj,/5O;)֪yBmtVEeyީ3YKR2xg{ eg5Xjݨ,/^w6xypmzWY^j;޽w4g]`ڧ,/]y[{E_d+eyI"zyދK ^[H 4/,(K:_{4\f]a,/ځκ`,/{%<5] 6k^ Y7,W/{=7Auu_ o+K5DV{ 4ˉo3XjoS:5%iyo0X4V:O{;/{;?kRey=w5XV:yVAY,u++K]^ 4'RW}$^y8,u,/uo>y^:,uN${~Do|%SK]]' . zx@Qey?"o=nwky2zyhؿghԛ,//ߋ] el{FY^rz+]ͬ zz-R֯y_4XS軁#4_eԟ,/-zooCGRVeyo}],SkeSE՜O>2X)KY:ch_g}j4,/ 1c=/z, )K]A h.eWKeyi _л~ d4XWY^kzOxBY, Ja xyv𼫂 4xWћy0X.P>y7~6X,/ u}^>3XҨDFw_yލwkeyiC7 K"eyi^>ClnFo7XVƃF(ϻ2XVûޫ /7k}ơaO,KEu77 dE Pu )zSYI<`Q(ˋz)yCx,/*{Yа1XTo&΅o|Ҧ\zlh,m&)Kͦw 6w+K{yދa`i󱲼 EB7`i,/m4my@G|ҶE_B/įfUK[ 䥭|_coZW ~yovѻ K۝Ү 7Fv=_a`iWGY^_A7cۈ<аe;,/;{Gm. 2{ }=Rz~?~/4oGO^~yo!C%xIZah1X:+K]ׯB7AGQz_C7Eey_x'4O,~V}*vyo9 ey^2 ^/_M KG䥣9k΋( H|=y_>~`#/BxcK'_@7 N)K-Fo}, hxߌ_а`R/zo@76ey;}h?4X:z>&xb]#hbğ,w+K:~y4BIҥt/ߍ2~ K*x?+hctEY^WzT+7KK+ſ,])KW}6v,]uă='ey M6K3L+7hat}UY^ozFBc5Ku77XUTnOYKߧl nO@<^oϻn1X-Rn»^=Vhlgt{LY^Vz?ۡNMccwACot؈z+v,%ct{~pey~{ W)K=@1X,/(4=ftߠ,/{4yCcGUey'iGoey1ޓ.,'>kX,/=[J>~W#H3Xz<,/=t/y^Lo$y3${Vo㠲5x{zהDh҆KO\SKO\SU) ox{w)1,}[*K_1zFb<4 5KkOm7 veyYz2%аML2X,/}7Io Tey{ɑ_U; KPY^ w޳Lh&f,F+K?#~Ń&xgOvz_Q ~/+KO^Pb!4 ~?(K=. ~_F9y 41XsLx/{X eK^'+ *KUаM\cGK^o*z{k_oWX?'sh2o2X`L^ {Kx67C7q2` fz{+4,uxo=ϛ ĝˀexsEL ˀm2*wEށ;E{a`XWY^z}ax`,/^>M6 z>D$}E7X.W?=cаMI,&44,(ˠ>Mw,4,.SAzaXn zNY^ ߗax`/Z~{ AE 𣏕wp 4K2Xg(!AOh&6XUOz硉C72Jey)׿ `}MyxH| ߔe1xsFh&V,CeyO"3h&0XtP!Ix?w_,Cf+ݧ|IߧWk }߃?zd@cUː/ex龃g =]P~yGe'&yA>GoFY^br^r 0Xb2 C`@cS2iޙ44=c ,/j= _,4*p}^;iаM7X"/łd,/ccgIаMN1XƴR1qxwMr*4 13eRxw+9Y˘Ge $lh&,cЇ11%w4˘2 ;] ض2k$ E_dŚE>y/f)Ǖe߱{޿@7`2h&0X|0xw/y%4W,+˸g1ka`w^{=47,V*˸r}&h&jۯ,/f[YN|2 /Iͫw,(rxosNh&,W/$$o^e?ejxw }аM>`ߪ,/*=аM>lL,/2 ޽ߠa|`P o$ ˄eKryJ hV?eLx[Y^&w?f3˄eyד;_O> 2e^O>K^=K> a2q!;ѻǘ\ ˔e.| /(C72Gey{8oA7/eq"^YcduWiro?4.47X(K֝ro 4,Y+K{row+14,Y_(KVx7s\ Keyq~ WK\/qw,/߸>R[%~9q\g9;xW?h,`,/"x7~6X⧕%^Mt@c DeyÍyߡKbeyI</&𼫡Z%񤲼$V=:hl`I,/rofHr#4l$Ӕ%/& MV%o.x79nFo7X%y;;'w@c]KeyI/&o@Y^ߤ>p5X%U^MyI TceyI Ahl[dZ 7݇Q%ĺߔwC#>nt]L='O@I|`IVixwm)hl[jL,/:o%@csˤ~2IIT T9e52XjmTyh*,^SI?硩JаMU1X&QIg޻аM2L/N M6q e@ey<^}G.UEKe2zNzTmh,[ɟ{שzаM50X&,/{שаM56X&+˔rF 4S )-exxww?6 eTeyr ;j Tkem2-xwʇWAC`򑲼LYwmR˔25 ^*#4S Քe>'wNvo2U]S/݃S= ({ߩz^k,S,/S߇zR}aoLRY^zRadL=,/Ӫ{,'jLk,/F&zaмJ<`,/9sr4S4}N 7Ӽoj4Sc iii{V;?Vsaoj.bxww_% Be2MxsK] ԅˌexw/5u4S,3v*r̆Rh,3)rL=h/7XferL+E|2Qey9;FJjh5Xf~,/35ga`/ya`^Y^fY}_a`5SY^f-gySA7czDY^fw@7u2K7 NJgji1,xޥw^P^h,`AY^f'{Aaz`=[Y^f /ξ> #eٟzGaz`BY^fog{oIevAo9^oz  9˜r, 4S,s26xwUj4/,sW9s/B_2X|,/s 9*az`sDY^ևz^o enKey;^=K ? eMrܻ<¢a2w}^} +4S,s)n`ݩow|er|+esr|='e2Oxw"34Ŀ,(Kv/f{L"? z=^\k }}] ,w*Kro/n2X?Ul=7۟G%[ϣply]s 4X:xw.Sj49˂eyY:eJ@x}eyY^]}<7XlW߅hl{`Y,/ {"hl{`Y8BY^7.G1e^{%~^]=Lquq[/!vD$c>|c82spÉ/uwא7qOӥ~7dNDMeR0],ݽaMܡ,gӥdSUew)Ktip)J uٻ1WY\LydmUҠn0]D:pAx)Kׂ;dm஫$7P`36pSM$aM`4U߆*7S8. oG߆:p"o,  Kör۰˖S4L"oCD`4\, }'aMUH7$<쿉ҨJ0]݆,.5D#ei@0]DFy1<쿉ҨS0]ůk S(~W"o#w<DKei9.6v7 4W6ǫ6"S 6v"&,{ӥrݟxDgei<..q6v'D7eiC]ğ]JM`wx)Ks;~dmvٞ&^P&`4,MܵD/x+tir6eei!A&{+%,Mӥi%dm~'.:<쿉`4 Yk7aM,M KgxĻ`4Y{,MKӝrݏob4=Lf o3w?Rb<쿉`4{Y B,͚ӥY_d1ǘ OlP0]-Bf(xٚ`461&>Qy dmI| osei~w0]&mob,<쿉/9/ui>Yg+x(KWdmA%71NY/S)wO`{x'(S婛Z. S5.; 3婵tism9393w"o N̆\eip0]Z[c J,Jeya0],OpUX],O ӿ#YL:eyzU0]Z,-ݳQYZK"oKdb<(K|0]ZvEߖ]v+<ەe`Y[%Rrt3O_p0]ZY[{{OYZ+."o.U`zY[AHei54."o%.{_T`<qQYq< u-&c\AYLgFg~tٓaMFOtyf#>~!Y̟ti]Y[_aM,KGw+YҺA0]ZBs <ɳ`^,59&U&r{S\]Yjrۦ˞O _,mӥ@dm^o2(Kf6YTY,Kr={67x+KZdm~6y<ɫ-ti[Y6s٫aM]Y6K[|$m>S?eiv>utJ^OM?`ޞZ䛔Yti ˺&oQv`CwNru&,НK;$\Lք7yC.𙒬ɬLIoNeidm =`Y]^x+K`,v8,٩.N`<YuM$;3UY=LNGI;~otB?. o.<略S`t,&_7tLNӑ>4Ki~0]:Gǹ&_U9 o]5xo(Kkҹ,%3OY: Kr]J$;yP0]:OFn{|de<7.#owtrJ_+j<KZ +Շ&?R.T'Gót=#.],]ݳt/.]F߮ynaM~,] K׏{tKx_+Kׯuvu/$7tLn{]r<ҭz0]݆,V X,KVr=O5#<VnmvsqTeSۗtI̺k}ɩOWnk=~_X,j&vwI9`to,o%cWe\0]F޼oX]YLK#뿋`{ =|OY ߥ#)FA^,= Kr]oO'P]dv1X],=ӥ\d%cwXLG.뿛幓 rm.۔ۃ\d}ߝ\`<7 YsۓWSWYW,=r}"Pgӥg_aeAߞxS]3>sQ_^:NYzN]zҊgk*oe׊<>˞o$eyR0]'>~k&Uߔ(r'S|<1.xywJ O]i%UT eU5.rr EҫN0]z B^h*Ӆ|L^ ̺RӃ|Lk hrxSW*ˋWǑE;aM],/6 ˋEaM],/~LW">9.D?aMݨ,kӥr]gHo_;L=#u s oaeKuy~d}ۓzTRY^奮r~0g"9,/ K!K^TI伲49./笠}TT\../_,/PQxSSo ew_}6<쿩'ty}dk3~8Uԓ`sۯoyr7Tceyotyad}4SMYEn,Jod}]M5g-/.LAW SOj, +GU3(˫j-<쿩jݖY_maM=, ˫ÑUN(˫r~0Tweyuc0]^Y_sϲH(SVkJ=嵛QǸ~D]^Y_s^7GY^".ş?_7r'*<쿩ו+.<쿩7FtyMd}I<쿩ty}0ށ7>H]ި,oW T7w nזO Q7L7")݃F9sp8<쿩F98YpK}oj7.}/F߾YaaMQKo_ԧ7~o|L,}aMU#wu1&+e&.o,oS_SY-.oރ,ou;xS+˛`3p?goey3>gOYti&c'ey`ى̺g~dey@0]],))X,Kd瞹ߙү~0] ,xjg+K17sK,F.o )J V`U YrX],o=L#["x.Q^[-Rx.Wf߷9 xRs䛑mwjxQ 7Ӆ^Yގo%Bv-uj<=ț/d}=![tyBd}JUty',<;[Yy"..,w?GYLw&#;^xWwq뿇q|#{g0{G0]ލ$.y a.,]Sd}mL>^YLw,]}xtyrd}z= ?^]d}Cxty]d}]oOo7<.,ӧ,-K_ίg3\EYq2owL$9IitUxՔ?>CKrݿ>B0]oFnoBe'..AFivۉ/7} 6.@n'ߔe@` w;}<+eνˀr;_U䫕e` <YknkYKVY{w_%}Nr;'2$>Nwt <5ȏ)ː2 d2eO ?,C~ːmr;~t]e?.,{O,_LCzhz(uy N77TY0. fRF.C$Cq<24>N 'wh˶& }4.C_Dߡy6"Soe$d~3tGe:'.C#0wUYxӝeX` da|2t7eI25]aM?,úeFak{~AYkPaw^o L5w.䗕etw;+%,e dLo Lːw]R2 pIH o]eqA0]F ,#s=w.=`eJ0]F,#7CaMU32b/t߳Ӆe{Ku"~ LAe`||?~He8L{#QxQb\ߏݹh,<쿙r1E'jp~9LːOTO'!{LOGO5LEx3*'SAdC3a͜,LOoEO}AfTO ˧O <쿙[UO*s<쿙sSg!gj WW*ۑ3ܭكt3~~(s!<쿙,LϦ gޏf.Us \Y>LAN3s<쿙`|6~a]Y>L Yka|G0]ƞ,c$SYƞL)d~*s<7)er;]o oe;<.c#XwJVx3QŅr)SUt̺sfT/pO]Ypߧd7s|1.._C/˺fW/ ˗B/s3S_e`|ss.e2>woe ^f>RC0di",? r;~~Zg2~[0]&TG u2BY&\L %r;o2~0]&g'7fS 2d{g,6;;r?+Qr^#3L+ʐ(_函N*Nt63S1,eb-d̀,eP0]&,V_;GY&Lw _e`x ~G,<W ˏ d}OYEt1Vbx.UnYA^,?tOfV(Or>Y ߵsti笃e)Sqg7cwߍ\ߟxnSs-qGSY~Q.NDID2L:-.rr;m3SWY& ˤr;}O-eu0]&N{XY&瓥LY'{ǔeraE2fS 2GdJ([ 2GedQdO7{L#.SNG)E.S3r;=;+{.o6,3^ ˌϑw{c6DrFYfˌr;mZYx&2cs0]fVDߙ{ll<;.3oFߙn}etwfPef?dk3랍oIe9$.3Fߙzl<2sv0]f@ߙ9rنf+̃tU Yg]MYEn,. ˬ{w)2+LY-w!4.fl2ejSY~A.@7ncKY~L٧"lf(t}#v@f_7̾#. llf_W͂2 d=e߀7Lw72{f0]fF;fSG2d T9WeCr;'ﲃ !2L9]w΋.>raUVd]eπg",XL{w(w<(²tYw{fu*<쿹jʲ`,/.t;ʲ0Lw\ xs*žtY8̺a"xs+σ7d]e/77eY". ",ePELEW#]JxVVE7ecrr|,jLE/#]:xs+ˢw{d] ʲhj0]mBEnVEeqUd]ϟ<쿹[etY|7.v o,Ne1Ur.v*aݡ,qB],#WL٫ʐR?eJdk1_^eY9.KND%;}P%e F%k7,Aנ.K$K{axs eY'&A%\6 o.,K ˒r})˒itYYI.o,Ke)Οs.uϹxjS8.KSr}<,_0]vEߥ 'aU}t,.u}垄7W_YNrm-s a5R|d]vǹ*˲˃,~]_fRekՌ Y~<쿹ʲ`,YϹV$Vel.s_SNY r?]ΟsauT8.oGܳ:+鲼).wu7MY va]u7,,.E)^P˃">qz,+c]/r]6eeYqg0]V4Cm]x_S鲢?pʽoLw{PMxso)ˊtYYWsٷaͽ,+ee|w?ֽonuAߕnon, ߕw<쿹ʲ2BFqu0xG(Jt:2>'Ƭ?' Oʲ2>',e r/onLU!*w_Pn <쿹OeխtYUYWWOa},eU*;ܗʲ*K,WQUӃj'r 8eYu(.TG?}}L,\L?F?}FQY(nrL 뿓3'rw2<*dr3e<g(gJ. j̈́/ʲ`YWϔX,ϔ;swyXMYVy9>Nr'3@YV33e!<ȋeuR˚r]-2eYsz0]RY3k*xV5*ȮbmZskNYּL5"[Xݨ,k&eVd]e7cwL!ګ\v+<ەetYEߵx֒w)'鲶}ewc/eY7.kDߵ>xS6>qcuuǺCX=,c!rf(<쿨21˺\0]ֽ,)˺es`_e'*˺tYu@c\AYӑw'02<|lx:.!wKBxAY6 ˆra^ oRek0]6Gߍl\Y6 FWJY6⼎l_+7jxWku5y(n?eq0]6.Bߍ{$SY6 &|>C7S|lg(u/dvaߢ, &o7lu4 Y7U5a߮, ˦d]oNeٴ9.OF;]QgesZqٿV_Y6ǯսrY}*NtVnC%?,! d'aͧe`l9YaixYeR5.[nG-<67_P-8.[Z#|ʲk0]A-8aV-edݲe7_GYlֳw|]x)֋ ̺s|}xz*V3Pw|#xMek`l,[u|Sx͕egtٺYq)xO+utVYL̷7lLm 6w}#|[eVLmwە,e d6e;3IYL'"vw,aʲ`l,TaPe{d/ʲM0]E _T탂=w o%e&E_UerdY ʲtف>wL$Ser=<<(ˎt1 YwX]xeǜ`,,;e,;`''_Yv瓃k5YZ 7?\YvƯP;roe9,.;'#Nw=6!?U䏕e`:YwS<.G]YRa,2tYwg濄7z>.>@]~7S]ck5rn,ew|lw?ODe'oGGx,sMw>%?Lkʐ(t''1ߓS1,Tr|w?̀,ef nAxQ?rF _˂gO 뿿+˟{7r+d˔_Eg`r?] ߥg| Yt2xjW(˟W܏W܏VoE߿X],Ls~AYב _^FxnVF对r8۔寥tpǟlNel'߂,{r]XSYL=w2<5{eO`쉯Qp_O-e_G,{)X=,{e>d[ec=..{ϔBx )^|PeٓfP ʲ`}Ykׅa-,{_/wǦP߂(BOm)ʲezh}N.4eهJ]>w\8ʲe_d6b3a-,Ze{ro˞ oL}w{C\x )˾tw (TPCYWwm.{<쿅etُQwO%ʲ]_.2eVAT(pUQr*d=cS;<쿅t9sa-CYx YpLM,fd=~/p c&+l|</]_SrTvI0=:8dKqa-|W1V1_~P_ȎgNOqqq_Ȭ ?cwrt\~&OCgfu)X[0=:n?ߨ'03rQˑάn0 Qӣr#;.;yQ&ܻa=߻+<+GӣryP9*ǖ-FWuEX]n0=:Nd1]X ӣ[!Yw}뿫;ӣ?@vyxQLW0WkB^Jٵxz7)G'LN ̺kXݪ`0=:!~63_mXݡVq?ƬG;[9:!G;ˑɬۥ脍Ȗ XݯX=X ٽ̺s<)G'>LNlf3|T9:{0=:1~_fֿ3e1&d1v|a-W0=*^2oTR=by߂Q,'0˞od<`$f], <ŊQyAQy¬;>OXI9*32Ȗ>x G'-F*k\dk0XQt0= ًuePߔ Q/Ywx<+ ?ӣ .{%oVN&]xrt`z$,+#qe[ >˨Gr f}T ʑL 1?k){m]ʑ G2Z̺ge^H>Gs̺s}Pԣ(rU[|H9N G >ȬR|bB9nGν3νIxi(¹7(d1ɬ;,fa-攣ԣ(~2*oEkUGc{7% ?U%Ȗ0*@~\9x0= c=<źQ.0d`=s$rs0=:=،YS-a-TNAO̺pIn2$3b֟3rtJ|PGl7:b{xSGބl{f;+G G6BYf[lxݔS G ] a->3t'/D;lOx/(GG@tUa-V*L*=l/f=>&UӣJì +%Uz1U+̺ `ux}JQȾάΫ&<ŷJ{ig![Ne߆rtڅ贇}Y{(Gi{+GWȬ~8P)-a=ۡ8 .i{!;4{ۦGӃrttHG2~8 hz7Ŭ{\q 1W3rtF|I;Lf}Ǚ ߹qǙMnqyXM9:ck0=:3>^3j>< 3|r|lϬ?/gyrtf|l_H_j <)GgƯ.auq9<W*GgN Ggǫ*xVΌWzTJUocwrT`zT%\ì\ߍQop=7u&xnQ GUc&f}+<ە*}+9ʬZ.J7XGgנJYnx_MAf_}Y5=W. GgM@v?!xQΚLځ!f3BGaũRYՐ-FgdJ[RN9:`ztvf̺{K/S2 GgBxfw%17= ̺BDsه-Fa-9U9:|0=::d+26%a-9]9:`ztN3d+1'SRߒ3sӣs [Yw_nIxKVL *̺眔oɹ9+Q-FU}%AU=-Uj̺u%(GUjdg]*_b GUG#{!;a-T9u0=ًuנJoQȖsw%W[rrtn`zt^>jxK`0=:=W3~+ZxKO9:`ztde]+*G~L]̺F "ߤ-U;oT].ߒ[j5Qٌ oj`zT %2>Kj[rrT ԣj8G*ɬ;G*ߒ;j8GUۄ̺SJ_K-F][rrtul#}*G5G<%Srt>>Ĭ$oIJ9:om0=![k%ixKQQZȦuߵa-)(G G;"cJ<U>UyNIYwS<%8ϡU ǘ=겏[RG9~,[Rw.<]aG琭ˬ 7TίLl}fN<%Mӣ ۈYw)<%͕ӣ-F5ܦ)xKVjLj܂S̺%-a-yF9qw0=ٖ̺'KZ[V9)̺grT`zTc=uc,`r'Ʈ`ztBI7 #wU.@_]G3u\<%= ӣ W&U=AeMG7D (HC NE"a9g JhX ]]ê[L{S%Ls[ݓ̬ۥ hL;~o(e) .Cv{ӊF[4VYL #[ p[4AY* KȎcU4ߢR`TXDf6h <ӔKtSu-Mg7yT..t+; ߢ9R1yg ;Ywo^\x)K^t ٹ̾a-Z,ӥbtNϬ?< obeSJu e-Jp-h?%DǍ%2xV(K]]Ƭ$?,_0]sȮd}ujxN*Kx!.CdW3>x)K<.\lWqoeB0]iK̺d6[YYLk!YE[a-zYYLk Yh+Xݮ,5qfqc<w)5qTJQ,J%wTnr>{1~]Y*=LJ1v/<+K9o0xRJQw>@U0Uc-e]RZdKR}7eXTLmf<)K|t<#.pX}WY*/ Kgmރe|4.Ct+Uv 䏔9tr#2>7cxR*uR%̺W_Ty(.U& WfWEcse2;.Uv"<R*ѹ ~{XFYLk\swrmt-9:^}ˬ?^}O!_rmt<u֢iF\;).׾̺BXEY}-.~̺E ߔr]%dKr{'Vo4e`\.M4dtxce:tIrWәuǫa,xE]ñ=;fݱ=v6<쿱s:۩uz;xzR +̺c'K\,.?uoBew0]쟘u.7v\$.E"fB.7ge`T=T=e/7vT}0]VGrfU)Kzt W1c7VQY>L-Ϭ{"H,UWӥf*VR`T/_LXUe`Pu ƪ) rC*VrC`0s[aݪ,7 8na֝c5aVp.7At+7 Ձ7VOYn`:̺c>< 6tuXYn|:.7BuXxc͔ƍt$Mek,7~Lj#[jnko6eV>.nGUbk,:ӥdogݿkoNe62.^D^]+KWRsdbvrGeC0]_lWc³|TLcu/XTɃY<쿱TLk1.7V[Rd̺ ea唥?rӕȖ&~hXgeJ0]n bf8auQ M%>8}ǔti=0es]YnLN!ەz(M_wt+7z+`Or+d{2뾯<X?e}0]nlf8ƞRϬ{ 6@e`|̞tAƆ(At+c%e?ar%t%*a__ x]_ '?pf뱱Q(-rRdG1v1+-/>YlolKuq!_cM76UYj\Ldf4xc3F;8< i̺g̈́76[YjL Ko lO93R#:!Ykb R`܊NVb a-R[˭w!:ca=,VX-7\Yn r{]olܺ3.~,rc[,~L!o͊.؋R3ӥ&oߚDR^,5K蚁ߚa<țftͰYknrƶ*Ktt^7MYj~LZDZ;cSYj]LZMά{> {V`,WLZKXݧ,ӥ1d$'t}v;OԾ .k#omͱnLڝ{?%xUOӥ,dv"cX=,ӥ>d}+K#tA><O*K~@,u!<?Q:uR',uoN37ep0]L@ا,ufӥvd}/ξ` Yω}߯Otgd># <,u Kݖr[}S;x,uKr[w ?)KtY=NX]LkQ|R7zrk_e^o{0~<3^`TX ^R/LzÑ{M5~w#< et_Y溜_vRy0]#on.{ <ɗ)Kt?Y77~ԟL;~ƯVRkd^珗7^AYL`6p6^54h, ڻl%xUA`4, ů7~4L J I`U0]ŹmzY<7)K28 ݹ;~3<n0zNr?'o7^KYF[]7 ^x]ei+. g"oCY4z(KEti6t[xCx`4Yqƛ*KӂҨ6rěBYLFw#یYwt%<ƭQ,."oQ.{<6ht0]@F~x[xw(KtitY}w}LF8Ź-tx{x(K!Gԥ&lGx㝔q0] r[oe)Lir["xʑR .{нoO)e)<LнO*Koti| 69x*Kti|/6Nlgx+Kt0]Buxx*K1ti>awSԥߐG.`4),M {)Kdm64#U&ti2Yt~ƟT&d69OZY Kdm+Ks\u.>PeiNG]9oSwo|43ui=7m#aVsc$#dm^+'I,M KK{!>,y4Lfw o3O7>EYLfc>Txӕٌ`496ǜg)K3odm~Ά7>WYLq|eiK]Gױ6ױ a?,ͣrܽ_@ei".͏#Yw?a9xJ˔`#p#ŗ_,-KZZt<"]E.Ax/(KtiY[{/IYZL?#oK7*K˲timݛaoQѹ{/t3 |+Ҳ$.--qc<;etFY[f|'<w+Kӥյr߽ҪF0]Z=,F,<PV}jrcZLV!o+9X=,> KwwMx,߅7ɷ#ok>lx(Kti=Y[hg7L֯ ok{`><?Tۢ>9:Nr{?Nr[t<<TK6'x,m뫟QMԻC,m^2+<쿨KatiY۸eaM,mvӥ ۸d⌂25 ȿS68NR=4z=㳕m`ŵw߶;q< Q.m#o.{<쿉+Kۅti{YۺR&,mOӥyrE`k,ܮ-q1<쿉Kti߅B2x+K;.Pvr䫔`Y۹>K\ O Wvr{<&*rtwshxCKwo@ <쿉rgr{{7q=<쿉rgdfDue`ܙC;M&nQ;gNYىk*˝r{.D-x(˝ ]#]D]xtd+ aM4Rtk ^Nh,w ]G-dֽh oQ0]5R߻5R<쿉Vr7ݸFJp{FJ7q܍k$rpd۽hONYLw udw)r{?4q7<쿉`,ݽĉ{aMܫ,ӥ}YۻaMܯ,ӥdm"<쿉..F3qxIeiA0]:,.p<쿉t0.!o.g XY:L2H<O !e0(.G]ax(KMt',d.T@{l7x+=7>oܓ =‰^&(=sr~d; os4.OGߎ:O3<@Y:L{!4<ȃc`t,Aߎu`x%q|0]:nBߎ\v(<쿉qw0]:~,&F)Krr{nhxcroGd}>Rb<쿉 ro*.C{n11dewf0]}Y}e obt'KuFdKaM,Ur{_]obd0][,d+9I~^Y[L$jxN*}qT+ 8<쿉urt|{/ؠ,?L'!nob?7.F&xYY7.Eܾ; <+wvb<w)@wawAZWwa7y+}ec<7.,EXݯ,EeRTY8X=,EMR Yax,ERu |xQkM~Yw7$c}Lrs˔8w%vU0]bm7MO9LHd7K|O ,)tmAߘ{>1<O)K`ľBߘ.Wx~,YgX\Y5O"oC_c+ew K|61x~,%tD1)Kx0] oBB%qQ0]M7NO3%6.o7~/ʒ?7#ob뿿)KbO0]? o}wiʒ,K‚dAi6龫"y:<ɲʒL#rt{aM,tI.Dߤ{:y6 KBdͺR&<ʒ:.YCf94Yd=eJ]ӑ7^Oևg>d%B߬;/$XY8/P'd LG<ɄY;נ,Kr}^xNSwӥ@d޷JvtLθ~Nr]?'7CY:t Yr&{,L"C\<~P`<ro)ey(O>aMT/r< xC3pta+)(Sc] 9:֕0u1,GǺ䗑a9Q&(ïy,]w,9ort'C.}dxSK`tY,]g',]6ӥ `.&g,]#u9#?,Dus5?kyey$G^,{ԓ aM.RG呏I.7vf%wcwt}<.]#oWwjUx,]Wӥr3}߃ d>?$tLn#o7~Yokr۵%g>Wey`(,=YTʩ2Cңp͒: ңY0]zt/,Hqý_* oLed0]z,Bn+: 9cu0]z,=w7΅7u[0]zӥ:]|xSPtԥ'){F.P8nP~ԅl'_,=ӥ6dSM]ne`q#o/wH ҫr7u-.z#oA.[Te58. [YYQ^[dV7UEYz'.#oow?RZxS+Kztvms|L o.[ S䛔`>,{aMPӥrǽ_T-esU0]笠~6<쿩},}z(KtY{R aM*Kt}d1<쿩דԥ/'Suדfe[(K_\ORL5c]OZcZYz],}{"aMQd˶7u0.p}J one+ү sےjoewo0]MB~TGxS`ۇ,纤7;L o`r串(."o_H% 䔲oLO#o=54<쿩L{07L!oYVIwM <쿩G:ty >>7 <쿩nd`<9Y\aM=,O.˓5Ok{)˓5C.OYrzӌWY<.OFߧ~T:婑r <쿩)tyj+>9I 75XYL~Av`iv{,5Pepf0]@3oSaMP23p oj x".лSp;5$y @.!Yde'ty:znpnL75EYqߧqc*<쿩ttܘJ,OTS3aMRurlxSsmtySd}ڽz|eytXYGj<쿩getF߁;RH^, 蹱Yx2e=7#@߁nZoj k0]],! jeT>.:! J5^PA` ,x^7 LA{w\zxSe[t|v+oj }0]C]v+<ɯ(t YSYDޡ,edewcw L#`sj<*ூ2z#2$:C9ǜ&W!1Tp[; x,%Q9An,%=XPYJZӥad-qIx~,%=R2̺ٓGJ}߿*Kɢ`,%uL}MXBYJ~ Ыw'?%<'Peh[dI} )2S0]Gߡn'<WÂ2t u~2tm0],Csٟ }?.CEag_evv0]],~ bV3.âs 9%]2 2lHaAac]2u ȿSa2yd`mgc| La8οsaM wi>e2deoO2a0]'w?6}<鋔ex` ,g¤/7} Li> 2} +e*eM0]F8w @.,#p L]F4@-]8] f:2r`0]F.Dߑt]xe`<,#?t#ey".#FQt!<&2l0]FUBYY+˨2nd>/t+e ˨r;ʽϞn ove52.#(6$eKtuYGsx仔eGt}te}^0]F߀,='{aM߫,ke4eiGsY'x+\։\,WaMǔe`^,{8<餲L"h]<録<.cG1}tbesY0]:6e]Ǧu,uq27L1 FQx]e̲`9,cl7xӏ+˘ct u_7SYƞLUwlMoL XY%+`EgOs;u'Pe+r;}Qix)׃26:q;֟.QTqw\PxÕe\`YǹDz ߷eRԻKu|Nv復߆_eEt\Y'ׁG{LY&Gw9}*t<Y']j=xʑ?PK2yNv;?'?RG2?r;~ S2wtr=Nq OeJ`LUU>2%V]p;_|߯eJty Nq{?Ly5.S>G)3Cc;eC0]^,Sw'/e25NGx,S#/Nuk뿿(Ԓ`L],S _x,S7ejtTw)7sLŵ u‚hBe^ɜoL&.!4w\wfRie Blx3*442Ns煌$,p^.p^p;͝2'KLyLY_7sLLwze/7sLOepd>+s)<쿙?+It Y\oJe;.ӿG=Uf)߂2fgkLyx3eͨˌ.r;7 $WR2cYwOQ2<%ke`؋,3aTUoeƿw f)32d^T7s̬L1daoVe9.3g LԄ7S[Yf>Lwf,3eir;˽|rCeu^0]f݄,V+E2~0]f%wۥfi,ˬr;3aʹTY2:d'̴7s̾5.GnL[e qr;}U<쿙;e`ތ, aʹW{2Sdtg;g0]\,s&=s/<)˜2 qݑLiL9]wN_I(˜~tY3Ix3ie:.sB6ɬ{o17S9enuK)7YYL1߹<쿙.27:3SLtO,Lsf*3Ӄ6d}2a Qg3"3uLIAx,RtY4Y3ɒTES(.-x,d]_ <*ˢ5R]_,뱙cX=,+eq+d]^ͼ eq`,,gd>IeY<:.#bzl#x~,_ r#=@ߔetYrJKwDf>weYrA0]B%]sx~,KeIY2_ckeY%.KoOeY]|Cޅ,K9,9L%5!K5, Kuy>vǙc? ty=>s_OUY9s96ٲfTLxNf]ꞓٳa͞,K.Kk R1ɞ o;۬Lr eY]0]V^lJwf%<ƭee`~]o7FYVF JwOB-<;e`<,+k;aޭ,+er}E=<{eՅtYYWavRUm鲪rg7LUkw/[O9r\YVm ˪U(O eU{T9 o6,G4>^a>,gXd}g oaey~F0]߃,ϻU]a>,Acf)e5EvעfPո."jZn<^ʲ_0]V/F>lox*5tY}YW%7>L5g"?SfV5 ,kZ@xeM`@f!f*˚tYY׸a͎P5Cd]͎7;ZY|L Zw]v H];Zw흝ovŵ7uYYnq٩f+ڭtY]G3aRT* dg,/P:xhd}7]oYeyaZ0]^@rtE $/Q EvQiEU)!/S ˋ/ߣfW*ˋrrEXov=7V#}x/(ˋ鲮,si}KʲtYYanTuwepd]In7EYM ˺rnng>eY+.Durm,"Pu?K뿻Cߗ=Xݫ,/uKѵ/k]F~Y_r#;ty)]w]8ʲ>]8H,wf߄ʲn0]wg߁g;LQwGM>,}n})w G weCԻ'WG 'lL idO2> <, ˆYra 뿟)ˆt]s__(ˆ蚿Trѽ(s1z9EVY6Fw"Ox~,stG?cGe~ Gg7OXYY6F!F;cʲ`l,WxqilݿFMn+ote &\ΝQPawʲ lBΝݹ31>[Y6wSMw?\xs,Kw{ w<쿹+ tY7Mz,;esXq?VHY6Gw{='w1<쿹Ke`l+nve.Weerr䫔eK˖ېwK@.,[ ˖wpo.(˖tٲ YA]olL-#ٳ*S-eyr}vGzxs7(K2VwolmL"VYaݢ,[ekXq?V5)$TcU9nuojӌ\GYLGߗ=깺+5rryk,/G?oRd}},.E4d5Q_ ˟ [Ȭ{_2\seytyד9_qדZ)+.#+\5<쿹ەty;+w$SWл+_ +;Arw%ߥ,+.ns \eV-.r]7wluu6Ytu7wl[Lmqm8<쿹ll~^7o.,ۣ7NYg\6o.,۳t>Y/p,<ʲ}a0]lYw?aAxJ)r2}#ʲtCϡ,;sqrݧoqe13.;pw=ou,u۹aQѱ t{ o7.;! .$<e`܌,;}YD,;eWr}gDn0<쿹eS0]vU@]Z47peمkQNdʍ77JYv=L]O#.*ˮQtٵYwUraMP];+z&+ˮ*ewydҹ)l'OSUdZ&Tt=YwsaQ3Ud}e, _w|xs ets+m[,{ 鲧7Ka-U=g-q[,{erbr+9I~^YLWoDWVsVY^LWrc.<쿹uj`:Y_uK6(˫Kr.fey`e{YY^Lw{> <+t7;KYFǍr.(Ө=L 4{)ו3Z-d}ͽ{&tyqd}I=CSty- ax,E}T7"X+.oD7}##X=,oL ˾rr}O8<U}e]r}re_Q0] D}u܇Gʲot0],^vُ{JYL}QOw)ʲ/)^wm3x~,F>#G99_c+e]|A,oe`oߒ~a/euR]\,4#[Y\Lѹ3<Qѹgdd=O$_x, ˁ蚟Ӕs P=ŧ[\VY^L{w,[r{)=s`\,ݽO||).?C߃Ó%QY~LC8s{sorrrA_o%r`,&YYMˡmr{퀊/Je9F0]},kW[\NYL"aa-,kpY{<ɕp`l`ֽ'R\rxq0]:::x*a\P7E7/ra-,o^L7"~߬,o ˛8sͧΏ^/ӈiy|} tyS}x ,GV9<~gt^~y<0w`kwǽϕ/?>\|vrY}x└,'8]Gnw G7t'B<\[9:2m/}LЉ,>Y8G_ȺRODo=-䱨Ey|1x NJB>ϱ>瓯/Wt>/ܞgC,ȑnry:=9y \\oqҟ9*<S!qi>8n4.Gl7[~Vyz>KƑ>_̢-GgӃ됣svnQcV֧Z?sUt9Vs:Hcscy<nؘSyy7y:i 4a: } iM9m'z^#OiM8 = YX‚>l/~,QX5c\6YO(ǧlI2qm֔f`v瀫7`.߅[yY({Keq i됲85-Gѯgy:-*;7^et^ܜN ~ָ`9w ?Zϕ<Ӄ/_KW~L[8\y3xy[ϱyfyzsyzpb(=TWP%JWt>+Mq4Cy:f<<=wt'{ ?+c]*vyGsy:-*> N9bo;y:'9ӿq=vbgbg,RVwp<\ ny\cY}p }..-;{#ϻn\yI=UЃ9V| ޘoy-s/&ߥ'[1/w v^?OE`>ߢ\-0;%_1\5pL.W9s]ʻ<<& wL.w!t>|hN~,OsZq.Xk>p-t[鷝__G+{.raʎs ym|%Owmwoa'dt㪬7Rjg;O˙hz+--3/G[^QQIJEiS6QфJSVVfhdVXD9Ϟ|?˵^k{}8T؋^=P2Ἇ\׿ f>Y38ScmTNw_K~=-RoTn Un UnwiMB3c 2õq`}̜%26yd>t D/w/{H^"ss$ro ZZ#<Fs;r9Ǚ~ ߑx6 K${Ǡ3g ڎLf#ӡ?Dq>\OAMJ5/G|εq|/'G ˵[o%Kh~ }Cs?:Nl'O"юw4\{s:kvu] Ykpu~ 5r†Chƺߵ}Gkv17w{o`\% w {n>@8fB.4vPl _">plpy-69s/qm~̑u9yoh] sU«MsΛZ4}pӏ1P|46Ü wgYb67{6Ct8st-tt\Ms禛s ^"L8-w,沊s)o: 6΁~^8sq6Bh~\pMÏk#6w#*^# ǣ;5͵qNs9y;.8(p"wp E8w <$dbl*;#^1Ts;uJl;%.ׁ37@/ε<ܷo$6f躠}NHxV#\t[:/'aϜ_tpp⊗o_ 4kqߡy^:4z]]w:\霞Ǽc\4/wqy6O/M+uk>q+sm_1y=DWLu{zˉ&Rxv; G|ﮍwhк4{ɏM~D֢ Νo|cw4p@ ^1Ls;sMg:tKCyЗ$&8k&1MpLb o#XWg6ߙ0C]]!M`I6tiO6YmE ЙmN@gM\K?kفdq.4XKѰaݤ*7%ls0I,t`muߙ#h/歓: մ[hV&࿦MF47' 3\y/k`q5i͹''a8a,4:J8oۈM;fkլ;еkc2}' g?ٸ/4{X3?7Xѿf?buN0悷N0bAxmlе8͔FA>%\8>'On+6/'6AxM#.rNw(ε}7N<;O35^8;i L$V?{iӨ t7A}'7{ }u,􍞾b_% L^]^1=/O:a3Y_ҡY_B`eo_t:M/kVz5] `ߨ18 (|p fMЙ­{&Gx%KDGbD ]8+g2gV Z KbZ;ikQ;i@c\D;1{9g(0g(0~Plo ~PngkwA Ov74\Ohi{ s־]"6˄^!1?8Mvq;s~ |l-:AGQ6{Zm/N7Zwb/Y,`\yY"ƿ }^~Μ8:Sxp9?Nf }9s?1 Bl*W ?/ZČqnaк\z ͜_zHť\^}kÅs:^l' O*|b>8Mw헼 #`ú0:Sxp1ЬY g]~]!6«~I8:i;?\Ɔ"db_V#.qf%shBA/Xo?w.b /B B,Y2YrɧM- \Ğ̜_4‹sϹ~,y~2Ӌ ~rk%^sƒ|NidN.g/̅$'MBrpmЋ/ε}vhz:C =z_xj59˵qIœ K!05ƒp֢kh5GYokN@c/]wjWAgskzrqMŦmp6߳ch]jV35s ڮY<׬P])ft?/6tvm4qs@Y~샮6m-l>}كcy0 c=Z[acȅΜrqMϝ^1Y"6Ҧg ߠ.9Txp@83]fE3g F8Ms=20t.fb]NWyTxp4Oc-2äuطS1 7;zI+ņߍL/~7Z5k4L*s~k#5AxpRmЫr>~#5C8X'Yb-t %$cf`.)н wxVu.^&}KUh|.p=V+f m BxpܭtmKΥ:t-y:/5|kM~1~ ~?z9?-tD\Gf}(39,#<_xp<6NѳI6Е«G9aO8ԇ_n!w#_CGMpWxqɵq~_#s.5s kwO$Oκ|!`]!uYb-ofrx4>Qobѓ="v E;{0Mkby] 6ų@rgē sQh3¹~XlJ '\8V6N&ʜiPp؜ky?|54Bw}psh>DxxļֵqX9}ݰg]*B/&uf]*bYYbS"T>uqt\_:COÆu9t u9<4C/@3^f?y%hIGֿz1 | ggbgLpp4s~p04s~iq|A8GA' O"G;yb^f$?{Xy4rhr-pm&<]8r-,!Yᙺ _F#ﮍnj .$Q=Bh_{  gMx ˠY/pYȻ+q3j߁b Q^kF{ 0{ %{ =+b4Nس|| Jl"G o'p_Fe6N3]q2si^}wgp}w@@Cg̵ͨ?c/t/qW{9Ǹ&skOlnM-[Cr)8s~Зs\"-yNt;\ZBwh1.}r\i`MM Wc?:U{˦F/k9zZ9C?7͵M3~ڋa)t|skVy9Ǹ&.Gl i6šuُ=y|?#ε{~>?@8~8§ O~,nk4q'I};lO/^*Z ~z'/6̹{Y#U^h' &ϡsw} cv.ƞ<s2fZ(p :Ui _"|p ,C ];/3!=fyM)ug} gʺ@T{

vO_䳳}!4syxyގ;v,yo_] T8{+|~g{salsX7XIJ&Lk HY'l1YsБ£;qc&W{uh?[c_g8Od)'UlEbc`1fӊ,Sda$%ѷԻ͒|~OmI:9%Qb{}\'$rm~Dŗ3ykfe1&!)ϤG-&LjLj+~z'NoĿf*~??|,jg&}(~vA5 O oʽ5%B ³g y@xpvL^?#vA?/k,b7YBBYx:^xDӄ_ < y;\I-^Rc%vHpgO3ogwoҙwRЁ\^U<,~?/>g2&S| ~垟@f =_. (|pEàٓ|‹ +|quȵqY?b|/5xF"`cVЗ)] FÃ~&2gig}Rsw#-B/n[3>_诖 vhQEw:asksby`ޢ[Ki魥B_㭥`Ͽ#3g?S׋9(~{~r~¡O~f_3Yl6kfwy EM]m} h?>;_I@xE—_*BO*S-6|6 3l]ma4_G*\ =\8 b0:Mx6:hQ"?6'f~% FZ +\KӝWCgp-5Rkȧ],~>?_ߑ̾|yOrDOrdO25$\CLm'F ?5$\ -yj3Rνp!t¹>넽}p14硣 "|8ѻ&Osm&t}6xF{>8^MN=zp>_*~2&G䊍}6Cgg mse-B8BuQbc/N~< 'Cs*AʜB/{p-ӓO` Zz|_|亠9͂~\3֠95w!fNgs?'~09s}']M)~V}sx~y3 M'<_݇{B}}vzCkNHx[ s]zNy3 k|fA~m=|fa~m8/6I'Yllngsfh>w۶A3v@mtpWvBW mN덂u@spksbwxy[Ks[Ksܻ{kinoo-!f[KȧG?'Y,s!?KϛgB?ܭ>|;_9*~[ mgd׹mtToA5ζeХ˄^.Bx*Ո[i̝CH`|f;ao4 7x؆ p>CJDM;Aly)}] 5:Kx6йbc{߆ܣe@~smN̼ oXaZ7ro-{맱=[K^ȧD,?Oo3!f 7%~?~IIi6'3DBw5){QOНG >\34ՂߠP"Kg -SWC[agv3̽ 糹kl3̺ ӡHxp- 3Rl\msyIhoor'`yz8@s\B'7_*R1ߥt[^Y!Ηʜμe΃.~9Ahkᗂ-НG O,!\xpsfgXtze>t i%yX%ξq*5|.οwO޵&Ql O*ε=Zy \SlMu;{4IPRѳ8ͪŘ{If[ks^qmR!o[SS2UoֿYb`Khz9Ǹf79U7wϦY9zx ¹̵yFa ܥEO)6Y³ /-qm&'sdF'Ye'^)q_c.4k1o'x 79B^s^rqM9LYOs6x6B2Yp| Щڞ"4<%h3sN~@l+|pl9]99>˜Р.`cs%A":h[o'?xο]߬1bX}t~/׬ÜL_Wl<;ڳ _=A]ۜ^*-6{`V'.X3ysm'<'!=j\ l8/6_ a…[k4kc^Ntˤg'n'pbR 4IsϤqvZf3$c]|S^1Ysk<#65&кLšc'មW>\ۓpc'As FIb!އgֿY߹/1n͜{9Ǹfv/׬!6hOhih]\obnv|s#\ mf.@sH :Z8meb+|8 g:~>'&.=s>}f =a4k1}f;kC44?';95c\;DlS;'e',90:Rxp # ?L'vI>Mxdir_0'e0Cg Z}{<|b<-oc߂; 7x14߫{95Gc\{Ll.&ϦC2{|csmG?yWhӡSsݎGeؤ ODxLČ64nrк+ s>w-KvBsl+k1wo.g:oM;^ IE^95cq&K~1u `ugs+s>8¹<]f+qK:Cl2g /18ͺ0G!%>`Ϝ\xp"5' h">m|4uֿYoԋa=x~F`}s/׬?gbs mol׷ K9Ǚ~y6/loDR-hyƮ.u;6z^.Jxyk4q߮op~cs>Oxpbܷ̏ Z~;gzlhw\bpE/^k6"lSl^`6"Wd mV'k{L)4< Øsݎt؜~Ax]6 p8͆1ǝui{mnkܷǴ |r2ֿـ>ڋ}?01> ;Ć}2b0'o' 9}L^\ۣB3ϣO@ssa]qݎQЦ(\Ox+Q]Č>q 䅇e4Eh;bZn }{ЬvoGwٝwk<ɣiM<OƸ&oذOF &}r}ryܿW ڎ>P'|(ٷ3nN. ek1O= gCo6]@ oб^795#sVb0[QonP~lCJ"k{8z]6B[?su :Ol/W>|k4cQ7LJer9yÆ8ao Z C-vs6 gqo6?wo+lV0جMzϦк Cw3з^$|panyu]*vX$^'|Jksk41G~u6п8a{ƒ|O8k1y}{@hb(=o^{pvo>Zft} >~^rqM ^1ɏi}7m?Sh]p|9ssmE~0CQ="{*sETMk䥁wvm&>0'ey3Cp7/uZ ;eܷ <'ib$t._ 2UYЬLherJ7ŦFyAb8MA3eD\-=2q o#u4Ao@3<eA?ZfK-4k[g-7z5[,6h 3mKep|$Re¹ JfM=~ZOMwmHx#G!殮lI9u8c'BsļZ sp` T[ֿٲ Ƕm{1c\el{7x@9{?+W  {y{ܷ B8;#&J+h1yk4[Nb| dK0YXo<ZZ sp hT[.ֿ gvqsl>0NlL`=[up38s> ZuA^Ƶ=2yrXa@'¹n\-61‡qw`f ̑Ph]Y{ g-}e=˸ރXzowfA=H[7y9Ǹff/lf{ / =Nؿ{@J8=B3<g纽 8 u)l3g g-]J} {m詶Z?޹3/trq;ݽc\N69C=w֥?ˠ;$k?+ss_"6_(|yk4ao2'/%v/l} @sߎ E]]߼"xC|sk9ǙGbSIR#MuEs!‡ ڎE^ sƢ,3g 6NSp%k%66- /֢%4X{m-p6^׺ֿ)A a ^ 1)Ol;'7~_3A' Oεݯ yW 7¹nCb_:/Fz9ǸIhw֥-y/εvhzڏ?%\}:@mݐk$ p^㧝&Zx‡ C -?dN|狰g{*|p֢ԯ@=8tSڋ=A/rqMїb!S?ZϘ#εs<4s"z\=6\l &8Mq qC#6y-!;gܷ{Z@_lt64?ֿ)^׼OrqMqsk'CɆNl?Z~λwε'6+b0k{ 9z!¹gJhppn8kOxHpwqmf8\f%fس.mK4z\e4_p/>ӵv |q{&-b\Ÿf{ {h_ƺ^gλ^^#gh/箿@s_HQvŦv£^]i_;]~֥뵰gλ4IY\]f-Ϳu ֿqb֋a|V^wtrq͎^1#6Cit0ur9r +wp.ʙ.ػʹow-yh  48wq~!܋w6s߁b |0/㚝#f*mpZΏ3 -Y;gBs߾wY;ѳ}Nf_UZfW߁b=˽c\skv7ki ݊6uwFu<\wvfDo5;csFl .+ye8bk4{9=>.wodFx;+o'4;@=K]l/^+Ŧ6h_Z;92{sm߁~%|ݼ.ȏpށFA#}[ ""iv`sch]ڣ=œG?|$VE{GoG|h>蓏k=;'=h/=fm Z?0^-k=s{G?GO{p{F+Nc0i<9O{ۭ=sntiYv롹o˃f-m~n 4=]^n5c 995{>rq͞ĆGeuiΜK cNn04QhPcsݶCMň_x' jiJc)^NJo홰goςN.}t6 h۷.%bS*L~+sk4o\ƅlذ.@yUmX3U\a*\h6{^U*Zt߹-1< [?55o1<o ]cgo).}uyphs<ábmz6yu1t*^f{}ءκ!t"G8^'Oy5 yS3AozeԸ|{\;~?|GCc~f?xn=bsm6p\\ nc~tz^7:N8 wpm}ĦXD~~v89^˘;[{?Cg \h7o+4crEOn)+6 /^!|^Z?;2nwI=d^zb?Y'^8'KO0/=o~ g^zb+(<]gK`ϼ:KxpG#4B3=.BsI< (Hkw#kpGz :ϛB3=;> O gqqq}qhO8I DI,ÙJ׎/<[ }-?1s;s<Ñ  [0/71chWxoOB37f߾,tp퍟CgM,JHo?&mK92Eς+|b%y<J;σ^+YNOE Z;5ν΋YÝq=-pޣ8%<~Cqz_} ˷4Q/:T~~'6@|JM8sjja?Um~5X3aCi}Cq~33o81zۚ~p^UU}^󟟆~|ۯz"<"\yqLim Ӕo׈ ߫3 Ρq\C}45C? }h{Þhn$$8^qp2fgE<= 8s_d Zg`O47}qr ssdxc Ps3?3jnWddD/8۠rU4tn9ŻRaq=U*Lx {Su3θw繱3y"4ϊq7|0<}v?gm-pvЌsm힆NκmЙb%<[x8Sŵ~kUp^m{\= sN[,su9m߄gqCn>5?^O?xnaqz Ƅ m!8c1? t<еkw1s1Maߦy#Θ .f{wɵE}0w151<,6ɴۄ06=y^J| oCn8 wm̠k=PZt52Bg-qvC?qӄ(K0r¹/8áYNk֧35錁/ᗮ$։Io~" O1C9Cy6 ^'gH{38?qfoqAnǿz #Xxpy4`~L aØ_]+pNo^F| ZA7׎oC*~cs!g3xo<~~0/qg17y/]=2 yoY߂.2+W r:iׂy6Ma޼72@s\\Z=hյh߇SЫofE?xѷfH'`!\Jg/%BS8k@#| 뽑8JKŦFx: qb\9&128V& .tU8sTsKӟ@sl+4xCv|32}X ]̘oc!fEUMhgyiB\`̛.^"ݴqn14C:ۦBiFqk4C9aLjyX{bt8Eoөq~{۽x\;rs.> m 'Տ9k5CoI6=\Dm|˘_Dm|[)J8k"ɷE5(ۋ{&Fx>{]: s c2'o1S3<#.q],~-֋); +|?|tfO<ڟKt OBW μ\x Րqgob<4 sa8c~a*tlC/Lf/̄̅.~r!z^,Lxp C?M"ޛ[yiDhbѯ g..'^b.7BȍO@gY\;I9?8K7c5s쭉&6OW6 {%Ƽ{ܥBᛅ]bBo7B g6bT!6DŽW ~R)k4E#$wc紺 g.; hk˗yg˸7%M1:>ݏ1&o3bmsh =45zeκ@S7wNpfX/̱aǹ;<·߹{ g.c|Ǿ{gX;߱ߞz'#׎ox1ƻ9knaǴ~:6<;<ߕ />|Onκ=?։pm"HQcw>?Z?Ͱb119Kÿ`Ϙ7 h}hShۆ/q/vصaчc>OxfsM2i_KCnDb^fh(κmxt +[1/CμC G0/&C3/Cg^ΥAw]} ek4_h.%-r왗sB Oμ~z>h}3?v|3>E>Z k56#& =m0rygFMas16A8_ -8p]a.Yƈ<93<?[͵pkYg]$6{^"L8#FO3gKuq6۞>)p޳ξDDumh1hkVB6F9<|(_gB =׌߅zQ.6M.DB<[nc:_xpϢF8E /^&B8#w?& R=Z|:¹ήs"͵pv+v#t+¹/6Vl O,¨\:Bn{mmhϫy>m6];5|h0:T:CN\3jN\36Ko }{N^ߎ1?}:Zx83 O,nj9k49O'<_8Ќiv\ O@ gٻ]ؔ /^)Z8]uq0lN 硛¼y+ o}43y=hB>TgoFpz7cN\3_'x~ hOǿТp>ioczO hgۗ ~LxZ8ֵ0ܓ[ذDt QZ@`mONDIS GOZ?Mcdwμ|֑y k#fxg &QxTCyyٵ~d#>*\>Y#  g^>Bvd^>zȼ|8tp#bS!jCy=~1ў*.cnh1ku NQ™:C3/] ~S O)ogL^lxvzUxw<=xw~%<[x| o >Z?͘o=s:㿂 ?84 /İg㸗O (Z;<9=3fB~<ɉ8 Uxw1A3SOY!̈́?I?4K=L?\3aؤӦtڄƟtf“5I=9 6W@ nsuי}xEhXYϺv|3(|hE#Ofg~\3|KD苴 1:3*W gý3|='" gttUxo}KӤ9e>˱?ž1?g™ck<y,M4GTrC5冞kR槴+IڄE^ցۘo?dm6θ;;6Y6AXq' O?s&渎1l1_-l󊏠˅Wg.*;]QD\\Thݓpf}psgO3iyi smk 0=4vEGhNwO.rfa7(Nsd;MB5?}!i`^ Θw gm'4|b__)u{Zlj  >7Ov}׏Iڝ-u"2Gˠ*8z}hh94 hiwv|R3Q%ms<פ-c皴b67&4[68v-^"}t33α]> ]'u{ĦQxS7D υӤs^Ҏb3o,'xc9t:u.4sJh7VCcN+w&@>\^|J?xя9kth}3m0Θ3 «8sSQYo ] ]iL;SZ|_1,t8KȾ׿.{9L9gS~}17'\3ޜs͔ߋ_i]Fyy 8c gmr7u܋?κ}}ĦXDIk4S2&R8wcq%<[8sQe7[qƘحH8I9Ί~˄Wǽ~Z?ԞSγ{s9Ѝy9~խNxpXw@3GBGƽx꽮L9G΄.g2~\3u_?xBl өO6o 3Gp^(|pGp8 ;}d:tp#ibsLx'^?uk4S9\7h0/𯜈™ûY營f.?͟ 4S+\;{A~iW1sʹ+fZk6O]G?`^gυ.G8k ƹ4[ۺ})03e^+]Veκ-}*6݅ {} i{5A O\04k8k8췯<^ֵ_z 2~\s<פ&6ɂ>Aje_C-›¼'k5XO.ٳpk{x$)qOk4M#kuz`^^E{2:WxpՏW?f= /Txpu?fm*&nOWo>%N8N-س8 M4ț{c{{ݫc 'O"p?ff|yf`-M-u:¹։g[m̯ O,^ ?}V[Ks>ukؔ ^%Fx\맙Ldfv 8 _"3*.}}+(}ibcf>oOf&XK>z?lK@\mc~~[2+W ^#<ߺO3s˹ҾP<}8}A3}5hOl' O&`-{6Կ^/}i'}l_ O,Wyp\h56櫠K /^)JxZ?쎘R.Үaw=Dݑ]OA3v@3λ~'kd|'6 Ok4z.o`-}n]g.vmص}iW!^ /^!}ivk1g>Z56Գ g_5lj{lB 'O"\#;.r«{ifWyN Nܗy\b ;;t} ' G__c洁>ig}:ehٗ hVХ˄ ^%Zxp5xZz^ǝX'c#3<?h8\#Ϡzb  O47޵X[oϋOn <[8(h6mK /^)Jxc-O3w+3XK[&†߂A'o oAyK&tp-s&AxiCҵ~D=Ŗ 3[.f_2z‹ 4]c^#|]-@M`N{GlKA\< mc/Txr«W 3{sĹkk`?q ~'B3O.܏q~{G8\#OMD)ӄݵ~yu~ޅ`-=\OtV^ x=1KODC_x2ї}ZswkqkR^/}qkf.aA 'O";g>  Ok1|iѠ`-tʳ/ms49䉥˄ ^%ZxpQk41~hArϭt"9a>,R8{źƿ>>,YxT3g ,98s)=.w¹r\1Žl1.pXT ~JxvfK,rc.1»=*43z ³ /@x\nsɾ6uI]G^ i3+C3+pf^+$ЧĦNx0#B_Z?MpYQǹLeݰJ#g.V5"}{S#r Y6O !<k4٫09Kp/XTxp6WA8G4ߊ iyRh]/t& i|9󗯂 g.? N}cj· JnE+<iOzyY> 6EBW \,?_>8/%þ<:Zlbw #<,sequ_y.Z:YxpF'@ y )|"g^,DoTb^}\;x4˿_˾ Ҳo7(hףeMeM8 “'),9Pwsl;w,{:[xpk59he.^.Bxj5kk4l\e`þl1:2GG ȁυq^/ܣ^ 6“ Ok4\q.-ޕh99FsPoY9K3G9ŦB1k#/Ki99|WҒZ?a^rpL (KΧKdS}  [z?t8\_Kq.^1t tp8\y o|^Z?zR`, åB /6hbi_h}k~Jx0k1K {?Yz ֖.6pW8Ү67Cs?Zz#td)Ӆg ςog\ɹ>=rz}^=hcgqo5{88Ys˸r\/qwLl*W ~Jx|յ~QgY\D4' ξ=hb\//  O"<>W矴aXt<\SB\M&t= /^&wg{A_ Z+'5]D<] 5g=UxwW]-8psp&s\ a3 L/υY qzϺͲ<هeAbvt.<,翃 5d@ _fzXXΘ/&"~˄W?7O ǹ|c󰩥-tz_q"&<hs<#-t6v|SY9, ȯ|w%kݕxYZlJ`ݕxwBp|fBᛅ` 4IhyVb%KW^ߺ|8R}`--Ye''4o T8gZX0p!бb'<^xd)9յ~1??٢=ςs xCxgPm?X8>~KŦLxJWpfE\ZÆg^tSOr|KIż\@Gx_'7Ys}س)%N8{TNdLѓwYϙBc?Zk7+/@>`_<4\ x往b}>\ s[ ؛&3؛&/R2C3Ιf3_/XxrDŽW7 \^瞛iaDo\/!Ӹ2l32BDoI+6'O ǸOL\6kiΜi<9 - 1;˄^%͕ٮǬ&\f lk6 o i;~ iEqW8CljMpOxḷ|޵~jZv^йsm mtߧj߬ >jU7uU7uUnBC`-ͺDۘG@"em@8_ O(}NAd\\:=dy#m;?ݢ1Zn fA8? m tc+?)gGk1\=q:O0^8B ?BОp&Ix4Z?ͣk=ڟ`-e,=O*Bᛅ(4 gh ᙨGv|K+_WNNuG5]l>O}? RΜ3m̳]ὅg,q^ m:YxT³)c`.z%[gdt&)\ δ ͵q;tp-ЕbS%ZIunq&o<ҕskd'#ZxԸdp/x|ڎ>p&qϙɻL{: k~ k^~|0yއ_ _33+|pA33@33^'A8yu?&Kν)XK38f>ExW\ 3COZ,?s2tؤ O%^0}o93Їq2rf5 3juz_'xY kV'i)ߦykiƻ@ ?Ќ󌏠C )8a >\cdJ? g$I"<]xpܛ֬vfͳo8}Oý5jܗ37 &kљ4LӪ˅3/}Ll*W ~Jx(/pfG35_26syn{™\X#sϩ'YSQsqNXsڵ㛵Nkq?O<׬xYGlMWk`j%W8nSqƘ8O4<0Jxᧄ ǽicfa.83u1{1»g:>4IYSq֝"6ӄg {UӬ5})XKSw)}C8{Ԕ)?Z1˔ĦZxS녇k4k)}82F'b>2f]3/Sz@3/Snfs|OxD)ӄ÷\o}ο.XKi˔@ /5%-Е«W ?):]ɿsؿMcLFb'@"񟌳M<Ь8eqqVy/?|&W&='g?κٌuG brg ؛{ٗ&:Ql' O!}9,aLJ|pϝ/fc_8~$YxT³g÷KǬs>>XKq]³xlpK񽠹]!?7tT ~Rxzϵ~hy^NR~:ZxR@' g^R,6)Sg_Z?=wCz 6Ksۄ?%yIyyI4t).^&\xj5k1 EOk)e-lקn VMRmsF$S )+hw :v|S93С;zN๦ 9x)(6i:˷iA/{q;ڲ> }yܿq-c,UxtYs·; kiذ?w K~ m44{ѸЕm7oX|_XܕǢwU814c2СhpfC':N6 k6u N 02XKc3cq\^,D8{ЌЌؕеO ?%AxSak1Vc.K81س pW8ۡmZ#T}&Cxy&i6ss9Q[a3I‹Q8`.FLkaj(WԊIᧄ7o P^*\P9aZMӨug^Fs w3/sQ\.r' O.r:4v|q@>:_9w=5{k6>'6Ŵ }6K#3#G@ /s$h|Xh|(S o Ua W\xsʹ/XKIato3˲<=dQ1EힳE-Ьrr{rmlc+Z,QQ0QQ   &**><9>}yq]>< }Iy[phzѓ7Ag<{%fLsN\|IN^˩ sLxp㡹<T܏^@oL׵7a>O^3^frļʘj^L{)}k!YxpzK* sj_2g ( o|㣷A7Lt͔a s(d&O^3mO^3Fb0& cKWmͿ$E8QKж8o8.f5?u>¹Cɛk' g' #1 /G_vmf%%F1Zuy_}{KNˬh?1}:'Sy}^ftYĘFh45t9?u8 ::OxK7uk1S1vxp/Ɲebz ¹F/_ ͵0z௰G/HQcSwmfZ$ReBz g4+)S0Wy[OWϣ#fڃaO@i^f/>{ʹLƌ3c^z} kv`]LbLb%'H%t /^"\8jiXi!EDU(IxNhv;azhut_o||sQA_I=^&?+13 =?Tp/Z Κ^;Axp ЬЬE‹ f#cK~(܋s[ Zr?Z7(Q1+q4"@Xy_xs;\ |] ES,/\xyYKȺx`;b8/n*¿9/w^u@ )9K,E<Ϩ`Oy5Yxpzev.VAۚû^-^$Xxr«\>cMA=nWY8K"U8?gɬ&GtBs#qNko?sF0}"4{Ts^3}9x/1 ȋ?ؗFgG''g (A#N@ /^&Jxp63}?rc7FLE  6yG1 ˳^4b.tpψB8q(|pC<͌0XfDq>N88cq/sB9gfFu4^3p>A8p=ka8k_88S$\xuqQ<͌ 3>$~Cxpp¦r.͵x7tpK =Lb')Lx$#' Ggbafo}{g3ݿ A? mos,>|9e~q\ykfykfVI.L͘}4>??<#\z%5ugC=' O,߇M2p˯*7ǝK܃,Xr͈aj霋x\C @'HL$Sc^ 6OSk!cAMćCg n㯃],/Dxj5OAs. {pγ=B o=➏{pF߃{F}“OW7])s9 O"#LYYmߟBCӡ˄s] }RbW  /Fi .OzcKCF ]»|&bh24'_} :VxpWx$#ůG344P3Ӆg߄[+W ^'^xpifcX 3Yp%; X>f::/&k.E $&Qxd<,lwo &wC<]d n[mNBӗzX_xJK639o { wU#tW t66;a\쀶5 /X9!4%3w~1ˎ{,gak߂~? 6; Y5= 1O2&_{*tg|g=t(;@wk~>$# O>qm>}Νu{*' Ο";'CW  t I8˯Msmje"Dz3x-ƞk={u]s^\ u!8s 2tČ*RxTc G_k4cX~KÅCO-*4?x*4<R8iS#Vx&}?^8?s+h[_@W ^#^xFMյyX8t+GY[q_#7`o= ֯AsϽO!|õy}έ<g_E/@8BМ9Ьy47ꄳE (Ix}'z?)6{3AxlFi8w81e˅W@s.+^ˡo!Kx7rk1sh/ǂ> +~Z-]󋢄Ǯa,Xq' OB_6O3k~!"xu0XuWo\\>gt<‹ 7ܿsg׿1:uX8W]W@x:} @?Bxq]k4sn-{t8hEPh[3g (yխRxZعQcwհKb_)< 9ǹ6O3G>^!tD>ꧠ9Wp^rG3)|l+c潆- ?#W⡋ m+.nNVi.Kx^wmf0%/ [B"t8\\΅z"?_C v Qxvi?<ͱ*/ើ4"F ]z sqi#4˥uЉ“"|4Kc9=K遗 ON4 sqi64|rKo@WIL7!EG_XB{Rz`in=^B^¹Y8aCnco9=]␿ٳ  \셦w4B KL2Uk"o6OS4,\F =6u:aor..z~3Rxhq‡ Gnqm>AYTc.\\M\Η˄#g?40~DqKp/!Axpz݅ hxћ\/VC R'K#G An6 \(r^_x $#.L\\ M)N~((1s /^6OIKbσ0bBW N;{e)<8mԸk )'9/_6cAHD<=|+|pzy58,w .FXȹڵyg1B<=Dl9up>_ι84˹˄ ^#Nx=r|̢s.yу??)tNsss8N;Ša/v& _)!-@<=>u-\|b9g%g #r{Z.kp?w]+>ˁ\| M gvp).^xEH\<?!߉ZEutfhE{\/8V.ysɓ>@' O*| 4cOa{ v=ժ\yuWq.>w}[U#uS/Ax6yk4`,qXDccZ#>^s\/N(枵$wE;p_M}u,c9W|2WWJLju7"'\Y࿿, )vLМBh+c w'O>YœCY;N!Ö́wuP8}^"Rxgf ,KCt b聧[[ ם>\>r£ wCnc>sN0^xziפON;6BӻNN;] '1  /^tmf$e=RRF =SN~8k^N㮱[x_kG#Y,݉=K^x^DIuq]kӸk >vY3Qx< iJnXR] G =#ܭV N!hG\/ۄ -7r-ǔž룡c>~VČ>^xl9yk4%18y]?|/D8C[o5 oΚ%cvW )<*h'ד];vSsq>dNwPS;w)9#1WS czb޼ً͛_by3Jb`L,tcpNI` ]`,o~sua=8ýWt|7C /^&\xpq׽yks6o\yAГQAaB}ϱfퟀsom?*M8}~}9tHQchk1o9Ҏ:ܵc֥O9m|/꼎sڎڮν_'1  /o|͵yK7u[gA oNh E4}u{_%ktk1B+BszN$~ގsz;Y'7,(<[x?6OSZ<DZRs=]%Z8=v&]xnWZ|Lys :N+{멏96po==V8SBgH8g k4|)~Ų*1S9~%鍧^\ rjtFMۄwDn6, 9g3Cs'5BG N;+h;@ӻN:Y8}8T#v~1IbF O&{nYk4e#1~ogBh8Qxpz(h;1~he˅W ^ܞpm>E|sX.C8J'lhQ£w O@n\)sNv䜋xMc ϠM;:^ݔ' )^$Dxp]Y\o,C'z 7Quq" {g ߅u/hƉw~>-IaԿqNUqYG?ybmg߶.^.ٶ^ц=M[ %ٵ~t]^3m~'}V-sZ}+C~5 ӅZ ͹h}>䭹 /^Ǭ\әsyHG tzև\w7kd@LmH1ㄻȹµya,#8G3kr. fMP)4so،i[ppz]3m9McEЭ&]xyk484s/+94cNl4=жCӣ.jŹk¹kG*&vp5vpNpv!~؄Վ.u^)W{\Y^mylUw&iC9G>9 .HsgplA uGv@s.>[G?<{h]pzVi.Kxp]YUlX6pXq铇Bs.WCsƞ3Ex1Ӆ>|̪}a~Ϫ/xb襇gB γhBhσsa͝ Qxvk4 ce#?T:'lWDNo<sqh4!ϮDIG O>Fxr|>P-swp-D<=,-\ZM:U.>v Jb( 9<1K}HqELx±g|+șmswqub\Aӻ .N;t'_bJ ^#{n卮T>3!111mۅs.zi1t(R\iLeί׿ۈQR*|pz]}МFܧ]\D|)^(/Lx9rQx\<ɵy5oa,Lo/=pYeu9/@st&-ۅw Bn\YsCSh?>z~E G}s0s/E8}l1&|q'D_6O^e7#bà  Ssq#4k (Ex+r{9^ozGl}a_oy4zW!Q8}#,|ӑӬ]r,[B _#^0s15p4P&\xuVc~oa!{w1};w qs.0Wa] qcBx G O/6O7}ξsX^p^F<=p/zox^\Cz%BE‹ ^wm>-CM[bϹ؋p޵wc{OBGKLXÄ'ODθ2O/BOkӄN;E 4h /Gnc:̜zMN8n===c{;a@p£ CνTsp/*{B' b,h=ӡ'%vm>fUs/z]3g c͹صO&tp.ÕS%Zxyk4Ga,op,? _!.~ġ\=4B  O$|$r{ʵh/׃AwN!?m4kg*tpǡ%/Dxj5ȹеyA{c NJ몠[ խsš8u7qm)5:Jbw O@w6O'K!D<=p 1ӄgP\l.˖^ Hx1r{ƵM8@{9ߥn^+^e'4bhzזc[BbspQc"gٴcX?-[7RO8no\<Y'-Vx3g!]y{ρr\C܌;fk"ͨC+b3楕޵n c1_M"Ux.ȹȵyqҼrvXh1u5\qo>S Ope>&@\sgpkp?N# ~~T ^+^xr.qm i [F=Sxpz۝8z8:Fx8'!l\n{ ONƝE5л6.N")^.Jx5r<|Nu775!XV35Gmjm1cG #c\ c_/@8}`='9q>3z:חA7HL&m;clɵy`,l֐6KwN98%МugTp:OJi3yin}%x,U?Cտ^ R)K'U}^#Vx&-mk1[9^εT}ϫꪑМ*41QI3ROx4c6i~|c"*' γM%휋.^&\xZuk1L/ڤW1n!^Wc'CEJՇB3Lx$>j6OSKX;ܛV?=Nx܃V!b5!'  /^"\x%rk1|sUpW\!=p77 o ͹Xm'#::B8}l=Q-?m Z ]#V8n8J]ʡVa_7s £E6O -]4=w#*p:͹Rqz 3g |6VB0bG˄ U\TM8&>V !1»xGxw <Ͷ0mC/߅&<^8{v.^*ӄ.|LYk1ۿrPH"XBEuQv.]*nn;w F6Oho,!矕C+WG N[y4b0h.OxiӅg Il_sX;N[{ǜ7AW Vb o* 9pmfyG{GXpW?@~'u+Cs.V< O'O"< pm>fC99wH!>Vhu+n\޵}Ip؊Xr^%Vx<͎ 01mOAw N[> s\/q4Fx8'!ٮ8sw\w#~Xu˿͹X޵}ip$X_x*inXuÂ_1[ ו@s.ʶ;aէ@ )93eO, ,͹Xv:3%&KD ˮcege#,RxZꗡ\ztp;/BwIL?g"c^v>{ͮYϘz ^L{<:MXKbv:c v:O+f0ZH/E 4Vxp_BkYs>w1 -ԧ[Ϡk>O5?^Z8k q /:/]:/Y\BEK Dn6ScycKK?B7 oεOжuº#fAGILx}˞=|=Fx 6hKNBKNARFotxKZ>3'x?31G c^Z 5_SxpY%د'<^xpw<|̞E 瞐]yϒc ZX=Lh%g/_R]$1˅W pmfq'?"U8Kpv`I 'ΟKpfWr =듽5{5{$t@b79;ON_14g 9B/^%F8{um>foYαO 5,n.ka6'"x'4bcc'1a;յy1%wu aq*4/zbH^b_ovޏt'">{;>{;$&1CzH/ 5:toK{u&Ä O>Rxp|̾4e7}%O_/|pEhڮ/AeS.Rx:}<;>88Aw;v{%ӏ}ُR_o,p;ȁ׿ x O^'xwJb3nkt<ЬQh[QЕ«W  }=4c^Czib?~x.~k\ ~aXI$f-K7wҢX =QxpE͵g+pֺR-15k7o icX ш,~tGxo({"{m=ҟaEoӑ?Dzt'˽>{ O^3=~{mͱ /N_k5k^o:› y{c_XY b? \ujpYr-, $'1S O?ei9XBc>rUyp^\UO/^(5fy}IL c dLK{i!yбb~a53J_O>Fxqq>̵K.qH/#0:Oxp 4BC_[zi(UxpO\9xϣtCz /? ]kyGXBs/X8[@7~ӵ7Gw0Ey}r^^xy11/0kk%˄`^c` ^c\n$ExN8o|ѵk}Wn {g(¹fZXtp&1&|q'umg m`g1.^(O43K_zko">{i|ӅЏK_pp['/x9=Vx g y1ݵF ;Bz "Z0] qЍm"1ۄw o,sm}?i4чayG(Fq/(~5)n?AFko 9M^nw>{͡y}CK 9C췾z<+W CkYUmۅwp>|̡1e^*~ Iq]\ Źжy\ 3 gOΐq -hk4j18!>@)/D8 3 \-8CAp8:Ã>{۽>{Xc*g?pBp/?ΚH>YY h>pm;$Sx.<~ɵy0]KG^G?zx#G^ǽ`~,h}ӵ7?ESCTO k 5G"%I1x^J5π^/?жB:?%[xO_G yȝ9gCz)I ۵}z[۵0zp|gJLs <͑ ?z4-G g^t*̫tz[G7p͑>ˡ z#O^s'x9!1S }ŋ~op/g@ #?ehydhy& #<_xp\um>)cǚB~V9/ 1ycZ3h[_Bs-C?%?{$7Y£rmwK^ۅxn$#0~`Ehsn4yn/4z}i*9srϽ>iz4x}s1)Ѝ{^5Ixpzhy.J\)7:~cctص0؛o O'{MsĬbL#j/T>5/¹t9Em:a-ܔ'<_xb%qn^|L>^*ڏO!z ¹CEGp@1%Qe$YhbOnנm@y'2OCHL"%˅6Osv%˱ݘY (Ix53{RgY9~G{vͱ|~X:c5 keJ+i??75w 3u"4_|N K|yN+Eosskˤ2pzryT 0IoA笆#3(;' 8):MXWN74@s-O /^:i*t /^&Rxr<x'ƒYT"Wg0ȡzR ͽTUUemFZTT2C5hLbQiQaRiRZQbaYÔ3%*SX4ɿk˽̸!̮3#ۯ<53&t`Θ۴xYncй۹#>q|rjT g_<^'|LifT`1&[Rl}G E=⨿+g/&Q S]맙7|ƹ|u\p?#Wxpk{t楠 _]&\xuf|Z_6,/g*@isgƒ“O?Z?08!.jg#8'g?Z?%Aڟ܇ۋХ˄݇Xb.pWЇ ?"x; \yϥ!|.SPQc_85^xpu`8T|ʛY)CO\y  ~qօn̈~5elʩSg.lfT[Nm,ExQ?3;3">tS:x.¹,xIlᓅ .@x"+]맙\ IXG1BW OB>qJ k{zf > =3ų&v|33y fIfIfF }_ ?|8"N3882Nbqu3r.k*, muc9WC C.ễ7o;Ԭ[\맙~Yv⥰:yL8+N3AНG93ZldWl6'36'^u7z&c;kL&b}X eb5q-Xg/M vF|f6&fVuЁzZzrRS3qkJO3{qB̎38 3B珃8W878d s}^<;KyXƙ#,qVrh2/nW灳MxANLڙ/| /^* >vf6η}vzpN"vz\*YcpG8gCۄ~<ϊ8K'@<[>>R3CN4a%4< qPӜJKs_'xs_'x3\l56vx~, )|p Y6=d)™q@0gq1焳qĵ9WF҇@Ę71s͜~\3SiM:axq3΂n*=l'p<74q}cnWx_“,19Ǥ{|4d \]wF>{{7K3Vq9\l*W Cx=|w3z r sY e4oμ☗ѸƱGE Sx± .) ~zlqOK&m.pߌ1]&\xſĵ~-leG~1ʅ ? u"U8? ์Ќ(C΍u1jtظ O$ui rr$F {Qg@g \:bԹgj87Uo6-A8P|EG'Л1бㄻ' $/(I&!/l/n,40~~WxIƒ“?ŵ~D\ `IPs3CfЏqկB8ύCUMZw ޵~ܠ3;eFx^fæz2t#™SE\#Cfz?tdiӅ!qiVa.ٜ2 ECB/ns1h绡>4^lv %Qxp\)sŹːp_˜<>B8s1#h!Ao :Mx1³g , Q£#<>OwfƠsysaϼϰgoIƒ+ކΤF `_:[d§ /YZAپoy`+6AW Θ_3Ь+^nC6G!>ЫO s[-0r`sQ} ZHHȃf'B #.gG]2FxpE<%]1Ћ.2« n])tR|Yx|>w\$Y8{]@3}~rr-x “' Ok4A7KNyѥГ g.flf<]!Fj^+^.\)^q.y鍽je ?"=.{$4c&hd[*׎o :77@{? <?V'mC۴sa<{E‹{'2ντ\zz'7 o~>˵~'6O𹅸`Øǡ&/E g.⾅Zڹ{wjpI&f^BA C. ۝FxLY½/uI}\~ugϙ ]$X8Ќ9B3@ 81]b[xf='OAڟÅ EN!~EpDž\=Cs]YpI&4O\\唣|1\+4ʿ[ ?$!~ASoRhJQQW w5yt: ɟg?^'dWOnfOtep1C!~Upo]Yt5 wޫx^v tA™nBs/6ڎst"K /^!|i :ݮ\Q8\KnEW1Q83\8G;!>{h?;Mh]OhVЉj\E;Btӄ ϤN>]8=Hxp..^& ]/|p?: 31u{'G=:qxǵs7cx{mBߏi^3ůQB*xOϞͳS ,D CπCxq1c0Nȅyv@_!W;de}g[<߯ :Idѽ  ]#Bxp)؏n;H.ễ|}GsEc(\G8\mmuucJknJnD Okd,5jjĿASgR#% jj䢤ڳy~gSs[+]?I 8,9ߛC5<8\]#Vx™ӓC7on@o8'\t @3I܃slt$t)>Ƶ5Kcy__KޠlރŒEO.!%[,9siИKOBc.#f)77Kɘ2fs1Ǭ=>KauppI7A^/4hQNZG )~-N8_[@:H8N@/+W ~eQA{1e:†f:™NS_{4dtB<!(=u#4s5'O,<s?õ5˒Z c;l>Y8],χ:; -Ax&fi;'k56p}<įsB:(vh?b4 (1.$ O&|p,{ss9;Ѱ+zEʩO ~}]p(u;Ħ^N ›{yk4ˎ/8;`ü8Cz'įg^?A3/_>t43g >Y])=ϥ4>Ɯ`3 b%™ !hߙ8;3w pĦQxVm=OSzrrOx^~)rg:ZxO/OBs]4tztpg&]Y' G^J'OSZt~)\ֆ_/Æyz /μUh_o@3/ K8/7M&ۄ{yYZ?M)ή\g+μ=1y˱7&]Y' k4˻6cB2Ћg^~ZHf^~B='=n* ?C|k4q'AGC;Wx_OB3?~=qR &[d {Z?r܋{˗GtGqR!R8sqyuq34hwf.ЭbsHxc!> ϥ,kЁ>p>ʼu=|(^f24Kxp;E‹ /^!R8?`\YsۓqYMsqV;0/|፳Ɓ9:4 &™CCs]>5CX#âʃXq' O"#tENxNM=><9ڗ ž}Syه~2Qhؾǜ@JO4 >>q{U{ZA“'4fh96VC |7At‹:Zk4+=Irv)uwgOs4klh1Sg3!JxOX;+;O򪠳's }׬L߷y9d)Ss<9:Sxp䳠s gOYKq=>=%{A8#B£G  6Vf喠s^zj/ нRV~Nv;xHubn"uqbB^!:7 8XeCe[dqҠ qCS6KyJY-}^417e>dܔq&lj'ϡqVEY3U}D'pbS=}~)SLE<;5ey{7Hl/^&Bx%|Ե~Uwwko}5~ȾԭF6[_>*xw_,EԨ@D> еa}6@Ob}‡ʘ2fLƬ1_-еYG/c~'c51qZkh5Q1Ć\sQh5Bc15)s 2(s9[|c"kᘈ~K5%}28 ?NF )jhWx_g$<(zTiynV!rm] "|ԌYׯUm2=22\kp^Z7#= :Yxt3g l\yy~6Pxp~ K c)^#w-n~D=';7>m"h=!+yϡgm]YO =kcг6^z߇>k:t:s8#yg+W 繺{ 4 3@祛^wnb_^;o맒 J.0k*kMCEo5y9g@ g?zd>Yx|gi*9cRu]!0u-˄3uXﷰ&B)|›zZLuy4}|뮂 u8O,wkCs-ԡߦ' gסo'MTcg ~]5Ƶ~*o{)^^(H8m󎰭܆;{:۶B>X㛪76VKJG3/83-yYz4Rshrtprtؤ O)<[î<[e?=a. `cS g^*A3/w晪i:; -Qx|Zs7yT6<3T}Lýa6BO&-pc_AG dz2񬱌sG*6iӅg Z?MAڟKjx-oM g.X}iguw[xpTF<+ֿ ۡ ?ֿؗ msQmc:Ex43g k4ի1~ZZ g׭fa/^inUM;Ag G?⹦[6/mʠmwϱg Wxpuu8dg݌L:5b3Yx ||isۏErp^8WdT \#G hrFM›~D8_ZNr<-|]OsYA#wEy4E9Ss-,=>]l-\AC{}«_sǯy?Z?͖b.ͯ-']@CP ٣G= xa}l&4 [>rf˿t5'A{k555皚3ĆL f@(:!“s_.8 Z(/_] 6‹/^3е~l\~L J|cҋm™8L` _8t#]NY8ɮԬ :+y.V 8۠'gZ9Xy;4,,w@O\y  YƵ~0[9ʩU-F8{Ԋ/G]8\1 ͳpN9A݇qП:5\R\5Qlf0kJXpc:Exp+Cs-x @8 EbS,|2±޷Z?և0 Ƥ 88z#~0/?wB^\hgmA ?$ri{ +<}ټЋbȋ8 q^6DRܩ'<< "z=zbJ^/oB=l^XGhy_[7x_NA“OOS{sY*r/=:OxpeVhe8GM*^!Rx[k1E>} OCo׽6Xژc ޛ 퓹GG L}a>Wx$Ak4/\x9)Vžg5Й³VsdE8+Nf<'mF|j׎o^:E+C7ϗ݉xyߝ皗g"B/7=pƼhXt/4\t?4ETD\ EIb,F8{ m.Bۘ_]!Rx:; )܋lsq9{\}a >$M8_e A3΅8\}&^x$=[]y%2^9- Q{\Y' g. (D坢p"tRe+c^>gTxlx-(I8¡6Ns\} ${c`3۽E‹s{4{@3/$Yx6G~L8r.;Ӽ{0ù 99@㟃~+3:Cl2g /{it^ذ ]&\8sqQwQ8st7b"UDŽ#/q?;[82w%б3/62/ˠ.>5Ex4³c]wk1ֆOMs"¹.A3qnsǡl6]b[xfuӼ {5<a;fN!ppG@3؃μd\"6ӄgKi?%d?;|.cÞy Hxpejhe:hel%tpe,7 ok4 :cyo K!0/mN`Z%yI? ͼͼ μ"6ӄgZ?C˼8{eq"™f^Fvf^F^82#.-AxV^^\yw8~f0/נw(5kЇk g^ :ElR % tӼEйs6|.I|%tbK'yIB sHIxm?*p6iNR??}dp9t8Ќ ЌӅs:Cl2g / iAg`ܣ>a2™G?RO4,Fb"UDŽ#/ #]iAi0˷aV\e^{'yIDO~yID}yID|4]8hd +<_ٮ4l : sg0/]&\82mhe{FFŦEx# k4 wǘ~A3p_{{&tL3{ :Wx|Ӆ/^o7C|),hX-p0 B_ߎy۽q>,of*hcSUC3j?*BN`zDO,3tMAsúntz"\#@ /^.Bxj|_t/pRa;Ⰼq2qy8M:stv; S1c}~3'O>HxpHgaA8B89qgOo=g MГ Z>c/4~>hϠ+W ^'^Nvk1{:go$g3n {A ?$kNqۡȂG}+6} $<(<>qf̅sx>uǝ::KxpǨa\>]*bS)Zxz^.r]ٳ @/+pkz s{T*p+ę˩Cs} :VxpWxA“ۋywMNwu =p&޽pV!gЅ‹ /^.{\pvЁ_TD>F7(=Tkw0p-ZsHJ6CsQEB Qbŵub:߅BϠ>z>b'A/`KfmpmHэĦ6/ӦzؼEV蝴i1isc#l.-!߷A=bo0M19Nom6e |IӏҦM~_]fhh #CPf LY] qOk7 :оc7ʡ%hǮG\k]wǃ}枂5k>B_/8d\MϯOh6z? |AFVƬk?O1t_ONzL|- E{ 3UYW@m,J;¢LYy{ߢjq >kE\#=AQ|3[i~ ?uY 짟J Ӿ~'zN1>[14-ϖɘ2f=2f+DKg_ɘ?li6 w^qfsbA ~dD 8b'?_7A~94{׸,{4_ڹQA=wA7kyj̆_OZj+4/׮n׾׺;ھЯkߗ6k;)i yk?zZ웟"oL:8~|r;WC™\Q)]!"/ok+嵯k*迶}.1/콹ǹ68g>3H8j.ήbcs3췹AۿLhSrq}g\zصo很ُ-~|:ݏ|3>Wko׎Nk=~_,y9Z+f߽zsr ]WB' :IHN1m.Δ1dlydy쓹Iмo>ߒ8?S%kh^Vb=yƵ11_8_\N{)c1Ș1?Ms\qDl>~g&bkEs߅1]s2H1=4sy9],1K8p2f)dg^5ccKe*h4f 41%-[~ġfA]40f 4W15+^S  Y81/;}v^f߿N [3tN*?n-@ `Zp~_hoCc. b36Уie=Znc 0K g N>H&U8~=\w]Bg εgui:3R|uif KK7 gB| &X/c]ut9mmh'm{iy8@9^p6kfmۻ[B累.ﳖky4-1[ޗqZd#qw0g9qq2pTo//+^*'DNf߈̆f#s@)B w#@'O::nhd=%˄,.~f}F>B{`Љ~ 6x}d&#fb65dN i>/8+Ϯ~>w@g g·aЬ./Px|kk : M}O*ؼ\ ]!Rx=u6/àg$+8H1V O> ,smB2+UVXBW^sEpiWE cVvFܾwḿ^;B'sbhލ ,kXu~H8ρI5{:=(ܞ΂N ,ڹO=d|6A{y-bؿG{OO{ b88WV쏅}K޼ug s,=l8p^z9ڮ ĶЕkzzv]C۵ F"_A +<>$*Yh"/fDNqkce^ĝ1LM" ?14Sf4m?_w`y<(mPǁo Oݟ1pƿg_y>Vx͵:M\kY³voGh[h]7 #Ovk^Sd44O]+sc_7#s}n/%W2?8=4F :y\ yl? 7.7=:o~#PWs .ν /^.TMb^-oo :oۿ<+׵P/n~D8{HR'{c7nq}=as] 㣟;' {p۾z9yecNW )|\y2N/^$],6]#s85{cY7oΞahyJ'P}[ 9oLεJ{硓' O&<]ƴSEW0\,™Hs!h7#y\wڸSNL q.=\L wՀq6$9\-6;ho7xnalsC7R,yb?+˱!. x%dLG Ti™LhY؋ѵs7"g!Э!?pVŖϝBwO)}\/C g.^lv %= 6›7 o*cr_4 y6rmvkӍs7tp[ϸsm j 5VNu;M)Mn71VfU@3&6B8`l=9h۴Ьi/@7 on/nv#WLƭRYi{8V%q ŭ}Vi㉸Ux"n' n' n6[[-Viqo%9Ehf_f]Myivhנ+CyiڛжP7t't+zHkޗi[г{@?iE+ޅc[7}68vם@UTWE gw|q+<^xpf:Ct4'9XU1߅ƙUn[ЁnC{uՌ#]Z#ݝY8c86s8l$| _9_oyy{B\|'Uh;uYoGe^DŽ\W'.h\Fc߁|߃ν:x.N6&9(rQ!r) $t\s*UG0#TbΌ0B!0Z뱬g{~{ckǯvv]50Cp>t³wg8Hc %3/68{5Bz'-X|Krk/? lDs~<UkOdGFG:{Ggot4X?+j?vvl_e} V=d}6-_=k8%=Xxz;dx o78ꗼC?z?fZIי9O'Uoy'yO{Yϩzkyga޹`,~liC=Ȼ lV} :CG=o-O/yYgFsџ-}`?[|$_,~9OQo XFtQS^裿_fY/Xsv~;+4X}G~xA=fNɥARۛ'K-w;R˝}v:rg?ZK-`BsE9 sEqy̺5>gk&/J},ʣ_4>g0gϗ16mo|\6`~X~'!XodxY6}e6`ͥ|˚9|f5̊U?̊5C4C4C4C4C̊e̊e!̊e|f2͐|fr͐|fr͐|fr͐|fr`>b=YܞŬXnbV,g1+۳+Y̊,f {b=Y"%̬XyϬXyϬX}6YBϬxEϬxEϬxEϬx%WYz-Yz-Yz-Yz-Yz-YRϬX^VWOW7W9TgT%^U1^~^^Gc^G+^_ V_U壟_U#z-Fヲ^G˽^G^Gw^Gϼ^G^ lVl k^cOF/`k[5;kkZAz V4 j`zF_Q.꿠X_p(X_p8X_p$8%/@/M_p smݽwF-m3>\\ V?/ZBtju!:g5:g5:g5:g5:g5:g5:[kt;\t;wl9ZsޱFcky5:][ktλwm9Zvj ]o!*D缫YWyWkTΉ>"^9Bt{u4 9isS]sSsӬ+D缧(D缧YWY5-DѬ+DѬ+DѬ+DѬ+DѬ+D笩FѬ+DѬ+D缯Z*D缯YWy_f]!:}ͺBt5 9ksWs>Ь+D|YW@f]!:烔0:ͺBtu4 9_ 9js>G|h07999999kUE蜵"tڤ0:gV_Y/BUs֪9kUE蜏TE蜏r99999999蜏UE蜏UE蜏UE蜏UE蜏UE蜏UE蜏UE蜏k99999993?Q1??Qs֩9TEu,t:{:g= ΞYgB笳gsٳ9ڳ9ڳ9׊9׊9׊9V s>Us>Us>Us>Ss>Ss>Ss>Ss>K s>Ss>Ss>Ss>Ss>Ws>Ws>Ws>F|nܞܞܞܞYoB笷gs۳9Y,tzktzu1:g^}]B}]B}]")B}]B}]B}]B}]B}]B}]R}]ҞҞҞҞҞҞu؞u؞+=py`͐ !}!ŗ5C/kkk_dƒ\u XU< * l56 -q8lU襯R襯+5““QY_kFOkF?(~ Q<Q<Q<lϚ(~Q(F`͍?57 (^ (~lykn (knd}QXs-FjF{`z#zxX\9؞e8=`V?77ηYY[[KF`yIS꼤Xu^:/id7n ^Y`*9$ʒ+KU%Ò ÒⰄ3a AuXߠ:,AoP7KT%^%U%U%U%U%Y-/!W o G`?X|Gh?Z|Gh?Z|Fh->Go7Z|OGd?Y|OGd?Y|Gl?[|Gl?[|/GbX|/GbX|&d,>GoR?ߤ)B#U$U$U$U$U$U$՞-FyByByByByByBfyFyBoR>R>RZa>R~R~R~a)a)a)a)0a)a h> V͗.k> <,Xj`җQ+QV5`VoW[l.5l%+p7`[IJw{V`Y#꿬)X_ /kb6`Y`,/;/; /S`YOl\ppo X_v X_vX_/V] V nnbMTeUeQ``]jq`}`Y>X_VĚR`Y9X_6/UeUeUeUe3A``ٓ\`3`?UeσUe/lK`rpRx%X_WV[ lnkf>8Gx-g`/V`[(F/`V[V;VVZX_$PgU-`yVV VZˏ˻UǂUǃU'U姃UgUgV$X_~>X_~!X_~18%/// /6g]gnCm`p$8lw6`0lUVmUe`|*I`W`W,|.؞U g=g- bFbl=6VVO/_[ׂX[7_[-;`l?[X;)[-`-o[ [;[`ŧb" Xů8_ qW[`{:Z?G-1`-iAw -y`[K v ׃-~.Â- w-Xſlǃ-~Nl+Xb2X~p4m#`ۊ3!sy` !CYC4+hϪ@Y{qR4FGw;[|GjZ|GjZ|GX|GX|GX|GX|aG)a?O@)?O@n[|Gn[|GaGX|GaGX|G',>?a OX|GiGZ|GiGZ|QGeGY|QGeGY|GmG[|GmG[|b],>Gw.X|Wj]->GwZ|1GcX|1GcX|GkZ|Gk*D7ş"ODwSn?M'Y|qGgY|qGgY|Go[|Go[| G`'X| G`'X|Gh'Z|Gh'Z|IGd'Y|IGd'Y|Gl'[|Gl'[|)GbX|)GbX|wn->Gw[|GjZ|GjZ|iGfY|i? OB)$? OB+$Gn[|a=,>G{X|GagX|GagX|GigZ|GigZ|Oi=->G{Z|/e,>G^{Y|YGegY|YGegY|Gmg[|Gmg[|9GcX|9GcX|G'->?iIOZ|GsWUJ_?W+)~%<ůDgY|yGgY|Go[|Go[|o#ﭻJoV{.[Z޺D}`%• tGW@wt tD_s}%+\_@J:W/Թڕ ->B/ ->B/,>"/,>"c},>G>X|/->b/->b/K,>/|%PD;T/l%RRTw)KV WTYU*\a_wSn}UBoU˔W2x02-W/r2`2-W/U/Uϲ_#\^\^\^\wUUU˵^U5[W+M wSBT| F F ͱ*+M޻B{7U~z/ OuX43jCwBoNwtTuߙd"^_z_1p ),"Ϻ@gKCc]-_<7`6d.uvwZA0Ow9ξ9S}рY߾O_k_=Ґ9yeߘ|'d'p#T0Ͳ^jFyM>vL?~QܐY}^8_&+>\gGg8rj+9 gvξ|>2_޽͊=Ao/v8iޮ.q;㳩|ˇZϫc@oJɩ;46 >Yۀ̟?`pP}M5qG<` >[ѳ_O8r~yɠ<߇ H 5i#~}"a]yL:9kp g>u`o|~kA9w8g_.gpvmvXgfSU6QsAlPی}P'ghv2ьjv 'k4c4ٯuv͇fg;O|`zxu<[|Uz.oHE<ķt>78o-Lωg|xZ>豭 2.l Z>ȇ}ΧV>C_'ki>۠3І}pP/pvi6쏃VejlЛ&ScֺќiCr7hO>i>uu>348{7gZww;Sc8$fɠͺtm4c3X^-g 8|׶i8o|}'6m|Cn+j[y@>mʇ6̗mOɇz޶$t鶗oۖPc5war gvj>2xA/356xm~78èƶ8du͝jZwtDƮ|mO|pjLn++2>[g|ւ'!#|!M3~+jueio}*&Pov>ü~|:J$Uث}iyu-8ه:䫜3 I]Wej陚N[o:Cj캵g^j5-ξ#cؐ!) 'dtm_~_<,퟈gQ>7:}ASm/tю #.|ց:C8Z>.LpS>^r0ow\!yG?che Ig6#HÌl)gp>sk^C|Ge2/;Թou>Dg_C9JgW=W;dp=3%5w f\SuYz8^wwv|cҊ=u1>+~^C|gdp~fg4 &/r%.7qN~{uξ7:0a!dI sH9ڃF8{uCsoq0:9x^ { Sz3η㣻ӷZg8goEy{n sf^C|{ɠ{׹\\n\]8ή=}`Ig|`qy~|i`݇,LX<,-x6X5x%X{;oޱx~U,rErܞ u'bm;]~MOq>ɇsӮShѓΐmL[tˮ" k2<'׼b.IB{+RA_pũpq8].NyYԸ8\.:glrqvdĹi&Mm3qnꘉsSL.Ή.Nw'vq8\!.N3sq ]Jg3řT8\.2g󦋳Y _vr&g{2cMuNΞ]wwΞtmoLXw$ѿCk t Az䃶}ڧ.TknQ=CcOtvcާ[lf-փpx 2>- X-3z]K}kא +-pw~I4?Yw>>uݭ>`W_?\8}vj= CmPp8PM8j Clyag{t\gZh'^ 7?:דo|}]>hw}yէӝ}.} z6z3z3Zǡ[2doՌmk/uNήk_F⻧a8 ?EG߭{`^|,࿤}pbW }],ޚpx&jz& j{%jcRVfim7}kos߽4ayw/7}A|ɇ}dvDw#ViG̭{2aA>L܎̟aֳp8a Üt0s΁aNב6L#XW8֮,4rܙ{%9<t|4ir9>|tB=cUÃaӃYa;Rgf݇9:z3z3ia6Bpx8ir,6҃wOtή;x'ݲ笄3(Ko?w/{ƊໝO|G}s:pg>y ov}G>8Ï[M8a #l'#Lሜ #ydD=wuή;+8%,cý9O/~ր{;+>_ڧ.~}#v7S^gl=qΘ#s;cpg9qΘ#} XAldlZo%+W|dNsX ?z|{~ Nv>ʇ}dciէ]wwή}`wo0zGZoH #GÑ_{\_]7:JguEό|g$,ޥoF7W:O>3D? Eէ'Gnpή}?6zGd8e NFQ22:q'Gi~58r0g޽W|dpBQ}R i~Pw>:{|΃Q}𤫱OO<٫]Iֳ֛Cw0OġEM3ǝ4YzuNΞpvICy$,IWKRI׈o||{gߧ=}է'G>} 7[hM8m h?p8zAѦy"W:=!X,g_Zc`μnMX^}pMgv#~:EaٷX>Q?է b2ۛ:Sxm[֛px&n7=9nowk;e?8ƌ>ٵvY9{6ay+~ N#~Ns{dO"}>=ׯ>yxtv=k֛֛pxG?pxG wYw$=pkzs[o u z^ggY |ˇ}di({Dhgg{N[֛pxfġCOa4O:=g%Xgxoqv]ANμOOX^Wa8~&ko|7N_{|>U>Ů>_p']l `Y8ӽu{Nwp{N/9k=Xjg_Z^;9/JX^AoT;B_*~O|GM>Q3O^]ggp&ބ1aLN1v7 cL!R8=gC]kwv̙w +dNs9S36߯ؐo ]aТ>r~>=3Jgg-[F87#?v7qh'pw..sMkEՉ[&,08 z7 t#0|t#0Y.gcWٓή}߁g.M8+.wp8f.=xoֳp8zZoXw0Y8kqzf;c}k Y + VqO*~>?-irڴO]sxXS }TlġXaXM軵]p?8Gpٻ9Q_',A,\PATp4? :C"pgU>KǤ} _aW^>ٵ^ 8nM8zvûn64O*=Bֻ5K/k]kw!-ay &pA¯4?6U s>&]Ë_1ٵ^tzYo8M8ƙqǙq㝿Ƃ5K/<٧;qjrEw%;i~7l, ; cuߨaqSg_gg#7M8!cﱻY8''=ݜ>e`>ळqv]t= +lK2S,>%i~6?5g 磿"~*߰}}/]}z q>ٵ^|#zތ8ތ8tw8n64Oawq.X[}O~MɱC  .ᅩO4?6Rp>7ȇ}i9UK ݜ]%5`Y877[;{guݺ4>SwK,Ek.yoJX^aòdNs`*53+ gn9Dx|sxէ~^ή}/}xYo}9swn3q.7XZgZKGCHX^a%pORŏm7l{ ~|toCaC?沫O/<٧;{`وC͈C͈Cwp韈C8tͻoOƿnD,l0wtveׁ[ ~ .*aQಫd|ìt)G_Fa,aO}]lֳp8z[oxw0Y8o?}^^쫝]kS0gެsWu}29 ?!0^|)HV|9>dyg\ pgfpgnLaP=n@5KDv]k7 ə7kB &Rkgg!0kuڧ.;p{Jgٵ`VYFZoFZoF;gެwW3'90X,7?σ:P>#i(~]}6Ǯ>C]V`Y|M8̷ބ|wo'f#kۀk}kycW;- L]F;? l!~\\9>"(pR+P\n]`Y8,ބM8,pw n LaAkH-h|<8n R7vC c%q,~HCal^ cYĖ'v߃tή}vP',m)z B8,Y8,4ݝA5Kuq~ήt(3oO +N4AoϛojwW~K\OO:{ٵ[FZoF8B韈C84qk\,<'c/eEZSyc[WبM2ٻ;{R+z7zB8,Y8,2EoIcC?˜]k73o3WdNsxk*r|FwΧH>#/ñO 78GbY8,ބbM8,vwŦf4s oɇ}ѿ>u߮ Oos] 5C͈C͈Zlj韈C84%8khp58S%yNX^a\aƩ+4n|q3: wQ99i5ٵzK7]^C(qWR4O2=5`қvή0gƇ%,yɠ"H7#~!߰uxM>#'?>OTbή}vXzS֛pބÔCHÔa*7aj7Y:rJg K96Ӓ|q87 +?, !,M*yQ>#_OBԧB/svڂg#7#7#Bif48qځ5KGww^ή̙6^ iJgY I,|ݒ6wK]sOGwή}vt5zK3ZoaC(5qhwy":qk웜]k7)0g{Wd`i~7lk&߰IO磿k&9ߤO}2ԧce=ٵώl= e֛pX!22KCa}|&w>ȇ}ɻiLw+ٵVv^nqhqMDlġiM_{\Aѫ9{sgU$yIX^aAřpw*giކ|æ!߰iS{r&{=+ԧ Up^ή}vb87a&VXoaE*I8Y80 u^5ήx3o +l=LLrT0wFUDXEa˝ 4,(u9t/ZξٵN bgp&Nބ a8p84Nk>YɄ>ٵv`86¦`ҽ2LO<"~6MGO|G>?>o=LPVvή}6= ֳ֛֛a韈CÉAÉ3U, q.ή~b"gަO%,dPy8"TBL:*DY8h 7pCXp>y"k*4D*4ĵξٵvUhyHX^A'*iNU-|ÃN?ׂ;s>rPR>?N]}:2MjOjg'WwLJf8d $?p8fpi84k<Y:y ٧9nT0gރKX^A#T0yM7<<('P}tW^g| 8ބúaC4v7 y}wA)kN{;nʷ`μ=ƒ i ԊO xD>#K>7®> xspS,VZoFZoF;J?v7qh'}wAeuXl&gߑWio,ayN:-7N-Bat O|GKDC˰OZN8{g>+`Y8ބ*M8rwUf4V.Jpξ-yHX^av2 ? ~ f77̞|=f{/ﱧOuiή}vFlġfġfġCl'qh'p7 6Etٵv3sc 64h?i m7Hې{-mSm3 0E}: 3%콝],Y8b S7pCb,Np8e7 3EtfJZYh)y6+ld0KڦYT0K)i~7l]|aiv|ξtv?gߑO>;?zZoTM8&3NY8j:qkή=̙ +lvk2}8 f_!~~~Jv`joupէs/r%ή}vgֳC͈Cw0Oġy , Otvݜyݟf$p7SCV,|6w>sէsۂ8{kl= [owwn64Oġm,ٿqv܎`μ`nˇ}y|sէOr7]g#7AM8|!辻AqO|N }]kz0gWdNs,; ZoFZoF8NLDlġioy5KJRiZysma sNq؂sʼ4?-tN!߰)h|tN!)QS` ':ֳp8zYo4w0NKe8fpǁ5K/qή̙ +l;TSA]'ۅQa v!-np>#>b|s8Zgٵο)=d= YoC֛pCx>dwpP2C}75Kuή?̙x4Oo???o9-BuW?aW>ҲQ'߲q}G<>]|~uv [!Gq&>6,>l'p f/o:g-73o& +lyT2XiÖ}|Ö?-R+(e9\D?>]4 'c$>6,>b $3>1,>bq]EF ٵvF9/uaوC͈C͈Cw8nwp84Nw]0=GϪk+ٵv̙c +lb2zqT/ď;&߰;&߰{3}<ه;gֳp8z[otw0OġF8t]0]{ܳZ 7ξٵvNsmE [Œ%i[IϦ/oJLaG%>+ou/?wm{T}`pGggp&>j f8y>jwpi8|k{nX3ٵvϱ?ʙU8Q19|yh(jg_g_ Ǭ71M8|!nv5K^+]kp0gWdSRCď~|#GHaknc]p^t7 ξٵ.6Ͱ9gXo w0ΰY8ag t,]_pgZy[JX^ap8\??% [{7lg=lφ?{VPc3ԧ+XsٵϮ`gXFZoF: ?v7qhg.=nu5StNΞpv݊3oWd8ܖ VM4?i(~YΧ|GڴJD۴+kPr$t\ֳp8zgZoLw0δY8i'}w=hf+]k}k^ ۦM  ^Inئg*x%!~W 3|ȇ}@D'aWg5uvot[,M8e ,?p8fpi8徻`7ffU8Tgڽ^33oWئ0V7N?̊쏦!߰cI/(S9|ӷn/sή}-}j֛֛p8;p2ζY8mg'8W,}Ξtv[ٜy,HX^a%n廬}_.m}|'6MPwž+ <8wgp&ζތ8twMD8MDsi,}%xoqv;c#l} 㭒xTNvC|øC|xW$0*sԧ_qky>zXoM89v7 sRLu>`,bN/rv9y',0~}2Pq82|#~]]s>lq}6.E6]}ξٵϮ:zZo\M8d8kwp84M:qk9 ,]Yx@gZyW1} ZÿGwu@a=;rscW~#٧:ُ7g#k֛a韈C84qk f?:{kg} 3o-HT>U7 ]> AaBDSs~v9^Ξtv炭g M8|" w8|f #m}m;O |qv? ֛pXm Վ?pXmwy"W9q? ,qx:{y6MX^a;=78FS7lO!߰GBa[}J]>A@Kpsgog7zބ'7Iw8|27ᓦyIOjYW>ٵv? vH %^@ۉg}(mNCaG{ö9=7g_g7 8ބ֛p8!7nd8kXtIgZy>¶S6ަ-ͺis muN!߰GrRs&է[9xg>5l= 7#7#ǡF8ur>Y-ξ'cJkSyrNQ^a`k7 vM|v]x1T;-owz}î>wsv?[SބçS)çLSӝSۿ/r]kgv=Wd}8 *~Jo.%~KTD~Dէ;TOwZg>sv[`= 7pANa8\`wp4.p]@{NtҝC}kvpm` -K;g3ŏ>Ea;}|v8/>˴O]p(]9tgl=qhqhq8وC< ,֧5Kwvήۅ~x3oڄo uo vN4?|t/Aa{KDwazZ}}]l0l= O[o֛pCx>mwpi8|}wڮ_ ^쫝]k\"nCRA]i !߰3|#8G>Q{sp3viíξ'c_}6pNÅ֛pz&3,4 nÅC w;{ٵv w9/ayg'Tp))r녽Zlgٵ[FZoFZoF; 3yh%sݜkb9=ayù8ܜ bgnv2>vVD;է\ggEqgM8|zqwϘ8وj=QfiZgZFY`μZ&,p7aO7)7ߤ ߰Cy{AC}}O}n]lֳpzYo"w(7"Ey6kk XZetgZF9v1ay&F>3SAGLa2:K{AuaW6vv?[ bM8\v7 M_{\sxXY|-sv]sz1gKWpK*h:o!dB$0t0V?Ci[[ږF( QY@1 J@&{=>>;q|nVc 쀾)Ia[?^ѭe/W>l&&]Y0|Wj ߕw»2r6 gר)t>uLvAcϛ4ϓlV4dx 0G|mG|mqs1#IgØ0|i_CRl6]Jm:Rab"c(g<` !_ihK:Ik[hy{m wXfi6AYG I`6335Է@)gm-hY0\ 6p:CX .(.1T.XgkC^j@P~ٺ6I^4{8 y6m6U1#ͦ3ƭx~u1D϶y,.ÅR`P!, ,.̏.T.X {󅼗yakByœli32\VS|m3>tH|f?0=/T>l hYPj1t "1\$g`Hf0\R߇4u%t).{f=6I]IwMwMnb3}$9%q'gX:MG-,ǔ>^Zj D Im"uHPfCy*=.>4 ˕^v MnI^6oC#^|`k`kR1|w0r|wpl*nu*}R`Xj G 32b92bq潴4ʟ|^Ccϛ'yg}Ӛ HG`Zw _w _<[4&4p1s|v+Kݿ_j HmM0\Kl KԳ [ೄR|Syƞ7y'y}2, $E>+g?OM秱Va'SӔ?]_fCMPj1TgKdq l11T.X$,5/@'(yAcϛ|͓lf`aLiw _ۜAy7ߣ!wۜGs7Y-{)g3ZBG JmRM0\DLKl KxVL.T~y2Ҡm>ȓl}2)K)6FnU>Oiyui)5fԥ?|ٶSM{R`&' 3d{2{ǵ4m'+׮-akO-Xo& -szs3mf?ϰC5 ʟ|RԦc(3dq l :Q27C^3Tg)׮CMhyI^w1LC>)|MiB>s>7>7í38>#e?AeR`Lj 3eer6x^/Q>]G˰M$/27'!斎|@ kS8 _9cGR&1ƭ* gv$,(}hY0\G Kmru\0\.g`\f0\>Yųu,潴Qʟ|^AcϛKO)/!?_Ny |q WM*)T m [:.N;V~g;a\j1&bB! W, Wg`넽 K;af^O넽 yS{M7n&oө|G>'"QLZAiQ;q뷨0ۇ:; z'+? -5 +6CMP!1YPfP=`E)V.4oW.E]O-OC-OD>ܧ _ۂk[ܥbXݶ`֯Oz>UhOYgz Zj6ݿ_j Wg,/3]>{\AUK.Cce[蛮pn`^!!k[,!,*XA߱[m<ÜY9)D9MJ1\) +6pejd?`Rfp<`2Wų4g/+.g4-ymq79;Z`r>3Ƒmg#_۲3pmg[Vyx b?C7AK:RԦcV*28+o6 v]Gk}+4-xm71-tH><ږ<ږU ?OA%?O_:Oh_g/hY0,BM0,Tg2a͂aaAİP==ǿy/1H[k?ۓl|23畐-gO.w wےX??aOwY=_T},hY0@j ?~9dU<{\ϗy/2dOU>]Wm'yٖ{}2<0=K>ɧ+ ]b  Y=_gԬcXJm: C9U2Q*м|:K4-zm g [9!V~&Lk[T11}0ƭ*7aYnGg=*Y0\% "*p:28TtJ_|^؇žO~3G|m+ VT 1m+>c<~g&C֩ +?[hY0Pj ?‡2r6 g|oa>R R>Cy[˓lu+pG`#_ۊGawA"wۊ2YB+gu 6p&Vger6 e@*?OvBc'y:1LmA}B>CgVL3FnSyO0լ\OVOQT ]1\-Jm:E?:28e*=.w.4凉kL} {Ow& LkSy|m/TTƠ.xCnJ>;$ Zj HmM0\kypzv!͠y/ @˕k794$/7!U҄|6|ML>[T^Ơc[kkXCؚR)}vX+5 k6p&Ugkeõr6 kZ삵qCZK࿱ʟ|^!oCcϛzl0|=df獐O|m|mZ]fa[?-9P7ֲN⾷vg)}v(kfCMPj1TgkKC9u eu&_7u}o]c(n(MkI^6o~620CyKi;t?, "6p:CX'Y0\'3c\ų ={O*yƞ7AOi=d8|k!k 'u1#i _p#YE&g=-5 ER`XG B?`X$g`X$3g {aO@OU4 94i=˦0>+x`Y^iNiNiT0۴kq_g8YӠ(򋨟u 6CMP!l ճ ֧oV~/ =oweS}c10ß "%нg9t31#C~x#z(gG| -5 6p&Wgeq l11T.X7t)u t+k7(4=˦c2 b2p|m:)צOS1ܧ w}Jl*QL:IOQ>쨺~p&n  29 2i*=nT=hKGՇڍj=o:)˦/ͨZd>0jώ;C>צbRnG0>nC5Pv(gGaoAj 7JmFM0ܨ6S#eÍFa﶑Qנ?^vCcϛ^I^M`x)dغ|i݌|v@'n*@5o0 >4$tig;-5Jm:R:C(c(gab]=.Ҽ/MBly5kw{m=˶囼22/|mL~Pݶ;c2bI9|1bM0,buPD l e7мyzW+ndhy[?I^?}2|50c~N>|m=|y1#W2ƭ_Yw~] y$lMMR`I!l 7,n 7WqwVB^zEʟ|^;Qm'y֟dX;&"_ۚ׶x|8r1]u 6RP!l1YPf0ܬ]=?@^C{絻hye ې50wM%!kS=PŌd 7*FYw7ϧ^~,nR`Y!l 7,n1T.\ĿһBV!ݝ=7ړo;h)nk=Zy31#?W<{uzT%!T>or,n-R`E!l ,n glao ޖiAv-z$/ͽ!C,voɇg2[3k*sƠxqgxgYB*g;]Jm:R` '2V9í2VOųwN@R|^Ћb$/ÌFOF )nI>[vAhƸ3:3|C?IgnhY0* [6CuUǰH11T.w=м W*{M6y3:z'݁x(|m3 zy1#ØgP:|Ct=>-5 ۤ6p&nSgdmr6 ۂ6mqeB^PS>CYf _>p,nR`]!lOnY0.3nU<{ఝ҇[CW={z;k hYǰH1t vC9u eq +U<{SN҉7AT~M=ofuOz0|G>C>f CT8ƠdA}>Zj ?ÏG ##9ÏdÏxGA^Hj+fI^6W>Go!k3N>>?T Âm&[vN)>ȏ3-5 ;6p&Pg;dr6 ;d;6C^Iʟ|^GBcϛ9Ǔlf;K;GO%*0̓aLlS |u8s?O,Ԭc(Jm: a?͂NypzvNǟN)y^I^M=v ~׺c!k@?bf H0ƭxz u_:o|IfcM0Xj ?VgG ? ?V.=nRhK' ~A3k7i 4mzmSI\Lgvm C>׶ |mU*A#wۆAp+Eρ.R~g' -5Jm.M0ܥvl wF wgb4肋 }W>סmՓl/|32&0gӎ|m~67,~,~ݭU;O:}z?dOQ>fpԦc(3]E:28*=Oy/} tGn^QͪI^6o2ψY#g (CƠd֟0x>4x:K>̇R`[! w, wTqм )y킅fȓlo}M# , ڬ8:co3|v2|OA(T$쑚=R`'5bG! , WqN٧Q{7fI^6koLȇ`G6`G6DŜb HVy[xϹBPLPOu 6CMP!1YPfP=`4k晽f$/۶oo6s=cV!kۦL4g wۖqp&{Y3qۛg^Y0+ {6p:C+Y0+3U.+6Q㾷X;k7ýI^݁{][ _ۖ6׶bxnm[֯rn`ʿg_}}RΗ}~d?`Ofp<`0hK_tkNQ~|^G@c)Omg:d-,!K:{*fMm۵aLlu gՅ_@]z(}vVhYPj1ty3}2aJef5tV#Q>, =o"Om tR`f mI!_ۮGmgUy,=Nga?_(}v6hY0/ 6p:C/c(gab]=nvhKg}]r=oe`9dn4l!~v~bd H8K3MKn$Ͼ",R`x@!ȏY0< 3T<{Ky/}%ʟ|^^ƞDOf&0pN`^;׶wm7_Ŭ` H_eg<zw(}qR`~" 3OdOl ?м|^ƞ]'yvy\hw&0/} k!׶Ŵ;mw.Wy+N_ =Ug_Ɇu 6"P!|"c(ghY0<( 6:C8(Y0<(3T.8XW(PvlƞeOudg)"|7bn8npn6f٘)\쳳1oCR`xHj 3C2!9C2!Cq1ʧ\}?|^٘a~'yh~|*ȧ CU1W>j[Z<9NԁgPb(Jm:?:2(0{ܜzм|u8I絛0{9avwE _awE;Tap8O>;3aY0<, 6:C8,.1T.87g 4s0_ޡ絛0F{[0H|x|m9 _?*gvCl*g u]&S&(} R`&~* 3OeOl ?͏~]){ܫ?Cʟ|^WƞÛe;l tԫ?$>|.渊ޑ֯,WOg% >ihYPj1t 1<"g`xDf0<^ W+sOvƞyOoS!ÎSؑ|Cw"B*cG: c3|i/LTcg} #R`x bxDj 3#28r6Wq_5#?|^=oe;>xn3τ|,<;cG:1n jiEIS>[y,HmaI~İD!%r6 %2atW~Q{iElU>]%v'yَ}SgHv:?|m!k;~b1}qƸOTa(aJv+KBK͂QM0<* GQ͂QyzvQ4)y ƞc'yNuafS"_ۉESoo޺;U+N__ =Mӕ>z!Ԭc(Jm: ?:28G^$|fWA'(y^{N9e;7 Ç~I>ӡT1g H?1xog{)gx:?b&~& dl ? ?xZӠ _|^7ƞ3e;ӊߍ|7 6N|kl] KPyϾI\j ?ϥ6su?`1\f0\=s7͉Џ)y|{N=v7ΉyOSݐ|C7R1'r=O~V :(g:VRΗtԦc>1Y0]:2,U.(e; ҹX4UY絛;{Ωe;\cw<ߧ _ۙOA*OA3[S޺>;+g-5 R`X*RgR9u eq T<{[Ky/}_|^(Şe;[|Ty̳Ak;l+UƠt~q'N$(}R`x̏c ?`xLf<`xlg{ s1K*{ {cvI^Y0hYPj qup\0<.g`x\f0<]p=my/}7|^8=ovO}6߹>g5)y1#1{ӷ7AORdԛfԦc(328r6g/{[+r{{c'y!_'dffffb[3n[U~k6Yf@{R>BK͂ M0;YvI^߼tw.>]}$kLP1va`b} ÏNg]1ԬcXJm: ?͂)yT({]м. l-=oן{:d{ግ|mWv]b8c#wە3vl*3g.}>%hY0<% "):28 {WK_|^EyٮE vC-/z1Ӎ|m722rXnnUjyqI(g.NnOn-5 R`X. \0,Y0, ճ м.n=Ck8{nee tp\`7'C>v'|mAc?grˋUK\R&~) _3/e/l  T.=n]|kĭ=oG=v{7!ùY2||lkv[b|lnر<{<ӥ(g ]1Rj1t \r6r^.tBˑDi^Γl1<ϵݮTAɹ%qԊg<~*uWV>nR`xZj OKmiupZ0<D Oճ N-ρtyw_|^=ͩI^6'7wDaN,B>~ڜA }1q돍gNwA*L+&f+M0Jj Rg__,~G Sq+~{C+yV =o8O9S|/<8j@6j@6_*fcGr^ cbNGjg)}}įfCMPj1Tg_*r6[,+Gϭ}܊OQ>s)$/S_$=y|9J>?S1_2}$t[x+g#p)}v埠f"VHma:C +l +dq xӡy/]g߭|^ƞ7“l[}rZȰ{z`V>葯葯Y3zn3z~*:-<}=Ϙ?>[xZj Hm?bxF! , LTq_C^Z TOS>]hy$/!!'Sx|l@5A q-;NWrf+RԦc(332Y9ó2Y삳[tgKvp<=o{^O>g YWe H˜3\ gY1S}@>|JͺM0<+bYC9u eq ճ βǭ\zeʯP>j>K= zhȧ%|mK-TLcGze .-Xk03KR~g`8G Im9M0<19'r<'g`xNf0<7Mųǭr5=g)@vkzAcۣ'y:dh`t#B>uST ńm>) ׺Cuo߭|ٵ}f& ?`x>5bx^f0<]p=nm_hKSxڭ=o?z7!õYۋ|`k{HໃcWywN~(g׮u 6CMP!1YǰT1Pqk@^vID5kv4={Z1Z^*ӓ|mO2=[2r=YnUjyݓY~^g],~- _Km b͂2*=nݯy/]7zW+nD-3/soCfdy8|mωGTdƠcOUax>turW(}vw&Y0&5b&~ Y0Ff0fg[=4n@OT$!okO=ëd|χS|*רA-=aѿNfBV~g-5Jm::CFPfCyzvB^Z}Dž{+=oϏ<7!SO/~f|m/~f|m* cGz5 c u~/8W~>>hY0 6:C ^Y0 3c]pk?4@V!ڭ{^<s~$|m{g<}*gA(c3p >t P5> Zj +6Rj +B?`X)g`X)3VgTm:> =M/(n)hy{=I^+ ̆,S!k{P1~rnugЅ_|ٍB*R&^42E9Ë2EOųm| ҍCR|^O@ck'y^؀nHWc!_ۛCw ӈ1#m8aSc~1OR>l1f&^t E"PfP="{\_y/-~B+I=o[=bĞ{+}{+V֯ފM/N7aο|O쳛0o_KR`xIj /3K2%9KA *=nKn\}@k %y{?I^|2|-0z%zYޅqp?N7z)}v3%Y0Vj o·ol  U<{C^y6cf{ޫ<7޸hg|w葯S]w}~->t忠|-f"Pj1Tg٬c(3cXf.^e0tM7P>ݖ\hy4$/go  ̖!_ۇߝCϏT ;m~w.~mu+}v+R`xYj / ?`xYf<`xY=2{мn^j+n+P'y>/&\[pn`|}}~m~[z~u>ʯ+:Zj HmM0Wl WԳ omCORmYI^j:dZvoȧ/kھekVW1en}6{WX0k]yʗx`WfCMPj1TgWdq l Wճ m+NS~m; rG-3/}9,[0싾S˾|m_ekޥbؗ˾[J_޾>t; W'(nj1* W6jb"^YPfǰXųm*۱zH~{޾o}R}_ v+!kI>@U1wnc/gQIfBQ~~tZj Im5M0#dk>:{G_ChyI^ |TAgg.葻|Fh\kE/V>CR&^ ?`x]fzjz04;>?\v;@cۯ'y~}cد_`v|B>ȧz8CP1>0&uz(}v&hY0.Jm: zb(gAK͂w6;u?`͂w2w3U<{ˠy/x9+'y~{}2<0/!~|5*T ߱|Jl*5>t׫%/U>LR`&~1^!|/~/g`<`zvq y/:=@vހƞUO}{n(]|?u~|m~|m~*mֻ[x[g΀/΄u 6CMP!|/c(gtKЗD>ech6BKmIgA3hK̆@v{@cۿ“&`, h >>ҀNs3\V1}c1.w;_i N_@G_|ٽu 6CM0:CH42M&bx<`xSěNt;(?Gv{=e<꛽Ҁ)# x|@O#%ϫA~.\ʻ:tP>UR`x&$ 7Eg7٬cXPq>tjR+nhyۓ~}k|J>@Q1'>2c ?hN? XIg?Zj Ima5M0!$VˏVY0&3V T<{Gy/3ʟ|^Bc;KO:p`Z`?>/kuځTLoƠ ?o<jj[CP/դfVBbu͂auyzg;WhK=\kwoI^vþ9Nlg3*Ơ {wL:=Xz -5Jm:EatX]PfCyrwhKւ kw64I^vL$9x3 _; Ax"_ϰ|iIwl(ߧ-5 R` Bb?` g` 3&V[=y/-D+ =/봤Lg-$&J͂a&&Jmabt(&,&T<{\i|ꯠPc+ƞ$/ Os|~I>eOO9dzGg&Q{YG;g)g$)RԦcX٬c(3ޜwfKwܜTEO{^YOBeOW(k3z?|axmm?N쳥ffM0Yj oo o.,3cXJC^Zz+׮#4O @3]gPӐ򵃒gt3zGvݭ?( CAnfba"FgK/!5 56&ֈk5l kG k5\*f cG=o|?@kPhYPj1t 3Ě&bXSf<`X3Uų{cB(y==zoCs䳊|CH>ЫUƠ }Y =Q)}R`X bXSj kFg5eq l11ܯ?hK?];{`Mym$/;oc o90C>5 _{[#y ڪAcm Oaoa:Eg=ChY0Ej oɏޢn oY0Ef0eg;q4'&@V\ڝ4ymoN80'ƓO{-|aF60>D nW~)QhY0% 6:C%֒Y0%3}Ϡy/=98OP>݉Rhyo'yOp !g7jFle m`| PuZ4OW>lZRԦc(3Z28r6Wqejj3_Gvesjc{Geo꛲Bє -LnbZ1}dpӪ0\uZ)}:?bX[j kKma bR[0-g`X[f0=WųǕmfB)׮l 4=F_/m N/#_;qþ`UKAW(gOZXGj HmaM0z:2a *=dchKO '+dhy/3/;]ߜ9S]L>7݌A-\o hYPj1t BC9ú&bX7zvAb]Sм\7UY;=}esoN9KusPM _ی|B' Ơf1n6U.:=z'(}{R`XWj Jma]uP bXWfCy"wj4不CW~yNƞ77˓lx0g?~>ks' O>Ƹ+<>__g1Փz~İ&Sgdzr6 dzU<{\9B=K1՛+G難=oTO}2\O ]*fcGrw3ƭ 3YW+H硥fCM0o"B}͂a}y~g+o)?WvI^6Cj<ĒjS}Ie Ȑ0ƭ?$=fYCORd)R`X_j1t B}C9u eq KT|)V hKO>ˑ߀t+hǪ'y!c|2;0'|7y|&COT1O2}dHnp*x>hOYg-5 6&6Pg dr6 d3T<{\Ż *%yʓ|SweY._;|?P1ŌA1n L:=!(}̯MbC1l( 6ajĤ?`Pf<`0Wųǝ{陧'(?_vg~=-eTЛsZ|A%z*cG&1nͫ0?P>fCMPj1Tg eq KCy*= ؈RܢQ~cڝ {ޡ)ekd8|O|H̀~PLb U|>|鹆оs>{v#Y0l$ 6:Ch$6Y0lT1l@ųǝ<߈s)yan='=s9׀|<|Х Yk֯NϯTȷ fJmC1r6 Vf0*=м_=YSkwChyyz7WsH>7e*{jnqOVf\^ .y_| cfRPj1TgV͂acy~Q|c cy/0:K絻p;4n$/;oc ̅<̃|@W11}dXp3^1봲-=W>le;hY0l, "BcWc9u eq xмVv.Q~y*;Bc;~OJ~2Ta _;-ɇ~[ża_^aIuZy+?+hY0Uj o[­2r6 NUV4凌oY絫< =ea9~ >_Olg>k} 1#k1l狘ne^uk*}"[fCM0l" MB͂ayIgyO:Wy絻=ry$/;|o.2>*0ɧ. =AŰw#w;;~g;_|g(g/= ]1l"Jm:E?:28e*=sм^}9okwyhy?I^vL\SoU!k/$ЋTA*a"hyG$/;o. sCE>yS=ZL` Ȉ?gx'N zg)}thYPj1t BRb(g<`D+n]+4#$/;O< ̕?k!kG,U ^|ՌuzÕ|٫w@K͂a bLj 3f2a39f28U<{м^zw+ؓ#: svAvD%A_bFƠ1XdxN&gyR`, ~0Y!$r6 2aDw-kS?Mv0&c;'yّ}c8W``kGQ1]vqWyoNUB/QrQ_u 6CMP!$l ͣg$6Oߺ{oKv.Cc;O#ߐ_|@H>ˡg7>2rn[ cFm:~OT>R`\j Kmasu\PfCy*=Х`ҼL絻~{ޑoy7y=$0yF=Tڑ3KSֿ^::I)gqڏHma&GLRd9y0eg 47BR~ynƞw䷞eGu͍!Qsc_gTnQCB>׎bng Ȩ0돺#a?ޡg Zj [Hma M0lZ-R#-dT<{\мV絫n-5ޓ쨿&|uZm'N:EvT ǐ3kׂuZS@Ӕ>[Ԭc(Jm: ?:ag^{i&5kW3hyG-$/; T?Da.|g(&cGj1n: g&:G>=TKY0l) -6:ChD [, [x7[.Wj%`{޼e&z0ߑϏB>|Vs֮uZ;\gh[I͂aԈa+M0lZl [ƫx7C^ZDOR>]=I^6%@ L䳔|ʡ# e*f-cGօ10uZ;/P>lfCMǰT1Tgdq l1 SkFqo@^ +15Ey=ozOy6JF _;@U1> r}xuނ:3z+?hY0LTM0LUg2a͂a]I^vY4gL>5g5tM w;'q돩Q|SЏ)gm9,KmaԦceq CyC*=~ {= ]JٯLbky4$/;fo!10Ȝ$]H._;31#cw!WyRN:UgOR`Zj [32ak9Aİ *=/y/mKS>]''y1 t4~|||<*@v [u<& ZN_>ۤ,zR`ImԈ'g`Ԇ潴IʿGvMBc;f'y1G|Ӥ&ó/k 1C>׎A*&1#cG13Lƿ?u~Og3f0Cj 3a:CȐ 3l 3dqkgKF4Ы_|^;;֓_:d8-0c!k :Sf 9qϰ ++23 u!,fJma&f3L0Sf0Sf䛩]Ͽ4-VAORڵ{ޱy7-]ӂ߀#_;GvA߀#w;_7i?gNpOΜyʗRԦc(3LC962aQ|_AR?)y~ r“IEp\239̅N!y-TLcGƅ\?;җg/{>%M1l# m6Mb"YPfǰXųǥ㿥6}HKGw\{O:d%=܂|8-׎cG=f63ߝn]G >-5 YR`% Y !K0ʏfYYq-y/l g*.4xo2]qs C|*f5cGƭa[` _t t>(Ԭc( m6:Ch+Y0l1l]Ж=gмWpڵ/ƞw:O>M{^oWi⍻D>EߒO1(A=!qߞϰYgCOVv-5 m6CMP!-R l11,Uq_潴kЕʿx:@c{͞eoMCw LWg@h_s|noG3v>qAݰj'5 #6:Ch'Y0l'3a׎nǵ%V=c<>7Ln|C>g8_Ƹ_gY ]RiK͂a{M0l1ll 퇫x潴Q㫪kRݴڴgyA!dp 2$ "Df[E"*Z-E-ZT=g|wZ{s﹅ݱgq<ˎ{7!C!w _;-s1#wӅ-N`οmW+zԬc(Jm:6Cu eq /ݟKT5 X 3︿{Mlef@K' imMlmg~Zl3Ϻ.ӁxtIQH,v.R`E!t ,v U[6')w7C̛نyٴ s3L Okӊg$tSƸ~Oj$!!we2:9ư&vî~IW͂aWykg2!uϽR3oZ'yٴ59m ̐硟! {U kmk]xCk+5U>PuWYPj1t BWvcx<`xzwqC@Y:t+tV>n6hy^$/@ ?V|@I>{/b/a Hz0ƭ~i;ChY0>ɰ&vWwer7 eU<{,1H*{7hyӷ{M?3 $T̿>0&ލs\w8CuoP~|ٻq.5Jm:mC.c(w<)w7n, 1G߃{w?qM?I^6ㇾD0v'Wڌ@Q1>cG2߬14NGwf&?`Cf<`cou14/ޫލ3o0OE9dTf4?ÐA6cnR13}$cc:IR>R`Sj {JmaOuS0)w`Sf0]Г=nyЅ/U>n8f$/ 0baLtu:&z7*}vL>tb(Jm:튉?:2a^qc0tL'+{7sl/y3I^6(LS|2yNA6k3bxNA6~f9%}@V~g~ -5 6&Rwd^1dq ջ zǥ]gi}DǔϽKgLSaN`Ғɇ߁B6߁B6Hfo/i:ΞG >3ioY0- 6C-Y01]Л=.~h>KӗA_|]rhy3gy|7pG`ψ|m&S1< rK3{+wq,,þþ?`Wf<`W/{\Ϡ,9FoU>.{4μYye:d:0ϐ'|m'|m*ߓB6ߓ=Y9+*۩WAK͂a?M0' B?͂a?y ™9A*?G̛ܻ'y٬ ty|> gY_Ơd;>:`[D:CK:RԦcݬc(3c]Џ=nwM:mAϽ3oeqNpU0 d|m6)fQ1< ws[?;2q|R|ىeБR`_j 1&er7 e[U<{rh _mMƙ7{'yɾ \ݠb3}${ cKbN9Y|/MR`x&! w;;d;;d;Ի `˽giWХʯV>.khy$/orϓ/9|B$O_R1< wͳLt 1:yVoU>l>)wH:RԦc1Y0`b w `yd8 HV2g 9ml|mΥ* r9m9 ͤYAg(?G쳓^R`8@j ;1n11lSq^tҫǔBܻIqlülL$v^͂|m͂|mNYY'% >4I1|fhY0Áa?`8Pfp<`8ZųE@Y DϽlƙ7g'yٜ%r L|ZC><A6ggege?ϰN (MR&F[RwdAr7 dA jAR~wC̛דl"?e,9E6=;Xnsx]?vr|ʯV~@Zj Im:RC$c(w< ?-П(|̽ڱ:I^vվ39Av|wb1}d0ƭ?xS=hyݓK=d83w#_;`GvOT  3:-z W~gpKj û6.up?`x͂]1wwW 4E{۔Xܻgq͓l&!!k'TO ti` ȄFƸ3:>tj9埏>zhY06ЗC_!~/w`~DųMgԹoP>nj4μ|3ngk'R1w v iw*gZj1lW 6Cu, ta+h>KfwW>nhy''y 8L2DSs /U1< w;ĄsJq|i\G>[3Y0" CZc ;!2u eq ջ BYZ?|]1ΡCp杈s 8'd8qx`Ǔ]|Dډi*&1#֟pƷLPoC_OZj JmPM0Cn CT|?*h>Kg|z){7B;1I^vbof| f6|u!k'W1[>2qc\uZC?|ْ+fCM0& 0p͂0ypzw00{7,EϽ+a8NI^vaߔ\NLI'i'Ca>20& gS~gCt 66DPfCyÓ*=h>K@QSweq'y\뛲>! A6 4@wU1>{Gϰ~2u-twW>l9zt,Hma&;0%1L SԻ R1YZ^GϽ+GN7w'yߔאay`g\&sU"Ơ.f[I<ÊMYO@+g+6R`8\j Kmpu0\0.w`8܏1]0=b 4[#/V>b4μK=Mmr|47h}Y7hoDO IY W+g+q.5Jm:RCޮݬc(3mbwU@YZU>r4μI^6ST!üS9?yW:o0}$a[?xUN>g/,- w;eûn 1ܧCYZ9aU> hy~I^6oox|m`P1E6w`ѿfV}!01l5Y0! #a?`8Bfp<`8B`{\5>KG4(Eܻj8M$/jS͞&#_&#_y2A6oc9uZ3ߧ6CK:RԦcF#n G#ջ F&gisݕ_ܻjMF̛Ǔlp/gɇC6C6ﴊ'>ft>[S-5 #6p&Tw#eq n11T.WS N]}RgϽ)ƙ7￞eMMq0Lw _߃|{Aɿ1X?gM=ӚQgڏ1Gj {"1&,#3Ӣj>泴_ߪ|]Ϳq=OódX>ܐ !kU Ӈm>]xGo*}vQj {6^up?`xor2U<{lgl?Zv̛̓l= _ ~|BN1# cgX{|im@-gMu 6CMP!+]f]튡zwqCYZ{Iebvƙ7ϞeM-?=֓AvȧjSƠL>qO uZ>toW>l)hY0% 6pCY0%3jUq,z({W{gI7xt/=KP49|)B{Zn'6~e<úN0ۏ:gk5IfptrhM0Fn G3T<{\G,ht+Ͻe4μ,9Xk'S1,r9 τ:φިV@K:RabFݬc(3ާ]p{\xh>K'@_|Oܻ8N:I^vG~OLC6w!_b4n#|g[?δFc6t_3^ -5 Im}R`xCO0Of>yCg-泴q)QW>~hy#$/ƖaLB{=FS1n# ,|i1bgm|;Fj HmM0cn cԻ ư5a~Pc~Ӣ5=3od'y4,Łi{W"|8*E6F"|NJu:߱گg+R&51&ceñr7 ceñgVc,Vc+W>n>ř7ٓlo f +>bxA6³Lt _~ Tgm~Zj JmXMP!1lS eq xAY|){I_yle2,|8S-x*'A'qg+|n>;,Jma&;T0Uf051LU.He[҅=[Sܻq-I^`oCYx;L _[0|<31#q3\~:]gu1W>"nrhy ="~ǧ`{`;|3|3?W1|3r|stw;/qyN\(gu CMP!ǭ)w ̒s>|mXd!r;nɗ3\Oӥ)W>f0Mj ӂ4u&JY0L Ի |gR(wKq~IÙwrGOo tށYz|Ik'NbIn'! sTt}s1?Pc>LtM0Ltu.,YxY ϐ ){ 53䱞e'fsd{MN^bc:H<7g zw*_ou 6CMP!,fW3VL}+.ޭ Ɠ|2<7M {ɜ럈gQ~g? 0Cj 360U1 3n11KW~ەϽ[y4μ$/;o2ri`*3Av ?K|縉0}dO\p4PF2;)JϮBdJ͂a&fJmaCȔ 3#12afg[torV>nr&μSn8Nғl`a-s.S;|maW aC 34>tS +}vSIʑM0I1Qw92a͂a<`]i4"й/T>nS4μ)e fkVXMY!M B򵅍*&m!M*~¿Im-:ZJJ=Zj1t 6Cu#c(wtOS?R;R`8^j ǫ;2x2*^<6j{)w;oƙ-Ofg2^Ο|YbkYbk.U1-/J,YBW?}vw? R`8Aj '1&d r7 d *=nwh>Kw]@ܻq-ړlQ_2,}g K>SU ">HtxOoJ8U>ӛfCMPj1TwdÉ&p<`8XD[,} .|ӛq-$/[蛧7y,r-r-Zb63}hK]k:B>Zj 'JmDM0&ݬcئwLd{Ih>KݮS=gޢme^ th`N>|E|EoSA): Ie>mʿF] -5 R`+ !7c+w`+3*=,};ЫQܻ,4μEgNB>NA39NgrS{3_u(}v,n\hy$/;57Y⩑焧aR9]b>2>?'N5(?P>쁟@K:Rabdq n11T.c;y .1?{w:gީs=N}7#9c#_;F~Jj>Gv*>~¿ѿ=-5 R`/ !_0̗Y0̗ ջ [g~WϽ{Zhy$/;o^+0/\M>B>N|zCv)cG]?8N_%IR> 2Ifp&NIa?`8Ifp<`8)UųǽkB*{ 8NI^vZW0|>d8m'sn9=BN獣g$0 >^g}ѭӦJm:Rab"c(w<`ǽ h>K_'+{7q杖I^vZ~E kYAvڃ!cG=Dϰ0|uOU>lf0" M0;?`}Fdq x#|}DǔϽk{gie7mF> _;/ WcGx1DXk L/|كxH͂a&HmaC( n "1q ({wy$/[m@G_C>7|-9SbnQ1Aw;n NF_ fCMPj1TwMd2dwp24@V sB[ϓl1tȰ|&b;u*1#-aLt _ryN_r+T/ɭ16pC,[SfCyT<{Kc,})?Q>q8/$/[7/ߗ1;.܂|m1kb7['fS&i *?Y쳇@K͂M01,N wLa;tCBoTVs}3o=CB/ ̡!=)k[{RN'Y/>co~Zj 6Pj B?`X(w`X(3w~g?NU~w/ƙw~-_|WCK:RԦc eq n11DųǽrI*2;(w ƙwdO+y߫;kN[U  3|5:}utR>Б"M0,â ƤH0,Y0, xW[s!~){"hy̓Հ wl9wl"_;X̌A?ک1kU'g}3TY0* S6pC*Nc SsT<{ܫգХʯV>շqq'y8@G9#s 3xNAvzGv=~90潩Ø*gc*5Jm:RC*c(w`8Nwi|ƹxZoV>0p杁s 3f03sg||BR1>2cc]gniR`8Mj ;i1n11lSqfc?|-8xܓ60w+f>Č!kg|rbe Ȍ?kN_ S1wR>kmf؏1,buP,,*=50|xW){fbyg$/[skmJpNysK )ז|m-*nKxNq$S^? u{ߦ|߇u 6p1n ջ ǽ,}4 ({:z:μ%80/[O! %U*m $~S<#NP~R`8]j1t tCu eq ջ gП(|̟;yfcx-s;sזsז1}H]sN4@{ʿYGfp&ΐa?`8Cfp<`8cg;2 z(_r<3gޒ7=˖ 37SUkKy|m*{A)1X/gyO(}aTbb K6Dj KcLJdy$Eųy #C(?|3%8~ߓl]`rȰt4B>s:|N@W1A)- cOgƕ@/W*ϾafCMPj1Tw%28튡t bn2t=uzEߣ|٣u CMP!,cqG۠,=[蛕]ܻq-K$/[V㛣pA`@>+g'zy1#e˜u|[7A*?|ٷnrM0,o1,Ww2a:28qog[BPIs޺ g޲<˖䛷y/gE-gE-{["ݖ">+%&i&KT~g'S_-5 36p&Tw3eÙr7 3eÙ3YCYv'U_|߂ƙ'y|eX~u`)w-w-T m9/O;NY }H>R&VHmaC +n +dÊ*=e>rV>8$/[waA`YB>s|Cr.xYW:}ϙ:7(}]<*Zc +6CMǰM11YPfg{Ϸ >K} |̯41{!hy<˖ tp{` ;ז;ז\,m92>LF.]]JM0JuP)[31ǭ]PXh>KOޣ}޽?gz-oI B>ז|C&cGfv` ֟ONO{?|xVWI͂a&VImaCyU,V1UUqo4ZUDޝF™wŞeg^(ÙszH>Ѓ$`hFv&9 ?:=1jS>OfCMPj1TwU튡:2,w_|7tg_|@;s'yٙx #g#_;~"w;6N?=R>AOhY0ΒYa?`8Kfp<>A/h>K? }XGϽ4μ3yy7fkw23| GcGf1n3<,4 1j3R`X- ~aC n ejj3|ɄnP~wgqyғlž9293.Sq\qڊd"w[+&05|*ۨ瘟fCMPj1Tw2a͂a<`X]P? g>K`6ޝP3oe+d"_["_[Qb9Xn+9 =s ,5/V>YjfFj k6F!ݬc(3cxTųǝg?|.8V$/[7go$'s&A9)뿔A4uzakgϮc gKmlM01-ΖY0-3nQqguoU>Zhy+y8 !``:S{Zn+yO֯LY̥ۨ_>g=*,Jma&֪;Z69ưVf0U.e;{ҳAV~wg_ƙ'yPȰ?*yo|m%mbxom%m'|Xuat~X -5Jm:RC1Yǰ]1T.e g_[uϽgtO򲕳|2 LYAr9@P1>R>h<ÏjN?gZj 6Nj B]cX'w`X'3ֵx,h>P>8Vn$/[|VT GDB>V'YϐoE/a;|G>g&^j c 6^!r7 2a}g$4 ] s>zg=V]!êNȧ|m ڪrU-$~Uo!}b~r٨V~rԬc(+^:2`9s>ƹxcޛs=s>yyμUO|z|2_3}c/3<>V4C̟QAK͂\M0+ s\p͂\ypng;:ݢޝ 3oՋeB>\sV}!w;sJܧCN?_>i tb(JmaI?` w` 36x*=SgX}s>3K<κ7Qӡw5 _;j@v08#w;q3G/.U~g?&ԬEj";6PfP=|~}VϽbԈ3qega̐!fϾA>mY+T gngq0ۜ uz)}<5J:- R`بeF ưQ=[;تޝw.μ00/;ko%×s~QFAv>2oq=YgBSq~-5 6gYeCWO8U̍A)qW <yK\_\-5)RC'c(w<9EGgBwT}q4μշx7_t |D>|8|8Յ*G/g~ A>R`$ MAaCh n d&&/CY/(w_ g*Oի|>2|,0_>G> ջT ?om5?o]?6pkb^埋Q*%އu 6CMP!28r7 e|2?=b.}l<웯 k;C>5>lB>;>R3&q׌g5ja>_C(?W_b Km|M0ߪn11<~ү_>vs 4μ5ekf:dE>C>,!\*f5cGja[MA6YDO}vh)g/B[ 5Jma&6;fYf99ưY="]3a}T>"mƙ}O/E΁{kg?Q1Av6mm._Ӌ]:^GhY0lt 6Cuܦݬc(3cخ.4> 1{wq͓|2OQSɧzb YaLtxL:$fwQ>%yR`1lu",-U<{%|^2 z*{wIg5eg tpk`.H>>#}Fkg?b01a'N;n>vvjJ͂BM0\cP!, ,. w,d Ҏۡs_|]8'y tT`:n& si,0}a[x>uzЫZԫfCMPj1Tw eq n11T.Xdg=gkT5]goz7j{R]!kk"оo w[X_KZZϽj=4μue tps`ZM>O|{:|m3*WA5c^u)@V^WhY0/ ;en  ;guoCT~w g޺<7'3#_[#_[w>S#w[>K|Y~^+hYPj1lS 28r7ww,􅘿C_ƽhy/$/[o{34|m0 STXƠԧ13s2 {+ߧ|Lj Im2M0\n Ի 3d7l+{wj|μie|s_=;|m=;|mC*C޹:Y?|fK͂rM0\. rp͂rypzwr]Rsn|gVO/gh`nK>o~O z~O*~n|M)go.tb(Jm:튉?:2q7}қFt 4μgι|6BwQ1>2֟sGC{+|jZ+F+?U7a[!5 +6p&Pw+d1+dq ջ V&47){wQhy $/;g<NSwSAvNBR1>21n -uzXtP>-R`&> ;dn >]{-,% :PsnIƙw|Os tpW`nC>&kߛp1ϫAcZuzThW>ӠfCMPj1Tw+MJÕ2 ߕ*=bh>Ko[Ͻu4μs^$/;ZH"|AA>o"w;֟1m_+Y,V~goC_^)5 +[c WJmJuRPfCyc*=6ߕ|ކ?Q>68νԓ\6/ls{\6l|۹m'6]X]JU~gBK͂*M0\1\Vn WԻ Vu)泴K9FoU>Lhyba^vltŃ2|*k]U]b*n]UUӮGLUR`&>( ;en  T.x5 ҮЩQ>k 4μs$/;o$÷ӵ|NQTiƠ &Y]nQv-5Jm:RCxPPfCyC~e2_CwP~'s4μszmle؀٦!66pAlmg~ClFn7CW v:c&>$ ?dÇn  ڪ -AW~wݺ@ۀنyن){tL ![H64~/~/2~o!P;5f*,,>, Kmaa?ayaz`VyХʯV>G&4μ <67=ƒKJ>#k;G6U1< wLtgt*}?fCMPj1Tw,FX2\]=Ih>K{ Ͻ4μ $/-0l6| 4AF }^a[w<Þ{u{:C9g퉽^-5 6p&Vw[c Wݬc(3cئzfAY3O({3g>egg:{6{6~/F~/ ~z:Izcg{ -5 1Hm#GdGU<{\|| zW){Gpm$/۸ kk~/F~/ ~z>z#ߦ|^_@K:R`Qwkd5r7 kd5kzaXgi/k)?Eܻ^kpm|ѓl?}2$0ΓϗsAב1#. c.gsík*_Y0\#Jm:a?:28kga\gík>Q{Zw'yy8|8>|:8z(}vDhYǰ]1t £28r7 d cBY:0fwW>n`>4μMme}30 ? p"_p"_E,&{8 N~cNB*?|8;o R`5pC nYPfP`{`56Y:g 'Rܻ8Om7I^67DŽ <|Gk~`w yI:+Y/CK͂FM0( Fp͂Fypcg|;q>ڸJϽ痍8< ̝/?;|m!_,S1r?;]?sw]87m& ;dn  S.x=AGS?Zܻހƙ7XI^6h]WF`g^//*m {C~ u:'uoP>쐟B>&Jm:m?:28'U<{ܐ,A8n 8 7A3qpe;AwQ~w,>. Kmq qyu*=n|6S>n8I^v~o^F33r _;6tU1 >21ng9vT>&i,nMR`I!l 7,nc 7wlboC(Xܻc7;'yπdx|>#Wɧ0~Mt1cYZ>;ORԦc(;M튡:2aŷ ;g?CwV 4μI^v}3XpA CgC>.|A_be Ȃ1n3LYuHV>lJhY0l b [6U!r7 28T<{\*h>KS>ޥ<3{]07)0#0)+ȇY|f T ߻w7~yn:hy$/A  00w|]["Avqg8 >tLߧ6 hYPj1t 2f2f*,Q]Ͻ1 g$/m@ ?̈r|BF>i1# c>td2t>;sfY0, 6pC,c(wR`Uj JmVuU0ܚcUf0_ųݛgG+?Cܻ{'@ۼʓlS7 {3e9 ~UcG7,%Yߢ|QˠfCMPj1Tw[eq n1lW ջ ǍBog&i:*{7 6yI^3ߌZ2lf`F- \A}!cGZ c-?g8]CV~ώ>-5 ۤ6p&nSwۂmr7 dm*=nih>KGOϽ}gޖ<˶.ONږ *qFq?-ᘋNt>gsI.5 ۓc Kmvu]0.w`]f0ܞ༶1C+Bܻ18nǙؓlCn ̘KgM>g>Ҳ?xct,7*UcqV.5Jm:튡C.c(w<`C`{XwY:g*S>nU8ʓl_|3r2|?0c;ϿC>׶|Zϩc BƸ~#a%Y;#UʏPY0! ;6pC!Y0!3c]84vUqsR;p]x'yم?M*簰[`RB>.H>ЃTƠ,= [NS7bΎgM-5 ;6p&Tw;eÝr7 ;eÝ;RB۠[\ܻ8.דi`J4|v:? _pY+ 8:z(}vNvPj1'Mɓ2r7 OOz*=nܓ|_wvC̻p'yمf62<qɇ_Fv!|߫~ۅrt/>F{TgMC|Rj '6Cu?ab(3cx\ųǥ>giY?|]ڇ&iμ $/:pѷv*蚐򵋾O>?P1|r:a4#d{gMZj wIm.M0ܥvn w1Ի vǥgi[SܻC̻fOF&,&CAvQ!xE*"ktxvN3wl1W>l쒚R`[j w;1n w},߱U>.{gE<.lq 1dwqAvgkQ1m]&~l?YǠ(g3-5)RC-c(w<9G?AwTeƙwfe7!ó_;u]w"_XbS|[q;ugfz}f=-5 {6[Qw{d=r7 {d=;U<{\~h>K~ }@Ͻ4μ/$/6d .,p1/kW1n'^@J?Q~Zj ç6)u?`͂S2SOEg= gij ){4μ=.\}y|UeH'"C[D+m_-Ul-UԨ**TQQQB%@<@B 0L2 D0`u]wws:wϹ߀hjyy~ ek25CG(_f(/vWO^*>Mb<ĬPbj(i5T{K,4\&54\.X׫p, ;(cE`W2CsN/ tzqOf(7_3zP[H 巐BW g0{_8 iI>mjASWP6i<2.?EU _qmA̳Xb5\! W=R@7 WH W$+{W:s.}4ŧ+co̰'+ῂ+&ŰW<}*lgSUWgc/R˔k=Pjػ%KxޱVCMĦP!dJ W9恆z\nx]{_fxi{ï޼> ׌~5#•M hGjg>gXb؄$6*JZ sUqs9\szc;"̈0pz8f afa _בs#eE*g_G̒Y0Kbf=x_,ٛYR@ìg{y6sˀ?]חc;"̈pqy}3]׌3]׌V6i<2"6-U5|8}c3v(y|`Yh5\- W=R@ղ7 WK WwVqol\Vxۀ̈Ӱ<輑G}x$&oA䑤?QU DmqA*y%fV\CX-PfRX sW|vmؽ9kޤ;\$=pC&u :oO}^-5I|(8 $ل}#}1?gwT|g1ogKBlMh- B?0[fa<0[]s.+tg+c^`y^u/4,{N :}Pٞ>$͡>*kMߵ^U÷o!f+D̳oᷭk$6MhF!YhFjhF]9-55}O0kMZ_&iyy9釠snR))@}J/* M 8}3Yk)>Vwp}Ś76>95#K}?l ȧ<4\>@e3xwPWk%6ZMhV!M5\+5P]9䅵KAݲ@ϱ{o-ּ#v/3Ch>f$feBW;_xiWuϯx~KBup&4\I ,4\kN]9_<0~x]X_f/ :^>| |l9l\|7#\Sj8wXيgw Xbj(i5ش=0Gfa<0'V3 ̹?9UƚwUW27< GTz7o._3*lnF Qվ:xiߜx0'0Gb=7k5j_3p.폱)Q|9vXz̨?ߣewGy$kFy$kFR6Sh<2j*mlӪj [8MhBgMXb؄} ׫=R@7 K ׫ 3%t\tŧ*c 0ּ$-5tQ~+QV&5*~+QVfjLq9y}+p&4 7= R@ 7 7H 7 64 =KS6`;Аэ LkF[׌K[݌2m}+3Nx<^Xbj(i5ش= RX eoj(5P]9/Wx{sAϩk>׌M}_W6i<2]&BU qN.xwn؄%6ƠFFٛ恆S=s;wg+>Wc;eFO 8o ;JOgPf#mGF`-Ѝ/S<XJB\Mh+ sB?07k+54Ug2}o.>} 0ּ\ˌp>@ o>S7>e&6#cy61wV3N?< T3~xXbj(i5ش=\7 79>< ̹cox݇c;+~1pH1:>?f [p1? _m#^gXbn؄$6&)pZ *{渏~\I?xG_f̀i8|tp1?fL!|7cLjMӏ#yu}>/B̳#v$fa^0Ob=<aBcmk(׌ S6i<2 mئU5txX (>W̳fȓJlB͎fYhYffyfuvfO̹SW*9vڌ5X_fc c :n>>9>R6X_U23N?[gKBVCMC,PfRX Vs.,L>ϱl 5W2c8ePäY&geJ䑱?N OP3>׌=K}(~ dU5_g)g8mq| HlB-pKٛ[恆[){/J9~#p/+c9`y^s/394Pⴧ8'8'͸ʆIw3IU{OJAb߷$)~gĺ~ĬPbj(i5T{[)  0}߼sW5#xW5W2/+Η78~ q 8~ )o! ~yd`YhMbn؄¶6ٛۤ恆=s9~=x)c$`yǕ$|ootw=Ʒ>O76Q?KU Gq:4/Q<%fEJCMC&PfvyH~;s܈9Vϱ k\q?5|=@}x'_3>A݌7BVU)>^̳%6_ja?pZ  3Ǎn ̹ttc/V,4! wHlBja?pBR@A;9m]O>v+i<&_j8N)?H̳SشJlZ s&RX eoj(5հX3M̹tt .ݔX&?_&2~tL>_{_< NT6i<لPU9kW,1|A<;Y`YhKb؄.lA_]RsKxݜc͛<LrV4Ģm3ԇO&O&P)$)}?e's)X̳s?s $fa&4,؄j@U {װe7s`ΥsW|_sM>_&2{R|jB$)>ʆRw3R'SU k'+~gKZ %6VCPP4Y3d௙=k&W6+h<2a%mlU5\RL v໙ȽĮU5\-x}}W̳KBo$67?VCٛJc5Tg|pAbŗ*c;`y'a|/P*?Ld?9aӌB̳| %6a&4,5),4,Qqs.xSϱ5ae& >K< >'<8k&rGG+~I#NV'j85d=L}y_3i>eI໙IBgVcӬOK_x,YIB}$6>OhOf>yᾞʞ9. k}K6W eaͲkI\L~L ').>M%mG&lBߪ Ӭx٬[VCMaP!j({VCy~uv~測KWoxW5t6АN~||ɏ+>d>n\8] MP|OCش&4ܯK ,4/5P]?)`Υm?x꧁+~!{WV-LfDe}n&s&}ȳu<,4< Hl¯j?BR@q$sVc;y+~"5}.Q>{|{ f2 _9BيQ5"W2SjBO)N>Sx05Sx05SZ*AγOi_U5S|gׄKBÃĦP!j4j.805uK_xݚzNwXN̔gΚZ𥠳6y)oRʆgw3gS3NUxs%fw;MhCNhB%){KNQ|9vc;CW2Sf)pIY?\>k\>kQ6A6U5{<4~R9k9kK9nٹP՞gw<,1 KlBA_j?BR@q;P\pϱaּS_s/3p\>|| f* 3Nw| \r?,1|Db؄GٛG恆GGs.18Aϱ?`y.u/3~A 1ȡ{V>oT>o3ʆw3ۄ͎3NwNU|žXbj(i5ش=#RX eoUgeq8 8 l}/w/3 4pZ+sgffʆw3U{fgӝ {)>N̳;} JlBãhDhxTfRX =s;9l |HEl5\L{5YгV<}௙6lydhcӜХd 7V<Ι&4<& =cR@cǤ恆ǘv\ʱ$'+cs60ּӆ◙6Ng:ʹ>LU6h<26U5ܕ ^ppWi({VCyEʞ9/0҂_9voc; 2;>t YkYkUw+ރfAg쾗c} ؄?HlB&?H Yh<>ʞ9n+K 東̌ s)Oag p8Ilydll3#jxxG̳'%6OJlBÓj?_ٛ* =sܡKu.R|9vƚwf+~C< gv:><<V6||9LpN1NT|33x`yg%◙"?I 7㧨S R6\w3kPjxbQ̳KZ %6VCp^Z  3ǝ M\[؝k9\U9g<tN99fO"_h<2篞Mgjxx]U̳g5,؄а4kR*4,YhX*54,MUqJwV|9vg+Św\y?iF A̝gOIԧ+He36#s?g_DTeg= 1 /HlB C 45 54.w=0ҳSsP]w4W2s`OýA}ԇϸ_3ϸ_3焲9G9=PU5,AmpqZT3ϖDKZ %6VCpABË"s\I 0\WcV;sF8ܻNI\ \ ܶʆ径#4 qZ2{)yd,4( /JlBËjbEٛJc5Uq%39ޯcؕc;7eSgR^P MXU Ϸ8= T/E(yR&4.I /,4$544@3ǝs)yإDŏQ<;܌s55 :cf.fnes6#sqzj\3^ZIZ^b|hejLhX&{аLjhXV3]x sgWwS߽f>߽f~ỷ绷{[ 8nH$65MhxM!\^YhxMjhxM]p-̹b5OV<Ǯ"k]_ WRÝ'fAOklNyd)jx+x+~gXbj( ؄?=?,4Yjh:g)s?5Ӯepw4\"\ςO>p[Lx6ae-J~?T 3V69gMĦ0Wi"PfRX =s\%j9VC|Ǯ0ּ u/Swot*kSz_=3}e9mG|لV[KQA< THB MhX! +B?а"kX!54PgT09K䎊%Tk|+kkҸ&-\ݤֶj߰ueF!ՠӂNLM pݤPix <4 cKp|l `YhxCbP{77doސPg` si?D0\7Mr/v(ཐh5< }>eԧ5iWM[߮aIT|.d`YĦPbjnH +eoVJ +_S9O.؅Oƚw_f8ǃNDO<<ݕ نf!yx:аRbV=J7k5j.dO"+T:=]+~ĠSԇ߰f!a ¹ʆ߰f!a7F:a7u)g| oJlBÛfMMٛ7恆7({渺̀9ֽxSϱkޅ+\,<pFR3An;,;,Iܢ ۴AjKf <[MYhxKbޒ؄-X_[R@[[quQ\Z3x]=[X._fQ[h=}*=}YkkYkk=l\|7\SWհ^!xiAQE̳%fV"Hc5Y<аvAx 済K#b[(U<. 0ּs/iaЉhA}4IlFyd^cjC=O kHBа&4!א֐YhXCjaZq.md*T!sY ]<✀H4t>=}Y|>l~ ⓴~F}f]36Xb֔؄5%6aM!?аBÚR@Ú ʞ9! a!OR<Ǯ`yY4\YӧfIe(mGt _XU <xO) %6аkRKhXKfa-ya-W350݀(>x]cZX.+~%q1ϪZVi>O6'Cexf =6} |<x٦GY%6a-M^KaPj!es.mjK_x]S2KY2/4} :MS>,@}7*AY˳ _PUèG3NUx٨KBа&4!זזY^;kX;I3E=̹4+pϱ0ּKvYr1{:Q]<}{_q*C䑥AKiXqux)y6<,4 ؄a0C5 Yh&54 ({渨R`ΥQ{*>NX.v/ 4;>K }g??!*i<&U5<4z0p<=Xbj4ش{aRX eoj(5հ\3E \5p]7V<.z(0ּK],M 8NW{kΦ>IsR ,x.Ә]P<}Yz/)_h<mlU5lq=2ŗ|}`YhXGb֑؄u=:R@:7 H )xK[|صkޥ7],kpZ$x.C⿞>X_u 5S6<nٳ/{-3N[.NU|~1ĬPbj(i5Hc5YhXWjhX? .s\%K]wP<Ǯ2`SepZQABIR4/MmGlBa+uu083϶S7kXWb֕؄uS&R@ú7k5jZa~˹U"!)cj0ּFYu !)PSYu 5*SYuJjz7VYXÚw),G pyˠzrpYn5+Gh<7AacU|gۜJlBаC/4/{а~aʞ9M06?]6']WNޓZNiM?>Q|f0mGlBqz?P̳%6VCP?Wi({VCyEʞ9\z劯{ƚw׮e/ 8k= ,J}oS6{i<|gU Ҁqz/mA̳ } HlBj?аBR@ʞ9KMNS|9vƚwW2 8! ӑMIstC}:G*ִ86?y!6`އ|<{`,4؄j!Bh!{0Bjh]3݇<qx}X_&i3ܷJ}S"הM? {VxW{mQGQ|SJlZ %6j!BZ g7t[r.mQƊox][ MLӖcA=`5'xɥ H3j߰n <]snxvwKBÆа&4lJ ,4l(54l巵%n sڵƚ7}+~ӎ_ : nYQtlydE#ڠwT{ !>p#˽*Fr yܟBlĹ)`yF Qy,r#pcHeV7p9W`N ,ZagV`;W]ˬ$Dx̊kO :޵x#0ֹ+ Bbjj{B=϶^[heV\PmomW6ۮk =l _V<gC?싈){o+;uk,㈱kH>`]`^ "9 T}UIOHƜC ]/T3\4Ɉ"p oRzļԤ#~ *֙t&=I=4a,gP_E/5j(Ʃ]Es^hёoC\,%8+-uV4v->:0;j ͻ\k a\t]Yw=dvkcmz@,g|Gk8Lx \U}V}V}fק$,^/97x}p⋕=^.WʆkלQkfy_J\f]Ս_t[m8Oi>׬~>_U}VSm-r~۪ vj;mKC̹%>XxQ )OU{>[0>m5/VRK3=>yc`>Ƶz+߬^Ms\6K} I9񞛵dR6;o݌mSdT~oU'6 {O$KvyT_+^櫯)>As58(4S5U5.?IL6ORYm\%^AwQ|We ^ldܗrʿw{2`oz`Vs CMW2kp1kͯ<< x}߁yy :5q e˪g0pvjX]Ͷ5l _֬V;e o^<8R͔ wP29{.p78bǮ&`{7sNSQ;59NͥBԜNo]p\v`^ ]wS|w?语u:`̷kֺ2Ff{6kx czښ9d-ࡺڻ)9vZ;fm;ϵ>V}>>Z.D6Assssli5YZ xYVo]ܵ?lL pʹL (iZ`6ەo&xp!u MN<5f]n]o1-ۢ~[j7%M-뵵{Zj!G\ux=4OVӕM 9%j\_ (k .:-e5ź]f`hru->si|x_n=A-TmYǺ u-mN6ut39/9ͫeM2_ C=Q}{%7R(K\ZJExz7e|˕orz<}r^&?S|F}ڎQmgضbEDݠ1sm/GKt '<9DnXeu\tkʾG ox\ZJsc}̓ƉXn!+~Nt on>:Dt[atkO\BkC`wUmUmT[ Yϵ!2VmU[ Yϵe䪵S;+^~[;}k뇁#}v'^`/krcך˳]9F4>}F)F}Z _ Xy. CD38w&3v;cǀ,8[9U<{7"pMƲދ#pbY &䵱׃ 'xpNf* uy͔5~}n/1៪>TAgp wf5kʼ o#_[(^'*~wUe'=뤍?NHuFgy}F5o`?͆,h L@')璧5<}povcƖlbݷjIjWp3l _6jM <5ѯS|%/U+}n^V{w˜q[/c\O:?o+l MzyPh"Q8W]nVma[7m))j{m7zxܮ3:8MKg*>[sN](S֭u=Xb`ǏQ:~KxI?O\ {MkܗT_m&PZ&7Q.Pmt3|/˪j2<Ϲ%z,,`YerA"q 鶩>pۦhO7`6P7S65njvQm~ 2~ 2Tm{o-bg^[˦j9%/,xѩeTR*{Ecse-ss^ \0 jNsR{R{\ Xbs%0 "l^}n+zM0FvҦYs9^+0F9an9v'jMq1x? b6U}^̫3 gUW}|KD}i5{Gj\(^}tŧ({W+Le#|. v {J77˺` v#vM^24Yol-nS+ &FA`[䋼JM|vsKvl 7eeCRo|xe/s֧&(FCq7{e"yy'0j\fSЄCn 7۹3[fymWmj;G]ƶ19]Sm Ucl=Z_W˧'d]pcn^S]}@ȸVԺ>.O,0.E+c>K~#"OXhO<}_ M>K\jjb]&b]WDڎg[H~2— U%a̡1(TM1]Yuw[91T|3sc\c0c3`֖40cbYwŴfx ,gq O[qe sގ:f V;]v~ډZiLv/P;{].I`3qyHE/V|k{wO{}+l^}ګ=cj36cj3WƄs,bP//_},g[DWy< G9ĭwgZda kCʆ b :>x ׳ פáSţ5;1XG?HAbOT|u2telDOg0.r!\5'w|suL_`b4V|gK+`>c#36[~]n]nU}Y}[llWm's!_w7dnsl>xPKwq '+&E٤*˹Xt%~> 25@=zxV|XÏC2|HR*Imv>Ct$hD6UMWm%?b``Γ17,{W3oIW6r]~  ,0`Q\C+3Xj!#b.Q}Jm |WlيX>⻀g89sL`ԫ[? ͽ[{12[b b-vk;Q '1YgϷMZm6VV>oklAP!\fVql׃l|Ei[kCch <oz kG&/7S`*{/wQ]M XDuQ~u92\We+_\ƻٺ kgܱuyںZR#O[oYV@wDovł>fł>f[v}mg6md[ _Pt,U-7+_wrQu;XX7C)&7 c'?1ƱfuYc7\\Љc\Љsi@`܃Cm։sNVVuRa_35k>Umc0oH`橈D`sis'0b۟\G\õqpy :앂x߶؞zc:`{!mx]ܶUUUml]{~Nb\߃333G}S)*(*QSJ2i*!(I/iTė e0 re0\Ϟw~޽zkrkb:^ku]rZiWhn{k~ՅՋ&]K1>#Ʒ#h“t_ov/k u`P} W5Gv$7GkH5RC&Y5)PXu`4kKC#/ 0Ηv4kzѵӵFеkMkӵеV{q׬e|fA?.Lr|$MRZ΋ẂeZ 'RK{gwн;2_eu|w:Ql;ex X8dJvƐyOΤym{Α< }+dE{hOt{tM xXl줃BwQ-ћkkqrNɺ6&7@ k?pm+ozc8m/L@Nz5 ]kL oݵr/uDCK:A׺`gNwஓ߮\9`%`oxW6ɥ t#yZ =/Yu@+aևOc?5u5^u֊Xڇu}X\0Z,OcnuGya֔e1kݲ u/y<_waas"0ƺ7{yX'{=]'{=]J6 Sf:\B6%o:n-#G9k3UUlb=ͪ4>ɪ.=5"Fw' 75Ͽ 'Eb^r+'\~p? }%+'}'ïC«ٸߧf0qW^X4Yii&+ k$y $n7#n7n #͈͈͈ۉh`vx,?<X i܍':=no piZ~pi“WQ>ß,Ovbk'A]A Y;k'k'vsA W8-gG=}fp&lƣ[|㱌@.-pu.M~sO%7+Z~'^LJ%cq?!ssÇ[K=%._ٙv3Cm廎-uL48NmڶlMn#|nwX6黍2\Hs ec_ H_'~sґZ+#FMMK -- o o$> ` "C:^wSc>/Po7 F7?JހMRTj)F$mvlLmK$9d,?2v+;9+@rxx0W'}@G HGFŸ{gн;Sk^X\𮐏

kgKRrٹ_[;3rr/\y0ɏ ˃PP0=r y0AR`GmGQVs@Lok`)v;Ns9,5|4?-I`y7gPȬuX+lƄ5t4]tdg!l";-bs\vr*Y;9Cݜ:q/' 7gS㓜y>r]?HrᣀSI><Z6*^H4GLGx|yxߜQ^|s"هOܭd%>9)|ح\sf $J:68u]\@\hcJXunzv;p+jLmQ[ͽZN|kE&Z3խVZ9=ZwkaHn CLz|ۆ"9|m7!^Y^|5okw|p7 wۓd'';Ɏ|[ sɷ;wH ٙCv~&;jo-ۓ#M}ݶY0|mK)\Vۑ\a'<*HN!}]ӻӻӻU=Li?R޶}m75 h=G(>9-,":-'t" j1/ۣOz^ЋF^ w;B$;N{ӕ"vdd]3L ;3Nw=CهO0o E."Aac[ֲGTՀ/kq 獈uk;bZEA[yQXxQ{oMϽ[KK.|kMPmC9؈(`jD<7oԟD'B}/|{䛂o\͋onpu/r΃Xr΃XNn}s7iAv vn}Dv^%;C:!w$=wT 7W'_]K"%A4ҟE:$h}eb61X#*o2`}n v2 =JzTӈc#Zx"HzxIc|TĐ]8&n,1Eb?$.~!C+wwG]țyDXOw4'c,; 7dGt\֗W H.uQDc$/$}]cyLX#i.B|H$Eu65`K!Y݁ކz>%[1^wߊ;Qۙ6y'?/ݱP۽V~swH \2]#ށ\9Jm?KcƲޗH\LMH(xp+!}72;~hΦҙj[:Smsv!sZ;-F9cqw ҽ2W.2W, cww-9v/|$_?m^6m'ngƒ%1.w|O(WW\y8@( ^\֓kmw|w|=ZO<]ᰩ27æKæ˸f{~h&$꺼萎ͻ\41$s W~s~sFdg6YHvVbs*o%;N[qqw9.+n#q?p#7&}[~{Xc?{[I}vqRqXYg'֍~<\H6>/gY{~ۍMUP^v MߗFj;N?H[H[3E}R&)ʟy}SRE"ӈtNґZ"U`ɷ:H셟FVFY$ Q5%֑ ?>~)cR/o\<%1߸h'6ߗh'~0߸h'~0߸h'㭄N8\i=6-pGk]g?짒1d"ٟE g N&ґu*vm?Wl_}gz{ Ƚ>\ =l'n/6󺽞a^8&<CC}Cs}}@t}*s}`"o>G6p|OZ4}~Z@"4/$_KL0a9/Vc7 }7GiqwoHt"]#v1gSȻ ͯ=Nɽxilۨm3j+{ 17_om|XAbr$W|K,"I_XsWWVx tT;?}Ɏ2# }AdwK3m^YO#{9 r3Id'";c_}3W_&0n~7<s.Nɺ)9C˟S/x$݁%Ydsqxk h gC<Xޗ#iX{? kwl"Gykg^(- }ź-`w䁂W7O9k9k݂v!n&lij+ >t $wuJ[uNyI)Cg+uf;t1ќv=qļ{Ns܈Zc|܊tt-ܖe]\dy˓R,O#q?OOyɦ|^kccK65w@Ps>O󒓣!m~??짒1d"}`I',դs5֯Ρ:7XwQt q >ػ$ڱwIc;.)v]NF~"15|st~DIA`/Dn9I}s}NmqD4s}NZhiDagZlֽtc}7 >e=()D5=&a=ݛ^RwoWɽ/P۾v0>[wG9c=9rwgEemA+e2@qNpy'~z r:g<{AoT'"cu^,ou^H:a#ui/܉J}."͑i^HE='9,hT]`dT,XKt\>tZZtF^9{ni6:Owtt$}ã>g1;:v죻 >|]9k.4]ǎ1v<={C1ͱqa]n ,㊚ \HrLף 0CB(Jz^ᨹ:ǑzHfRK=9t#k )=tا{cDSϨ F=u3IwKL^~`K=?د\!s:r Ҿa}l䖉K/́|՗Mng&1}Pەv3ws0}1KG<9棻ggrN97=ܛO-$-3Z]q<:φl8ڸ9=nM^}"0e-5Otm$]x,Ǔ=gNtUow'Oy`׋~|r/w@9l~I6t)A ݿlfd(ܛ !;##21򙞝~Βi\cp=kWۀr&T$oBv4-ےvԶ#k|[S|R|R|j|w} X8ƮƮ'T4~Af'UyYs it:)3ıi`p+/.o?o Y$fW) FAy1r%ds"ٜE6块F_ykt~&V'?$?CEdw/%_3:J=r9 ܀nN:6}`{aIGk |x)z)z5S?V|Cm^t/5FxG+o[;uv^K&;)v4ԢaWuN'֙cej\ c iC&?N^qp p@qN8s&w=6yxǙq氜ea9d5B?!_bgy͸.o zuPh=8@:Q$  y[&(x0O:@s80@Ϣ^G3Lu{`}iLlfM_GUy]ǞEr<hmp#'\m9!{x5bǫf$q?8NA葲O8pp[G@OW"J=rߑw#b?7:J"u] <亶x8"7`{.HGׯK,^spuWo8XK[^Q7ɦ֟UسG\Ǹx,h~[<$\x ?,>wLALy:2XH&X%]1w[GGhykhmkh6kh (=gߌhR Izp1\75&m'pII7S-oyf٤37M] ֱdu[ϏI$S}6>wnxumvts%?BCx}.|qtHGh?A/Z]o Y5y͸NAo$ pg'H_~s)Vu > < \h0P@e`[tkjtFz:ޢu-[Ɏ-prۘ%DŽg Cg9^O{/bwƋ_$>/g//yVrJ6"FlM:B6/Z*ZjYc{LCح|^7ߘ:$+1r1R<n۾-9!&xTߦ3շ12b"~cmUnDKM uxvٹdSyGULX*偅1u1O5c&:1<\݋)NL [5%%גNx&K|ds"dSX{ ,6W6״6X#6Qɳi|r~) ~$s+ 䴘cI_־ہ'p#N`:3yLޡ3ww 7bv|YAA Xr=Hà$ۇAmIsJ`Ycϣ }A2st&.7=~ , r~{d1܏ i^Gofln ;ɦ"8@ku y"hmgHm|r9-R< $y17!Dm1OP ֳ d0=C58dI`ٿĴN\a:8rf~#:XWT}RaH| !: zx=yXbT#;<nO#M3JC c\C%ϡH+ nW`OR~'96 0/Nt18%uNf1cEn?1 QǛG#*f=;=!RV6]k7](]^dy{NFɵrpZ'k|^dGV2]]Kl1Oݓrfk|{rO<(p}+$oB!#LO$zV0L Xk*0jCC:D*/o?/Vw?xݓ[W Qm[XFB^XVy9۶m[OmoWc) ֥߻[×k| ]\ H.g21ˀ5c5%W _5I>Huj`ojkX$ `:KWnһ4LcfZfat65331;`}8LL +|X À5)$dUt L3G3G3G3G3G3G3{= ?&}Xju?"fK-o*>7E^j 5Um![|̣ _)_70/׼yy wEyp\wK3Frk \s34O#}a _H:lO*=ۓJ|8s{_Z޼Ӑ-_;%9p1z@|ej׽vB]1v0`۞ζ=%}oT-ԍԶSf,{'!=9A$O| x8G"488Gm5,}:Kb``m==:.> :OW~@+?ȔW%wŖ3r߇k S6ONNN} l \$ދ/JbOtlfd<+6S(ӵ [1M<'s[ rcl5 %Ɔ'yҗu9 p"7'[VֳtCZk! bkk?kK. oc9}!{y8Vyy8Vy'6L \E|8T|gvʳ{Z˨&jOmJFI[3cb#!Wn\h7ܱpYcҗ86X cb7T u96.b| ~8_2e!gS'>iVG| >bwk#goywϐ-D.^Q(E{ǁ1݆&Em-l#nѓd3l'Gdsg<:w3ៈ=/|Vx1: ~|7`Ϧr~(p6|랗цods\H6WM =/U7dټlm_om k{6OH=Zl*Ǒ$uc$/$}E?r|[Zs5w*Ghb=Z81O%Ϙ8ZG M]ȍ5O"78:M}ȣ>h=}c XX࠽'z #}5x`}Ł-NY^܋!xq/ 96q&o|ǁⷁ?|qt?N6'͙d3lf,x,@6 qygm]Sll~j^r%oH>5'/$}]'gSiOh,LJwлc:[~w(1)cRm{.cl'v&q6YmR{N{+1yw>xkq}O'B_N ><3x|ǫ .=^]0{4Wnx /lm^hF6ېgKdL~Ul"_xlO6?#\qag"΅ }B$k>M~)J::>SڧJOuX׈p|ayא߽`o&.立0^׽m/@mRf{{SۧmS܋jf,șL:I"6AcGָ`Vߎt:NgI"ruW293#|F{Ϥ&|(sI竇H_JσKM+OknX>yz\O>u BJC\$ 0֦}K@k>/|~h/Aۿ1KοNJ\.cKXZ/z1V{08ڦRi6ڊOm8ʓIGX\Dmَoqcqcqcrcrc 0qcqcqcqcqcqcqcqru\ہl}mhnE[ۇ/>|dcXOȱ]zvB=㥗/Ҩ-ֲKJŸ"x$X x{_jދne$>Lݗ$\d/Z(a6 NInHBN=Kfdbq/WSF_Ew/בضRۆ>iuE甬);e4r{ t\ZY?\W^#/ jRG7!y"ɅW$`]_'~?@:IgH> ,+ Xy|x/+O0* `;W+1J3&}%L1i$8t$7^B2X8d5A !t`Yqc!L='a&\n X߂9ϏIT#{Aٯu/1~h sk_+>Fm|ِr޽<8 Yc_!scfN2C+w%r˧f&ԓ_}.8^H2cRƛL;8rgI.| !y.K|5 ?S[;ĐD^M| IԖHMy%$Z%$;=[/F=7Ih:0bqlH^E׾rhb5^Lt6 \IJ?/ֈ{+T)ٜD6͟&W~ Zl'defOSs,5I.5Xpp2ɻI~|<\X њ &8~As)m'ٶ$O_€蹅I ѓ̼Zz{ʃ;Ow 'Bjzϫ~ctzq:;/W2/{5S7ld;f2Olv6Nlg4Mӌlx6S׈UKNn.$7M&]Ɏ՟,j~?Ys2H?({dzWt|;fM |dݗaݟ,0d}dzjrCW7I kѽ4f-NӚpp*XH}w#J8w^Cb!Z85YCIܿΒ}4}4,&Nyl!_Lkkm Zen6mm32R2-Z7C<<ߠy:3H_kY/qii#;‡a`x2ŘBbLz))-Wh] Nm ?2E~N=89e"a!=: L~[޶{>bѪTEm݇YȑL~+w\CǮzF|:-պ*O;?IyWٗNe'Ml۲N۲07ޖ4 lr$['`}roOgӇtt}ttZ害*kkZqZkK*VgZ/ѵӵ˵e|[n7ORcǕ^Mr璾̵H_֠2E/5v\7U9 >O Z>O2|UI1XMt5ξT:P ׽XW4]GiM,ɚW3R}^]{+ _JqsgX#vrE,f~k|Yfkb3 |/|lv"kdS7UO7U$qIDro\m$EHi/q 9@\8޸ #|״˓iTcL5%.X֔8`= W-W'ZLwmpu/i/9u:Ԗ}N>wny~MGAs ^CkS򗮡g_3:g'g<%Z@}R¼Zrxu_)7svp&S?SkBәw8,q WZ';\jȸǁi4G3i4G3i4G3i4SfϤYr&X}qO׃Ozr,ok胓]0}Yc' Ś!夿-9ļx`䫊M~nW 3V^W[α]`96Vl8sdD^U,\ ֩9IYyajJq)$/jk;ニ\C #'s}Rpr:9I!Wf#\؜!a| ys|],[NIޮT$8T$8TڬomVڬԄl"fp{YN6_'h9AllT(䢸s`K}1p!ɋH_:\kc[:\G\=ojƗܙܙ{ dܙs sgj̝|\W8 {o֩Jߔm=QU/o 3yz/voaTH\r$(~c|LJ-!Sz|믜$|8 ܕlF6Sd+9]lkgEdsB6Ϳ&<' oW!z>p*uo2x ǒ۸yH_9O/g;G3s_!'J/Ga_!|US6 ey7_2=u!?̋Nɼ %]8/Aۇzlu:6ڎzuuQ>HGPe] Ր_C?W>֯ ykX_knA򉙳?(gvׇa!咿 puS2g)vOժ!7ߵeU2pb`OZy`s_{j=nj5CZBZnתvVZ՞kH+žZ?ٟ]k ]tt r-ѻmRg!rrpGw&$H_ ? $}={ľ=g{7?нִGW?-(o@ 悠`gƶ ^]@'GJSK.ZPRT.ȴb=@ײ'4^޼>8OuNS=?\wT_,;xE6 fYCˀ3r_׈6k46k$G3d%=i='5I <)v|?JnΏk"y=u pO|9 Oӳ?7(~oP(N|Y`||y`׀?sԈz5|Q3Pݓ͠{RW6~o>g5fFWf |kuŐ_8P9I; Oj>E'5B~IW<qqI6͏d[9_lX/jds##fDNyֳi|RYK_8+$OCk~1H p|?ѳy?,~g~5">Xօ`@|M1!߭b&;RxCZ<_a~q-}HAew0N-l;Nj~s)~2g'/!y&e. q ItIY{$`?Kދ\l٩Rsy Ӧ}4䥟%93=񳞫#xX\!p|3H.WR&Gn0?9ɍ{!nu-.ƐvK0m'#5}ħʇ5MI~VaZ %֕ૅQ$X?9oQWY-ŷ 3V?V?du9V(/N::^?Ŀٿgї1=(_+T%O];b($_Hr!K3Is1Zu/cL`;ί.˯z W=w|5Ibj;ڎiVg0չXp&W\ײ'ZS~-~ʙ|~[>=Gp>\K- |X|brb:[Lbb<Ś:%gP-j%Z= ,jmuKN[B9| %|zn іm+ Ʊ+0Zy//%Fkm$XZ<rudm4`.o.uc_Ķ]Jϵ.M&@kեHN9a)儥2wLͼTX ̥tT,Ƿ 5UBZkE3)sjM < F5ϗNɹA5\ ,F=%F=㯵ImOQ[y5ew;=9rM|J#x#CgX;`k͹ryrC$np7"}9 ܜ[[0_b2;ۀ/^8@J k֍ˎA后_;յ?^{*|)okovJ p_[_k/v7@??Oe۶N%۶5K?_!*pɫ\b}e:::D% dL혃I>CLʍ35vgS:2'딊{g]uu-X~q57`K_֏H>4Q$_K7/\gSq:)!OOӻ6]HGZã&Y|5GbXNkrZkrYknƾΏ!峿Dd\h9`O@7_ ›/?iH.Ǽ4Nqd?xPՁbgp ~aK.WRk%4p|++_Qꯐ% ?HG, WpEs>;bB# wD[5+C? ȱ+$ Fg,tƆtOp2V/F^ş=' a1I6m^ն oH-P{mKi9Jb,K̔1\֝$_Hr*M+$_%#äst It$_%`R9&mԊ+}e땺"+%_%$`#ᩥbrzZ  VjE=R-zhDO:#ty1ΚV~a S{Pm!w'1{:%s9`\gIć򡮎Lx2Q7FSWi}~f3_DKl៨yk#QUP {ܘ_[ۑ\л-kt9Fs0G֨?s%%s*+udZmEok՟XGaZ:KYK}vJ Yz/b)A?5S}VrwE^.gg>]|=PǷN|BͿNC?%Zw;J!v3%*̸J? ˄|_χ|%g?z ,~6Jg@g`&,:Gґ}b//kg?Ya؅:/~wY)֟YncۘE6fѹ\V&'Kzx[~X \g}?oe$۟mӹT۟i҇eOXc֔b/y̯CZ/3c[!*Dkž !O< 䁄_bց6HC5F01d7&y eΆ!]+uJ"erJ꽠?;%^Fo]:֓u9Զ9}\bl X˂s|?\2>:g-Aya3`/6Nr]3$!P'`RXl[V';tM%^lv6ֳ}l='̖>%[Wp-DI|?4Z;.rw~^rrc٤[6]kS&qm-m6u}4a&"ֽK' yB.c gtOL7k|ӻfff/Ibex$nN%u]` cԷYnsBsknV,V{3F=@L1-awSn閶[轶-ɶ[RlqLmڶ{m[轶-^ۖ׶p!G)V9!gѿy3xu'2)9z}ѵ9G;/Yͭ|kG g̺U9!08_Hs?D'dw`?!vp!q/@S^r/?[ԥq} j; 㾀5qS<9?[&?n*t^uJ[g0gq,?Nd?x9ߧyiЧ9$z)4 I_'Ť/v|M~|ۦ"MmB+grp`6'oS۴#8-M}нRgc+}, ?CՐnxߩ7qq#q?r޷pgdg`՝_vj |13v)AW8] He7!DjuZQ[C+]Ǯ]kOwi ++ŷBnx[\\:GKMkt(Tfe^7Oʘ yRԭ,ܮk->#y:3HÞ:o 3OfI3 oXɚ^nwn-pn]!f`]% FM|)Ws SR/yh v+j;fP[ (3ũ[E`y'ywB1c z:WO ؑocC= tnәV~|Z C_Wa떱vꆉ%*|[Uѩ歕tmzr/u';e\{C'GxҙH:i3tuSCpr+57"ks:_jºkI.n2po"vV2OU̗݁u 'a'#K==d=V"錸W/0=I/_{={'oгF{4PQt-Hs|ơ&/@@ea tZ@0pI\m L KנsRcMU<*wk~@\Ui߄8Ht]rQ#*EU+D.nrc>1tF=Ly?]|ipL{Ucԣu=``Qcw׏󨵂m|n?G=Q/oAzݏ7ČzCb 5dd"[|^d8N6'-Ah~WtuԏgN]c eG?9g:Wa_8) ɪ/Ow8q=ߏk855齌㛈f/'>gG ׽ 1|\s,b8-uG I`}s9"0n.';5gq8 :[8kakŠMg@Gm\躏`|bI!vb'\o5M4>^w1 cZH 861[ebkmb.4b "y_Do#wD?}X#&f3!I!׏fbOcfb3uG3/br.ϗS+>eХv ?}+˾u.<|BxPQP\ KQ%D5Np_ v_䒬ͨ0jZlZj !j) Le?coDѱ_c#?e^FW{\| {MIy 8q錋t:D'Dщ}'.$CIx9t.؏:MJL^Шk@W__V.qTKJW!=;\~)}V ۿyC|)y/ HQ퀥ϊj n bKX,QT$xWq՞&L8oq_?~o|[~O!HlҹDt^*:/#"'HeY [tbtt"_΄D'z:Nk焺òE%.%*8]3.fT `gҁ5D5w-%rxwJ^{{ &~Ց 0&`}Oc{)t/ZjREި1FھTj_z55Xӑ٘ˈ$#ݢ[{?Oc O1Wtׁx;^NW~}e|"g Ko%6t+Z;VW_~+ġo%5V 2[ome߲om7[o}EoY?&^Fzm ~D/#QӿDijxv⑾85YGgFOFOFsȃ:M:SB>xJ:ǝ*E<&ZQ%]kO0xJ&-`ݯ$i闣G $鳢gO/y99϶ 7䃵Ʒ?֓9IFvN}y%{$=Wi<d5Vz k|]Ѝ;11t_z7&_<';s-[Y 3j:cʢZI;ڣ{G#$z ѥVnBtY6'W"'Ϥ|umv.!8KGW~xGPsIyy-xC0rrRFF^M9=A^M9o-OǐL1Ɇ<'j")e^-xP+& ;=B. }ij uy&vyB*/LN6-d3HV_&MٹphwM ˺~Xj^>IjKm`w.h5H{/zʋD Bu1_0꫋綾>ErQjh-w}wcHX.MP\{,]uॶnnf@xIzhKZa\n%c;fyi?uv<^IUsxԧ1Xi_1Y/k?r?#X{;z{/#Sj?z ~\Xs`t:Ac>`j{ ~p~QcֶNMڳXw;X&Msl> ߰MZw)~Ӿ,bɤ:!EjlǤ _ ,}Veo.[]"=MVNK,v%Y`sEj+gɎ!$+rb7\suBLG1]|/VL3R_EAϋlxbmv3ɾA%OD!sOw^bz$3f~藝huUG_L>3u-, \9~yW`.Ew֭=p7nHۭ vnb72H6dǐ4EOmȢV@KIv #蝻fx.6%/ŌLt[.>eYe_/흭9Օ1&X`]ſ1g62POB=-vx6\vƷ`}+vCͨd3qDv+p{܁dC$ۛdoYKƐZ Y - z!O)W9][Uk"`] u*FLF13WƭnO=ѷ`2ݰeP,UZ`scK6ֽ \bcQd N 4;w 5%)$w8du zN7tw uXSc#?ٙR!~J<Ї8ȀZ߁_G}қ"i\'X$DX;rGD=]ul5e-7.dbM5Ft] wuqHb5u]Dz[/X'vp EPs$kG mL{H(bx=z^ A _go&\FD5vF&r+zO{/[A1=y7LU8&|?x*yM|;qd ϳσhzlkϲ8x/p!k/aM5w~ FjnMtor~2ߘDlG`}>4B4X 0A L|`!B E ֨k9q2#lNgSd{`n.M]@SړcMuOX$"^js`́衮>jbGgZ GZàG:du=}sZ0ZLNEw5~ 9g-3YkӁz^l#kk퍱5ӹ^mF{_3ouѬ눾gP#5:U@4 {e3^L{.ذLlvZ=|@sGnKt|`aAæؿ{ὲ=W|xznCη>~/]nz.9? O"ޭ[~'t=c퍽W '^4pƒح2_wB&q ׽yE@#1,z3X*:I;cyt%rX2<dz_tntt:{':;FRK[b?]sD} 5JyG@ڃ#ZߵгO O }ފiqBj'钀{Y Y/]Kٯ̮ qg["?T3ac'b??4 <$ɾJY}"k~N$[#/\8w-Gq[/aD{}ˍĿxʉg+l#uqWͿ{X`y7 'F|gmkx3y. սFXy\7`q uw}]b5b䮈R3G3ilخخ"7 Jގ+sk5c]ԵZG!_~k+n#=$d9,k--q&/p]=s]Cseq[\g=:ڳ=:ڳ=:ڳ=:\ưppp΍*qchJw#ոNѧ貟!:H<ͥu&:s.5Ϙ>&> e}zyqpoj\?!G>%!$dW*[#όe_:CL}l~ά_#wB{e|+Gz֔A\_8S`l!s1}vVv`_ Vwz!n8M/V|IlFN":%ٮ$_dQﴄW3{c 貮[L-D\t6/#sxħ%'w? Χ7uL^o,R< no|Xb2 <!k>M< \Cڸwmںqck#{q`O?cCئtRnCyMX6j6Gmv@F}4Xِ;umG6ճ5xL$[BblyU.>x;h9sDvj^vbj=k`-qc;1vZo`|;&9j27vh ZyMc1TN.1o޽/hڍ}Ѝ}sZS.m/1X?X_{ًKt!"K|`Q|]$+5U<2^^ Խd.>ǚl!٭KDIt4Mw`Ps;=ӋX0r߻˼x͠b x'=Bx̼ZΣ$'ģ $xpd Ӊ_j_<8e]绵ʭH}hH-4RrTA:wݤsL瀈6JzOybQe^7E5FuEg¯mX7ӽXƀCrZc_o X C`eq D!&`{^G{}qd8Z Atma8=m!2/{*Oz}xOw1x0xg0"c2Gce_˞٠01>tBP`yrG {-="o8WKدXБg?r{~yoc8Z@׼%4A  ^DbZzF2A7 ࿁ jn4lΟVQ? B{ygnaU3hW͠lGHvȢ<'`A x\{σcmyg̠q=^POci' =zqObCǓA<͉Gz5|=WKsD:7N,~\+O%TwoRzoPOxtQj8i"͵~ $ܫ5O%!>#w%IMnU=$ڿ95Z9'i?[c7~Ԑ7 @9蕂@toJ+YfdC7%}>XD:Ur5'zo{Am>m,{A3^L$kf_ƟRύ?ڿ3K9KA\7ǥ^wc)_? ?c)Uq2ؾ%T[ j[?[nˠ!ZTçHP1DO FH}c/e  gA͍~ `Y<3p>J^8gyd<5ICIvY䟬YrdEt>I:_ s<(:އ}$:ml|L:IsxAtb6QbId _ԟ^&x:'~o!rwo%~Pfлr3u^RK#],uq:'83Z 1N=SPmeok} }4;G+@^/>lnN|Zz&|tF:!uίIE3әcΜHщ<$SXB]޹nW>#IDUsSC: \Dt]˟]OWlπ7&3C[H\`c=<1󀋱G5y^rV`I`gkj3}qS6#5" vwFdm>ogF݈/`[3bx\N:$# ψY*G:?"H!=Ɉ3~B92!W "Y]㗀kH \u}\3%Γ0R%H ,1XƟXƜTXꫤ^Os\PmbF6cfd;/F&5/Fbe.9wemi⋃IҹtK:!=1Ō/fӤeҹtO:ίEg7Nk~3I-A" p/g xѥN8dl'5p>뀋HVrZR[`[h f4Lv&u؈}%&:cu̝^JJ:y:61"2~̌Xf/}1 EMu/F nb}_,}'ŌztD:wI秤SoQ_:MF}U+fR@}$)x+ѥFJ 貯%$Y駒%}/uHRXϴ3ᰕɤ=eJXc? /~IYXjOc&Zh9En:p~ا5H<ҹtE:G: :Ig|t~D:Νro$D #IkE8z?FY\p$)x$p ɦDI9H6S`?ӏ34=hx`)^:'KM?iɠČoaX~b􍰳&{}1T(Gm1/`[3z,M:ε^4[DgkߓIn|tGuZ>Z+f怞/xp ѥM*^E2EHVIv d5-?q^n=h)2`U::rttUPmbIsXҌ;<Ř |_T1#|_fHrQs\D:W_N 1E'z1gH.O.Ttdb.uu|蕂\EGk__vz[H t/0@57kt5V7kL> {o> \ T&fe.?f6^blW/ƀ~t׾_3a/`[3v59t. _E'jN#c$Oο=s?<$:QTtt&?8yMμVNg|C`y y{c^`躯= $O'qOG k>y 8xrGk?绘H wj|XcY i_qA^D x0ѳC\}"e^I;{Y^TPbngGy6n!^8-*~_>ɳ)?flMGk'59|m$/=]_II|1c5y7j4'TuDWG2Fl|.qxҏa?6s#^xdA'mmp̏RfCVҿo&[E?O?%qH@kN\E<'.q\XCU^ K{2nVCǓ%lr=`Cɢodeɒ=+>pìbY\fm l:MgYJrC`!`{rc`o'^Mto3_v!GD {?Gf?[|Y ~A ?J\'.=?N&,&Dq 'Q'8z8nv'&?f­~; 4@}-9x]Frw`{ *)#!ɽ%W$gK$^)z`ɓm eoM\)mkGc& dӾy1ϵjlMv[tg#Y^G:EgXmK/,%9x/]|臈^I*$z5u&y<P`~ah:ǁO6r\8{-sJ_/cCzy/0L9y,4o1$.r6&y/y&v4dz<ӮF/lDž3 q{Ι.XfXfg$^pl.p}7kD~!<> 3Q~a&v/&U8z$' {r4.=DDj s /;pO|Dpu_Xܖ#GzE# >-s~9\b``R/%ށy \ƝBy~L\ [ȰLlϩLY{( WHV~ 1`3$)~I[x(K#[&5=!WO9ќȡ{9G9T3}[u? ,9<9-Ǯ AtѤm5 #߸t& [a}M[64dBͰ$wa3i5d@r64>ˤgG Kk 6g/JW!'$~]DkU_#w#w#rHdKIVswkd8@z*I斗H'z;`%_F\Pmk&=)11Sj˞ O'w?s3dLrz&Lғ-z='#=g>YAzWw3.M>~1>fZL~PjT͇)Sl?#D pπ˜Gj_xGjB:RcXc }#ǀ9%ΓM6f.C?N&7I>(~vH| ρd3RNid]VLґdHYSv.SKn5Zw$ۧs'soէgKG<7Q;GiX ${6tZ\> }eމEnb#mZ\LA;軉^AD\r/3e>bk/\[NY opݓoSycNo%f*8e_8<Li , {j |~D"IKm~9pPPfQ|)MGm!Z(2r_}&YGTOISLS S)I~HcGK͐ 8AW_w ~ )%891 10FrNJ,ɔx`s;܎;c&OI<j83Agc%秤KLIXMI.6ԫGkKSw}:5sԞS[{#L}j_L2SҹtK:!r6S%|m>M:_&oH>6zZPX %躖џ'ep%Wi9G<5'RkXBLy|y)7˞2Xs-u ru.#u.kGc; yֹnMvũ߷y ZàߟЖ葂)gq;5{8xGH39 z8ϭ4^dI';Q| ݰ&9G߀u Uro%x'w}7+{/էfgOF L iY? fM|`v?t)<c3W3&h?/$ߐD þ~;a/ |sXkԃN8ߢ,~~9Ij:t9iC:i436-kP4P,6Lfs4]$G2Mks4OC111H y:`$N6LTbSPofլ_kH/=ڜuCkswYWo&"HHHgҬEg5p%,«B1rWڤ0VSk@;I<{ZJӫ]<h<sP`C5 , \LauXா g>ĆˀM:&;HA}d, _rI$~.[+}\!@<<8GO$z>~ \L%#9 be`kc9 }ÏfN#{6pcsN[sN99g "f0sFs1\C:!NG|&swˎ>K|Zܐ廁$h~ 0̢3Yt2K2tDc>s1sv>w:?^f뽻VG}`fNo9Fg_~v0sa3*?FQm+vràXʳx/֐"JؿPkBؿPlqLO$樧csu.fnoass'>[Vs[-[NLlU\Jwfw4`3Wр}ܧHvd'ˆrUD|x=7-_N*oVs:mUmTUp$Q$;Ed$do'߈,j{|Y;{G]cD׸#Dp1k.z XׁWݙz w:7urs<';'ў-`]okXT"[C^bJE`y |f^@l^Cs Ns^Ws^)sGfy9s,&λIe'}ɼͲjmӏ]AD>}DBz$]į`Y:{1괹?8X Xc8j  >eCA3_|;/=~lk7_ ̏p:w:'8{8Αa(щm~.I:KHy >5vO-9ҹtM:? m[ă/߶v_%q(qk56 ȡS? \IUģgJgϹ+{;"}g 1Vc;y;`Yk\].u.fA]k> =`S o+,-܇dsHv2Y ,E${n "{!_e?}!3R7}3%Kϕ,M Sŧŧ_]ϩImɋdLXsQ/X-{b9CNX8:ģ]>-Xb2up)3`j.2m~dq6]9&{=xG.-@1S֚)~Z3 nM.g=ƒھ³~nOxPG< NL5S(;?v<_U8zσ1_st~_ts_X K?ec`aCo/qfۈ.{wZDE#~Y/i佴ԟCXrQ %PÔH>Ikw Ч+"Y 6\4M~s7w1wh!ɮ%ٍ$+w>f E}dn,sObA @tг, z/M9#@Z pR}>ZGKe'Z*$iӁeO>y \̢SO2poW>Nm8ڷnLj,%ٞ$;dsEG!B]B,5",^[G=AD//nHǿLꙴm?xOLese\f-iz,k0m4Ԅː \` Kl[l1p_qe0w$^t%'[җ}LYklI4ɦlb.'KIZ>BLs>+e~+ZVMG\/P97mJ6_8X`8`ͽK[Jn \LI!#.q+-YK ^DZZˈGS˩XNrk=myUz} %:Yg%b}GVr,cf d6pK~;cv,5Nviɦl_E=4ӗsYگ^]%=S.`3%|) B)"S^V ,Ay =GOWn ͟ۀwO{g#m`u=~ z/p+^J׺R;`J{X| })`V`)ēNL@f"[|'n&'IVm†f ş>JnW_rWz}C_I<+ӽmto6 鍀37,izs`AYn^G|p]2/JMicj&N-#Y R "ٱ$;]dQsv.3GFџ&^:۶]jt$.WmЫv%ϧw՞j:+[-y>+j:+[-~gee 3tVVYj:+[Mgeljw`#WYYYYS+ˬf.4яMIߧd y5Ck7bK7GS*?OHפӹӹ87f&#b,t.Ow:#I9Ktb],/uZ,ӳte6/M$:=uY!ы_`U_F<ӇSm\FqeII&=f9AY~73 } x0Kz>0՟sL25]z%l]Z]r!m]DYCϋо5 uyDwHisIC֔ ?z5؏Vt͊L4ϏCljſEbm@3>Q|}'}ksۇ ?HSE|tJ^B f'ky\\iΕ?f%kjKOx~Z^|į5z5z_{.&xX}^y kpAYy#wW`r{_)Jmwݬd%-$MdQ|Zd+DI->64+Z9d-蚇OHt٣Br:.Ŀxn?=jL.ʥIoR:*Jj*tIReq`0`0$!`0`I*(w?}cZkk_zӻT#z*Eu[Rd_9nlJ툮܁蝈.8ரI_`W&{} pgލ`ہ{7{ 3&v$;ݰ-tö$%TڱN timN!cmN'zKmvpk:x>:_Йd I9v1e@zt`d&Yur`=O&=tGe Q9j%B`϶5lޭp }%1 xn+e.{+wJK{gď/>sAW GzbIϓ%~^#O?c|,6A:wn!n) ~ك  ~{> '&O 4'td;[ > 0`k+{+'ed#؃W>[Ma9]u^wJl.ؐ{#;)o o=oSo+o[щ:oE6tʚ1}e͵6J-ǀ ѼeC4!]G矁uh; 9`/XL_<_] p#S)6,>&vlGVۀ#N_ 'E=ӯȖw H6JdQdX\YN]rxT!DsD$~y?xd \@>{Gzf t`w+t4t.0__bN|3,Ր$j,pJΙ1vOΙ1vo:.&ٵ$Cd)I;=E,~=y]rrRDE0;v(j݉_r]B`cڋd56P3 ;P=G3;סCWWe'dSէwE͐Ҩ7R9=]IOңq#Ucu-z`Q[ajgt7|?Im{~Lz8z~LzCnLx$eIH:Ǔ\ҹt"[Dg'ୢ36ytB:/9q:(:6տg\JtۡȟD?NC/0YCKl^~i8ր][EmuzR[IVuxזOv72GZ&yG."~`B<~iEJq9*sg|- Y}(=G\*kh=9::FG.ֽ3,kh=:8:tk ێ:m4iN5ZksHd7CF| SE qv>m\F6ۘnocס :;&E} D}(>TPNCwƜw1Onyzp;׷?]\2d',yF.'Ymj 蚣 {1=Xb t/suA`=/ p;`ñ*NF)$NjN>\6mDҳZ[¶|ζ883.s=5Z=]\%KrFɤRSQ]qEԟ C%13N}/hTxoX%X;]Ŗ; XűHVaÞup؍Dzfģ5!x pɊ>eþn(Sx@`{H`cx`Zg3sHV,as|A; M섶NvBod}اO| Xk0뉔';=C݈ޛڽDm :F&7|>m7 ljI0  }4dyIwPϛ 'llr ߓEo} {H[D}nc?qIǃZ$T_&Y~5I)@Mb_O%2|x>4 O:`OeOx{e8o`H%q6m"8gzw ɍɧO?L3xO?,c Xrf8S.s0{ةۈG}Tcxp)J ݦJ /hMM}2M.& Gޞ&4|T`O8mFzt\=]'< ֻ~]L/>wMA0꫔ۀ̨RN4vx3_u"fb}4)n&G}d_#n"=ozWOEgg;{)d++"d=^$ͤ{7N<;pF uQI˝4ďI'gq/EKU,wk&ENv+}G uQN~7)ƒ-exK{rֿ)Gz&X k#5w!z"K ܃{ouߍ2=G0t͇e]>eΣƅY >¯c1 >r˷+ [ɷ+˝zv@P |d_&ٮ$+w`3P>f$BHV;W>S/J܀Z`/۔!/9$|p[◼Xk LrQ.#ʕ3| 7{<-"bUnua/hOxQA?3g.`=e/^c`_ln %~?oW;:}ϛ5zН/32Z:AHu)̓ n|mu'}I09t . wM}{à+s.ul8֚s>u=E]1GZZ_٩IgJn9稫gjl~iǾȯc1aÞ|DlSgp0w V|*';Ɇco>f$"ɾEY?dX*Wn:yf"5Wٝ=_vp ^&5L QL'Y?sfs\`Z\dg';+R ,kR@,Qޤg2K6jYbxvtV1l_lOz3x9c|g7_?gӃ_;2,_fsH-sHsHssȽNyw6C= OΗI;#Gt6\toDcD}z.;z!yElE B"n}.b <}g1'17/IpS`CGwUF3`#W8̣簳ݜnlWw ,qs}!I~2#hᐅ7|_Ԋ#7E{/eT_r:q:6v:t}':鄯|tA:? _N ZX |UƃmDKx X"')$ue-,{9}ؘCߊ#5XD(Cp#^ܞ L{9t0h,q>3+§k=9Xb8|̻o ܃yWK.$Yz+zb>7FHҀ%?D<m܉j燀O7Gs #8 x>h4X&ػR?G| 1X }ϔ]pnKf ^) '<ۛ_FoX0 "H ҹtNydwIYHy3әVLLg&I&rէ݉{UiğN<:8_C{ohk.Z ^,,PV=~I-| lR v7*Ǟ}0^s<''~o&m$g>&M{9[]r1pc? #\ܙu.;N󩦚O5|"Jz mD/&z usQW,^Zk>C@k /;0XG^X#cY@w7 PG-X{d h Z{J+ˤG lߧïc17>?}J >? "vߕ]9݌dG4t#By1#njxd$4ɾ"؏'k2իrE6-9iw :3/磑17xL/g[70v3RHv3nj;f9dHv1ɮY GdDz*5]H?pWy;p$~9-4X}zpJ]֬EwhߴHm]o]LV/;o,l=Fcyڹȯ1#'{O{O8ij:XzI 5٤?"~:-|t@:IgwKtKBt"Vӿ$isI:UbjOIzjÇA<2#5FZ_!8Ι>K}%{c挌w ]CtGwZG݁Yԇ=_"ufd<1X`;Ԯ'aUߤW{񙎚-jm=jAb`j/F3ьg(A:$/wHGS (y0Qs K:I|cFɷMFɷk/";.|#ѥ| _aGߓx4oL=R<,xX XE`ۑѯc1~}:x;Ӟ Gׅ}l8VFlw:M$8>f!cFw"'$OdF',2\d/(_]e3)C_|įm`"_oOz4XY=zw&9?܏|X6-%Y]>-p.r2z?b\Lr2a%v{mzv k?Χvu\LB.Z&kn|A§G3z:b#ыlE)qN%Nc>g1Gl1?&}=p=/'fL}/'fL֘1D<%{fC@1=Hjk5ZBm{g3Fam;؛/55a[]׻$΅_%"SA-׳r]{%"? x'Nvt`=K|Yg)/+N Ӿлܘ/+zvW$vWQ:/Fk=3X?u ͗K#'OwՏfI_odUAl$yqqp/2/2b@O*=pWzq! NL;81oQ[=pj+ʣQ[ҖճFڲzR[%QjWjkklkkqmoQ.<-Jk۱-/Yk')ޙu.LNZdk=0JEtW\ 5pp^v+5+u y`#9=+iXIkJ]#5` u.,·ا'{~|7Eh/򭡱_O_Q G;!3HBҹtn%E'꟱H/w9FssՅw:Y1{XWKuPĮ!P] fƺ_HI(w ;>vu}(Lv+uǀ?Lur!ɅT'<= ZZn|3ߌ .s|g>=(>2_8>rtC|/?SH|ҹtn!HbA 73әltftZd+5)ŧ[]׵3D!s#Zp5tov ݛ]g\ Xb8`oQv\?u,&su+=f>'v MVn2l& Y߾~Kdדnߙ]c%3[=+Q@\ѥZ8ߏX֩`$+UXwk.ZZYnF9$Kg5kէ eG{rC2QK|F ,y890oQdEgBڞ'4KE1^k=?N}'< | ϊFL(= |t }HP9VtVǓ٤s \G:w2O'L(tZL8t^' nFtY$z񫞻0Q~`Q- HV=]G{u-8X5lQظX5_!hQD-"=\,!`GuK GE#wM8W; §wxq8z'"nx0'.Ͽ ϊӁ;ηH燤7B:y|m&2LG:Hbҹt EgpdbġI RKG=  ԨQqޑ%_E%w%~;;kNkLkX} Xb5ZZ/[Sgm6$j lM!D0j 7q}@oZ+=I`ԮSjڠy#0片j3:ƋI'y>t7.jI=;bfҳM_ٛt!3I1`&#ys1\G:wNɓ3IɤCWTQ/k+}/H D X.Du-~XrWT`okN 㲹B \<f}^l ˞ݲ=[m10vKϒlwaloJ>†&KG;RSiN~t7 \BtQWe݉\EZwTk;Mkm&=u.ܝdlɪO?`KxF}W,_o&/?)o|s#dy;v68[8t:'ǐS~>27#3%ٍt~J:S¿f׵6u=ب޾A s91ѵA^Bt?9 Cz$k\?`ãuܑtz78fmfYˢk ' YT_4`p`h$cV }8<ٯ67^LNƢG|~+'>$ x)s= ֋)-O͔;OkkJkkʣ)][S^ޣ>3E)81S4jjDmP[rogȽqĞu޵]õ]ϵĵ}k+V0d[?fМ3tg'ɹ.u~T6p/;=[}gkc'Ucǩ:"5w+[u~a.l57X$Kmz4XW\`׾m:F,`ݗc_mn_'{(})^ d۽g@*px`9&10xĀ\N|j;iBmS[?Q[rjr껶rrsZI[qmDrڻr^ޢKm}Im P BmMfQ[5vj%x69֏9?<9tg]J WλB*9]jNvuTlzf;35VYLvgS=]ף Zlzf3e/hqL>Zۀ <Mm 55X˘8O}Tyv6S:LM$~3tf\щzf щzfLҙO:דݤ0YtbNim2ĕw A<8w&z^vįI pX߹wr~ߡg?,93 Xz>#z!`;d{vOΦ;%G:Z_ݝzİSڦsy~fb/>5}w{~}{iO^4z10MkI秤sI:'Y5pl94#ֳ*iLo{"C}>x`y_cS0v3 9g$v'Y ro1ӿ$4@3D9dLO֎eSDs?sKr7"'5=JKut-`kK],> 8ױayOdz 1#kL?JM˃N6 q.cr]>@}d]ʻ:$ Ԯ$6y~;1wr&_t}/rQ7F7nQ; tŠwKrQ7F۵3wwwI:Γ9#!ߡB *Āq99#(|t*:wtZx<}蒇 v=:[7&~{[kXR'x8 }~=%#8x>x\tc[mYŰ]^<8|lJlugۙ=a3:ϞyμdCE0m NOK$+[ ;o,2:E^!8ѱGU6/0dߎUѠK qk7|];|]"{x$h¬ȫ ؘO}ЕBAǺ0kU.=Wt]%kub} ?Ή~WnQ=ru]Wyt䮼$MDwFy6_2L:~6GCURQI,!6'=57:=Nr's Lw=Q+݉.uZKޛUiğN<.D 86ҷ j݂x۫~+uKt_>!gC_bfVv }&;5%|d瞭0v3ت$;d'ԁ-u cf"e$d,Oz,{%oh~tD}bpDF7GJk[zgFѣ2z y/hM1fX0GsPFy:0zg9T}fn_Y,/ÜHV[/,EHv#Ɋ`OXeǵj]ы]މտ 7Q.k _u_ubz_h?Kn*-]ѫF/ǯ5K |7=6sIO`%I=a9j i$+[%Y2dגl1wagD\=GQJu ܔ![5kM8@-W)U|Z*φ<7z}A)'R*9 J J+hÁƮdXX kӊ}Y#j>`ԊKfɟZ/Znߥ+^vQo/Eވz7r ~4Kh>G:&ξ3tNjs'I.)F@mkGܯ %D_`z@1ثrk;`]i@<1I;n ~G뾸 xѵ8x4f~%~ 뚅>Hd8Hd8u߾2C `Gc,e <*;WYWyTCYOׇ2 15e1e\1دIA\VD}w%)S.5Lɖ"$ۉdu5ҵ>,ItՙFR?(Jt}8:9ԇBC1ppPpiyA^>1⣘\auj>p_vG?B9Hl?q}엗V5_|c$FM`_/ƞȏQ|&$ɗoB"I}dl%WY1յ }8hׇ\t}8pGe\1/kƾ+{'\V̋BޖO;_K=cϘ?ԯc"UHˀmiVc#Zscy1<6 _u/lWۈO3b{٭eE=ZkkԖff0jk5ZMmm} 1ֶxZcCt]%|W=݀7;.!Y 1\{ϡ{K10H\a~ߞ:/0Gך 1̑>͑3o97z{IPD?AD51 U곏4`ُo!V+e/fX) ,y s`U@RsSIw+6o$V{y8تRlZo|ЯgNU嵀Uυ7#0 dc8<͇O _c\X.f<GloS[R[V:5ښMm-`/f| ,_GmNS[V\Zqkk"^[ֶ+9uH?eCtA.s'?pw$=RK FzH1Φ"={1 ?л6?As C0~|A1Ǵ|?"߱1zo蘎w8 sb0!V:ztQ+zT/ur8`}?|Qs /;~Tcm}0+#=O̵\1q_bl9\d/VWHP(yx>ۊ*/&$&-ﮭ\[w ں Җ"mY֗`j+ʡR[Vej6j #u޵ZY׵:|^[֏+oy( g=G<<%~]ǿ. Bs?ż^=2bkYe9p"įc1+zy`]ase_VYOl<2dGl!ف$;dE5ƪO֎eT֥@׵o?pG _뫽='zW wᣟr~z''cjORO?aO껫}?+s0x.uf Ϋs#Ϟz\->fϒ$!OdY̗}Hv$N&"x'kDz+k ܊ϗ=.=w X3e,, ,66?6{s:z'I2🞭 n n wMl$+ߨ}L|gAOlg*#KGu|AHΉ5 .'D!~9ۉ 8w˼= LgО$_dmXmlc$dKIVjfz6cc5 ϢF={XzvDkDW YSb˞.6X8}+jC=yBqw~ W?Ԁ:> ו8($ŃwnZ0cT3cZP~'qb wR'ʵz֚Ʈ5~֚G\[k][krmyY¼[Y ~zHmeP[9\jKIijY#Ri[D*>΅;%b7Ub) qbN:%bC_q ̑`zGW=O贏O9͑s$p};=XܓdI6de&os}>Y|a>gX>vOv힊p힒<`;`)n`S4Om#SR> :1¯qh֔!@5ǁywĶ͗uv|ƋuY9wxk5e:XZ'~ﶟNt=b>O*ך}_ٺ֓6F)6\lK&<>D|-pyvϳ%ԇRC9؏u=6 9stxN/~)JOhS9s.Zz7* E[ E<Ïhp)tV9q:t^"۝9Igٙt>c>dSjc.^k]8įy?xt.`~N #QO+6ui?rb 0v~* x$${^d3/l&oNvCp d &% e@׵lp{5; =_{IGj,`z~%xI}Zq0 |w|w|w|w|w|w|w|w|m; G[Buͺ ޮo4q oqϓl#a'~!fif nlsw35Qsm7>9MѿYyd"ًNvSM \ 1c'fS$_>*&\0ȷa7I Mza}^^Fri\K%Ƶ ̝sK2w'~Gq%."YGqӞ㲋˲{XsŃNr') ^C2wχZ>fӳ_(M]gaŏm>> |e,=cAmv6_P[nN:ut3'љ 3tn|ӹAљim!kt Du.'zKΉ{4'q|Aj qScSb E`/KmXI`\u,fS37w~ֳ>ņw1vYˍ̓H6dgu,uc6/" $[B4lU;k]c+p.u <苈_絵yo"YS/thu/_vY,5Lܻrp@?7ױ'pNl7=[mXm l-b+H}d_!wD"]ddXG=@ט5_} B!įyL">K>=G?[>": c7[Ήrnn5Nvc>fk mK Y4lhwXvGAט ܁R%w&zO<;  Nr>oC5W,\hs~1VIF>blb<[af\ꜭ_jNDb߷d%? MYeuWč{u.bxDoJ!3[ѽ$QOw*;ۉiHe}d?Y){٪Dzt K{UD$~Wk_נ5>_SXtpM :քoF)$Nnmֺh+p5 5ϔFM_mk ٞ R|w -rpV`6rvT=sqӳFу8qAhhxēDqobo0V`Gtn]iDƝE<$,W灵ށ U[˽\Kso}5n2s1ҟ{w1_'}w 4O Og;/>+X1;։=H>SIzΑEjwE|_t_. ̝뀋.9$ZmD/&=[⃁+Iq_&YWu}Oi|z>O$`' n,13p%7_rgM=Ay55<䋿֛;1G0j>%>N<\ ;ag9t!9s.#\&:v.'HA#\уn@tC'nENG!~;1`>(X],>@kl nsGDu$x~ 9Xk 5z|u!3XΖ:=[XԈzxNߵG<_瞧_'w6=]!J |*q21&q2pz7'+8 <^fJҹt"?ߜ5E'kN\}ӹt~K:c~imIеNxxѵ\BR<4q?AnCzt-8.eui-k%$E$[H+u/*Z}]7tpٵ{d$s] :}uc<|Zۯ~4%6˙Cr^(bCKc;zT 3}JҽBQWGS[Bjk:@m@mڪkrk gJι^еv\[{\[{wm}^ڪ זNWS?\O}P&{0{0$'1 xl9jN;/K}7_wp~g7_wu֧=K:/k6X?՚i7_ig_hBށ#%#6%fZW RW^\!NBǨ*־k][nrmõ~־H־Ǥ-=.m . 5AmM.B<}RY˻j]!pkΟC\ܑ;q} Lq U4W d_X?~ ֽˁ]\qX̾-\/fٵXwxg<[afmq9-I!a_?B $wEcԐZ]~sk]sE`uU-DO Gӿ<Hg57Y͍p ɞ&Yw)&ˏǁV `@c`iȁ7w|o潛NMGn:EDZ}6Qk}X大BV`R}ސ:7S}0d>o`ϋuUX/:5w`z534 S}`siw֙{u,{%Wh˨/]MF<#˔+X||{;f][!{֜Xnyaײ%\~˯`؜0NpyA3cG`[Y" }+0$[JHV4,xwg).࿓|Fzsʔx0Li]yzJYR;{GV!zƒۚһVw{yg t@,0%9D%~ˁhEğO<38`Y"oּEb ,y)xXi=0֑V~)}" OK^V$Y#҉܅艂Jn;ȳI35N>8/h^i^EBI. qaH׍oԛ !=e VaoHRFc6ޭ_mkԂ=(N܁f܁{=X_a$ێd;lEN8&N$,]SD@MSHvv tg9 `Cs``K_qh X)e]tC.<܊IZonOHL{ƝH΋q3680rQcE)ݪccxF~Jҹǭ L5x|u60 Xc8@mu;=I] 8 Ԇ V#ߦ~9p%U `uB\yqu k:%{<sadyX2ϑIwߋ~9ALrn4G\ҿ&[I~~`o vnr˚;e:ea{2gfx]kK)]?eOy{9QW6KW .!~`VK +IԷQ}DP!]pOk~@ߤYJ:Ki"g))HM |CgAM,qJ@ߴm6uLns yS]wwu}hڃ,ң~A=Tsr) XmZ)j²~){ 1W=>^gY 3qe %Vx!bɔm؛&KN5NNy3џ\?9HgߕX?}7˽o$ZrΦzp;̄`&,9*Msgpsg2_ZIxXEƒR%xÀ1']ξ јl,9 `ɽ #u.`"5X;d'<P_z=KhII%4KwuUCv|uI\wy8տؾ'>`)ar$7 ~⹹!l]s};p+׷áovY׷ï~'o&}p {éoԷԷeԷ Է=Է [ۑڮoGi*}H3VGiv$ȓoG^v};GoGJ}K}J}Zx7GuJjNK pGz _='h^0cߑ./KxXl`Y_^ֹ=-0X̑]'o~9 ,x4#x 9Ma즢hd+Zl"X"$/"+dX*]JBЄD.p%~nGGשoLr>jc 9#Ba\u,b#-c{D`9ǨXتгn*ֈϪXK%${dYIm |dsGoYKo"ѦW%,]> ﴨ$q>AC) n1}ӝ!S5KMX/8wv&zw'_k;f5q&p\\xLtx S[VD~zOO)`K eNk݋կ9Q&jc>q4p)ˉ~蚣WQ'jM]ZviR欭[)R)clQ`%ri`01:3gjDBEID$RJE&)I}SyߦCk~=Zur~g/^{?y1ݹre>cM(o/snCL^_Ư+}X'"3 ?|Q @*#/7}qq+ɴ[KW*?1o5<'d*/<'*?|8}>N}^`<~`&u, 0W{Jcoo!ssK?=nru5cX_{J]lkٺ7r69.gf,>r r7'yCH>k: OՎ'ՎS]9`=WkvKy/әU2Y%әUؿ']=u7dtΏc )'eg斿p y{f} Wmҹt~C:!{H1 ~~\t"Gy&fVE'r?::͜Q3M3#4"/3Ry{f%`dVNzd]ȼ+z|h(>YXֲLp۰ͣ.g:k]/ b{C}7ˬ/ bKCoa 4"$ɬ cX֋LsmfMi)`MiOvM}`u9șKF.$\2fύu7 O^\Yx=rNVYeiW*EY֮]m[mj,m-N7mlڕku5MmS[<%Λ5C}I27AorVYx3ɷRydT^x^e6٘bfc2SKMQ|koyxyy獗PQPǛKl |ڶWm_߷k%{]‡mi=N B@q8ßrv)waGߟWZ:V7YZv QщΟYs+p6O:1s|Nttu9svv  2;Ϥ3;z x- lQMK _R$Nf%Nf=&em&In[3C%όxcȩ|ޯ}y;?~^oyG;-.wƐ\`}+]ducunlunkuksͤn H:%E'/:͜~9.7ڴ72k먼^ET^c?Pyfֻ{S{S}>7s̾ng:M3#5_0q)=iJt3L)=iJtJoXw'pm I69s οo'u7.v/lC[OC~ˁ=e{Sյ;SMjsәt>s p_щV9t#OI"щػW=q L֯\l9xɇSy À}2j(tp0}ާ}KLx*㩴: `:oLw7Rݍ0X`G5?'S1u}{6v4{ist`]g OLl.c4}ǚK6pm?=ۇ[xq@u錮ѵȗXfO-&>BsoK_m+Lt9_-|߬7DoVrrgi%!o˫5rF`W88ۛjڛiݶvjk5ښDmIJ΢^ޥ>.j밴>evѸ=ȕ\ŋSHJ31*`ےbfK-2_֘X#->RZiGa}aG߾bw?H9t>G:sL~_t@:$??I)?}N}rՐ!$|u-p1wQyݳ|ʟ2mg\C+C+}^>R> ,1s=95 <ױ2]45u^Wf쾿\ꎦOPR_I]3bꮗ%ܺc熙[ ZlmbKky.cbK|->C}(>x x;OuOۺm4n$ ps&.>F_jS_-#[]ۧXy8j}$]3#|Ku>z?]#zw HW?,cLl8qjWMcm}m59uh[sQ ?] =.Lˁ|Ƌ?0 ;V@9`p yV;^;zﲝI%[˰}h}h9PXƘX 3N?"z'=Hϋg1yG ^1=R@.v >NV^bׁI$\51pp p#Į``6~ɇ|ɕZ,|u`i.kp>3+pz>nM(IdtȰz:H1,@+mW}nw\Tç:sK̀KHI.q;}~ bӱOǨOGc;yHtwj:J, ZK\ -ZӉub!0ѻ~ OܟDqƧJMܭ|#IlCe2ߡl~zHΙg!9g'}¦?_z(8'\cD`.? OO/˨`K'}t*v|xq)`OӀ՗a\>w{oAC]9?t3j̕q1v!;cC#D}Y^ u͜/++c}ұ|}]LȅρI.cI> ~x&W;V;^@u 牝ybgzYr|`Ko=OHu3yb$/-Xǻبȯ;s>S~x;+aΟw?\֯-ͷq;Y2 8t$y>9tN'EH|ҹt!Ht4srxۥC6}x7!:*/?x;Ś)}6kJ`YW^w9 .TO\:rf|Xk4|˫#Hdo:Uʫ#&N^ G=" g|GDjAjk"5zZJm6J[O):)=u:g:Z޶umz$-3Got(\x+ewPyρSy͋x3Ic_k,3H H$| ;H@/2#gz(v1&vvU-σɖA9s llt_w4[k+*qv`{Py݃Vc/sX,B{!чv!!D"C,2$|1&vn?2jw^h^H}0r:c`ӟ] ;tm},>_][CJ}>&`;1GLz A.ql*yFzV5;&߸6=R[A.v x^+'\[žAqa 4\º&^@ #;ID~2ØW\*/-=\<ƕ<,> |2\|$={X|$}tXM']Xz"*#yE0=ӽ0[H^,g`;KDX%y|6>}H`iD``LXy,ɫ\jIQQeͳjgʘh>ʫV;>j|?Վ]AcՎckۺ9nNIqX#NYpq˜xz/Aq~=rcoS/S9.S˔W#zЯz|)#]nZ>rqj.7Nm6F>pj'6GA6+ t:OW:O״:Oөs<$=IgN:NJy\fNN?"9I>70u͚|c[>k5muz|ϑ{N|cBP߅u0WbYsu\/jk$Δr ).˱3PܣZyS]A; A8 . .EmfR[ ZjSi Mn[gֿ?#߶m[gkضe ]/OZ>/V_ 8LĨLw*#9m`ivw3ٮz|9-UםMW7o%;ro#.*gt-Fw t {H-s 鼟t>J:{t.$oI_<<ɹ%?W;1LT^^-T^֯tȺJ705.|5;)ѡT`'[c>boo}[8{{k{g.úu\-)CG=ϦXZ?}#6>}M}玁?ny$wtjD޹>s} .G;3p#Oiz^K3\@m=HmMfP[ ejKCM!jmBǶuiF-3n4u\ArYCCo}v+gBo_-W׈L`]#UvD,j>3 Xb~(Xs!N_N_w;}uo|/{t}ݭ:+ֽւ[i-Uׂn2<;sƱ;`__m껐tr}B_.. O2\] yc@rlpppc}Lc;?~vS[m[{l['ض)maoV uSl[mm} 5ںڒojqs+IymoVkS \ʫ;T^%_X?o w~ ?2vG{H?z^ӯH"#t/GwWP>ܦ>npmᄸ35@^'y*/Bvtmdx_ܸa~..nsshǁ6/wYawE.+,|tM:?"_\L߾wu3?ݤt=;X}`̚8>`waO?qp9qx'`/H^I/wL~q)uV_[܋h Ab!o|)1!oz~wq#损gw!/7S>՗)K&ܩ ?S N}N=_ ,'Xyx*ɧ|%_ +۝Eԟԟꏾks琘25o9Ly$01OבC+Mlt}߹[&̕;#\ؼYO+OI<|ږ){YbOxU+:eSV4)>C(z>vOr<p9y$pw*>{8r`Z xxXczb@1ռ{p,yKwshwxX|*\8_Xy8x:e[v gs9PlgN`;NYyvqSvAzegI^+z 7'=[IH1|3{EW?䔕!Ή~Alek\I$A%΄T^8=Q;PKaI@@Z`m60}c /i}X K e`!)&= R"^ ?Sa<~[窺p{W5p5W\[_qm}@צs cݤg BzfUD^!=k Z.ӕ.U]=Mi3%FӁ\n^`90Eѹ F#0uNu| tn8|l&pXϬܭJ"o'>Cpfm[x#Gu =IޣfMsGvHc{dn?N p3׿Nu\.l\k[zJr\nvۀ[/738"KǓiEҿC??Cדm'KOXXEpʐFk{v|*-8KĜ)TF \r=KN.66*AzBm%$W|䧩[=Um '}kۺ z05Lwkq;cN`= w<䚣§k~n΃Sot6Іu [w=D㧑߅\cbѐx ;C$VV;xر߫wZi^9 ?C~S8o- .?f/ʏ{~Q)oqqX|+甗u"3CVWC vjM͟q~o7/ ~oO?|']wmpޱ[HG]\`l1S|2׵u*_ `]/=L{iqv~;T'/P&y`PڳscP'8tѶoCm߆'áETwX7&q0z~4,a |i:4y0,`=؇qX2Lbpf_yx_Ww15& /Ə&=+9VVp___!,B"I_ _p*' ԕNenSa`m7qʇwʇ^)pɫRy]!Py9O npl83\b``zg׆k^ 6\;bkS}},cLDN{"a_$6J(+sgU!~+ $w]0v'a-.I8 mʶnbm[71Y"Jl5cIl$6vrc/!MT^mwx*Nev:s|`Yk"WKN)> 9I q5Xޘ2yId(؝YT5.Օ{ݘ'Quc~čT_TWԅ}uKrR?T\H5$=T$?` (*?ʈM#Wy>l@zO6z@Hu`"ȵj:ȩu,NH%F'sUc'=v*Wq窲GT؝ʷRaTwՕ5a~&̏S);..|Kb#ɝ"IKiDrə#7o0Lg}|~)rt8Gh:]L}3t7XH;`i݇4E1F0W+ʿIopY>P*XKOz3/5m곿ώ\t<5bk. ϧ 28x8~;!fg}691ߊEHg<~quMy䊾)V\<=_)/ _m8=kx1'nK{zX˜xJ2>`cw88x,|t.'kI|Oq8?Hy!= 95G͜Ԩ$kd?N"H>Z| xE{XߣI'\eLs Ri`O(g(g[FY9`ţGʸL~ (}Q:{taA q<^Qk5z_*yl{ѽd\Ѳ5/X|XUAc5>>rFʘqqVO7CsҚ`ڕSmjkm]ĶuM;5a5=m[}ӹNikpOm͠^R[-08\#6s{ͧJ9/E*hKLV'd*/> ,&K & =Eyct?X֩X'_<^tq 8݅xA븮_S.8BGkz:k ])ο&@\f8y3ȱ߯^L䈟51.S>h'O$_9p=05?+R?y<k^D7k!7@rε7kӀy |m{ژgӹ6W<mQX. N5 ~:Q}~:NӉNFeԇUԇo*0x z zBΊ-u,i1ب? Kq~Q}u.S>z~RO(yZVp՜Ok%ZIC9 \~ \ /jZ|5||gөDujjsj;jOmmՖpWI[l[kڶj׷mni۪ŶU;׶UVjnik3=n[fnkӎ 'D;&y[~:\Ֆ$fפSED{I$Z4{ 8I8Iuo4BI.q=˘D2&O4]!qGlT_}$/BN_Lkb*=y:ej/Nspu:wrS;8O; pSgw:c*8u&<ݝ:'ȍL!sI= S3N>8)"#IUVg]9{ߜrn椮Grn^Gr3}7|+W=łL)?B)E}`MMQ΃Sh4GSh4OS,4j`^O>Ocp8>C^' |~2hѡG]W{9u ]=qyruyr}<m.OovwO ^꼾="I]sD,~ A:g΅s9Yߜ͜\A\Ia$Lϡ(%T~Qy{?I,yRh){!`ceu~sɽsm}ɽG{;IyKob`N|cwjٺIMn{QRwpսKu3IuX\z"<|vX|954U X]`<ЙT:c\94}1j>@,!twk,}# "K O}\e*(WVH\e*ӊՇ]Q>>Dk/Z_I2yCp;7\ug&חC3̧V{=\9R?d+c֫b֓1N=yь^yr^Er-s0ɏSy]<^[~<֝.1- }NgX;NwcV`i<J+ŧK*,ͪ> իqe`O |FNYs$}XQsz.]J_ KIZt":z;EqCYY|u7̜ԯ'9/YMj'\lU8T^ւ,pʋݳK̺Xօ}IY|xVδ|xV=&kY OzqfxVg3$ۇ o-`W`z}}ad[ XvdQ|s~|JzInѳXK[;%JaPrN3ކu⸷r$Lr9Kz X웵X` "= `] #kX7 φ.6}~WGV&y+`G->=lͣip,) ѼY`vx>["|>gK^5X=ֵ S&M2[;Gc`Y~sc4J7S&I)_M~g9l?'On`'c%O%ӳ{ s轆9?Eԟ'9sBY;/$Ik.=>ḹrA>[SI˔ǺӸe8z1g){/Țb lFLh|_}iTyoyW\-Miޡ,B|p˷R1E& ^5~BIn]Xg]h}Qׯ"`u8~*/< 8^i+p/TW}`?lËg} L_Juo>yclC΅62Nrs_q.r;YCOWה2.SOʊ˔׼G`/)j;'04.R.[\n4I6sirI}`KN.IK3$l&Hy;DX?NY2\F:אNpi"`&Ys5 :Ĝ$5qltϤ#csQy]+sב]w+?չz_ \\ꃈlyt{= y#?OW>ӻ<=O0y۩tl= jߵ !Ǻִ\BПz6;?&qFlz_m4m^4rNcMX(c qDup[S)6}\=K-ojm|Wtfm5ֶլmYmYV\V[-;fzCur H1 #灷Ryke9G0/ p%ɗ88*zI֩+3_w/ <|I__//3 nK2+e\W鷺 L2u,偍 ywi<T]rf.S~I͸Ly'Eӗ%?}Yƞzn+T<)ǀͷmԙ-r3p[s]7u9S7s]7u;gϩ;]>NKGmm5dj^ӶojjjAZQZɶռm0jk,5ښIm-/t2s|ѥA.~x'ɋ|?(ǻ-@rNe7_g~e yɷ[e5 ~ _0tA3O~~@߭.@:t`W;`:^f.̠rXx,l?t!bl8-9 OLypŘ˔ .Xjtr 46ߓm⿐s9>͹+J`[V62[ 鴔iYǶղmeGVlV>@jk$%gRΨysBjMjj3j[jKO|mi]~ \r-WXxE6AIn\H{vI[yLڧgI8L14c[;i ܍7Vr7pZUzZյzZ5&=mHO@]=fBX=ra@$x8)m-S`T2>*ITÂ{b}^>/ֻRbuM`{W'\^ T&Cb{k Lqo1Ž)-Ž(Fq5{uu7KX)3'۾6oiN8X8].Iuн%|gظD8V5>8 󔮧 \ؼ؎X: |Cke릐,GlqZ˷[n.wzĺr |imrҵi-9qZK`ZeXrwW\c;H ^ \DS[,9o9y]e5g ~<z̯cqZ4zbO0WxJהE+enw;ާTw?=k)'u3mnl6T7M"i5ciһ^C.}sH>ss7]|NEBo&_WmV} ,q ~oxI@$O\X^,^K{Q,ޠ6o}7ۇۇnp!)&=tGtǀuM?;#,O ?M\yR]ӱF,XX$Ny$geKҝԟމB8]漭dq#HYg']gaMM2o{N~[5ֳbmrG~[y|4r{,0zu,N;sngb0Css̡؝v˩Tw+AbOR{v%T۾ K+et<W\4Qu$_O #zo2Db;_?~= 8C`iӀl_֯cqwmԾ%wڇ0?sվ'c2Wi/߽؝yT8Օ81?Ng+TwՕ?:JQC|8{NT^؜˨z&zƺבtCgk+5o |$%t2O0rtV>:ޗu\ S]GQN)XƒupZt_bݗX%}6{Un.·}?Mtg3.g:$@n^ޡõtӡ>,Oi|yOi x|C1p# muFmP[ri qÛL෨ W֏.j0u޶Q5p(뚙ێ//rJKNxWQy9.VӽUt]W]`=[X Gս9|]_ {sȻzG>nw>;>XƘ]?S^{4W9jJ~c*lyǎr!@>p9q .:tm 9GOz#=ϐG[;/uHz&=qt?Irs} Ar;#yw*AT^p*q+`z=z=a o]]]jzfujzf5k޵Ym2}Oһ6 ,Vzgοl˽Nea\[wf֝BkNڵ{[#uJ'=!ӓAz󝆉I8$y,=;1Tp)b!;n.&.˾;v#7v[ NN yUcuM ,ljs+ƌ%Tiy3Lyqb)%y'H)H%Q'c^`rK`=5tyED`{c=޵`ճe-Zc5`Xu`͋kZS- {U? 18$y uv4A3"n_۟mq}v}=?Ύ~}o:Yc=~7֔ѥpȵQ:۰;]˻i]ڸr܎nKusTWc>.rtLuQݧ9w;f,]^uA-O&ګLϡj~˨ęX_`Yc;ہվbkuC1bwZs'0!aI<ᘇ 3LJ2'}72׋ q#y\]Sd˔_˔ڝ2e~b̿j;'< ToRjM@C.7mc ]p {A:I9WtbPO:"-{\4sMP5y05|?I܎\ӖH8IH`9N&=F+?Տ p#CV|x&]AuQ] {4=S뺌cgc{b-8ǽl>֜`T87| 69ď5?|n~z0t򫭝sdGEȟcr.,@0!-hx8[s= дpkk{jOjm+Tƶl ]g շm/ _Jm¶P/j.jk$5zڒwB^ pI {ׯJr6/S RNe4.)]O/|^w,ָx+%-Ie{o_7[٠9<|dS :o< c,dO76;/}~nXF}XC}c\X$۾}B;nInե|BcD'gO Ӂ7SjgS]yGl3e_{Xcnݨ\x7;F+m8j6YBiw6E`:Hg5鬦j 鬦0j iYH{Bǹu_2Վۀ m? 7SnbzI~[T~2\a֎OC/59濆M\-\ '``?ڍ1pw㐛&^t' uÕmpm[7,,Et(cF<9pDn2Vn▁o:L1n /qǻIsi7Hy$s7ukL;phlǞ}S˷Mtmۤ9 Xb4g7)M8r3z^$ۇtLg cĴ\3Kn`gg ,v-l8M~Y^po1?83W^6"Oo6!O3M]y 8P[%IVJVm+RǶihۊ[K[HV$˶Cm DȼK܊ s\npɃT^8[ ?\Xbin`9oɭ ʹ^lb*"`Z/6z֋i֋ϓ|N.xk븮EuSyTW|<%eϭ \L}\roN}զNͭN;J±]Qc!r,\XZ.Ǣ6w981茶mECͶh5zzڒlWn6eP[oP[kOo_=ԖfUFON=ȕM{\ry$D3Ry._SyY;rSN흿 ̀Ḱi흷y 흷y 흷d>l >lnE}Xab\[zq cOإ֐>S߽_l)~EFry(d򫽜 F=/'k'8O>ȓ]d˟l.<ݝ“լ웬Vgv'ҙM:{<>sp_9t%SH,ҹPt^4s/iĖp5tN!y*׵##1*/< S򥭔/m-`|n0K[)_JVʗRKʗ}Rl`čKÇFNrBN{/u>Kϓz^NΝwFp`O9!py3rOׁ?)rw#߾ݝդs=,&Iiљ|Ft:c Vg:3ꌵ:c6sO!/~[5 ,|&kh[ŧb-A*z֋2ؗmw[m'4O^ ,khW˶I~{mH^Br-]vI.Z" *.FhTTdQ $7M Q@$`طGt75:82hPPTTtկ_x>zNwm]ݧM 3뻼R;.{ O]~/$H?ߵ ]v6LkΖz6'YY;`[UtmO)$M"`'kuo@b;!t ?#Ԝ>kA/g2 W?BRnV$~&F~`;,g6_I]Mh+m:_۬>+zX? |Gŧ@w;__ott y U΄:^gV?|d#Lhu&t$I; :-@$a-AW CtiB+aD#~ m ڔX%m4%snܿXs} `ç !I|6i%v[FOg$(%%&A.`n}Lx8&]9!]sX}7 G'x'xd-Nz)}N}5yh` 拀"~k `9:T[Gz٧'`BƜ0xRE9zQRZg&__w 蝾,;}}z/5G]=ڗӈGs+pK\~9~'1/u=ŞK]7#tKgn{vg݌~ w :t` =eWxWG9$yXʗ5֜+zگ@Eģ>dŏ ok ,u2?*>Jw{wD px{ºxjA&~{^7oW&AoX"E۠YX^,w)QL)Ɏ`8ăIJ<֮,^72O'@<7P㔿7#2OPxoq%#.\{o!;]6qG_c ,טD(&~Iw6wY.^0s)iX;eohN}zSk)ƶ3ǰ-{;5;gF=jeBz/oeОq>;;u]^u'b,lBleXm]ƾ2@^2A8p ׄ'J<?E:I*|tJ!6LX a[H46<위~>jsΞIz1I wIv+&I~64I{Hewag,l|.X,%ݕ=}w-癉UCxHށnnkK}K ,-`ub]EWLHbQrSavU>}w Γ&?w[?`((Հ~;I .Dwo"xo&Zx=>/}/<{tַMw{Hl ,x30Cw{=tomCk=HbV`ہ]ހ`Z 07ɨ.fPo z@ELzw;ݳf&7_-zRbZg3=[k{=)7z=)MIO[Il~M,5D}^c"{D${9DOR;[W^{][b;`~}zcok{t_яaբ}Ti-zXXk%>mOs 0pʣ!I9FxQRfZ|t5[7)rߙ9߀LK Iz=9EzCWD6NoE/]yW1;coHDy_s? woW}1_DUk w:_coޝF / 0ωY:ωx{_G}}9ku?M5|b/ H:|==2j};h"3XO#3IrҹtN:C:?s:۱ms:&9t'ԠיjD'NIjsÁ]򉃀uM Kl$LZFb>6q7k88&7z޵F|~S4?oi 󉣁uړߔ欏rEݐߤp(@ ԁ:}}|ӑ:~4EwS5E6t~%:;I珤יvיVLߖG4myk6_$еLnMtO%NHNį>AQ"B-:~8N N 'Z Xۿ.dsIVov+նǤ 'O:DrEf/́QgrOv6Q';h{ҙB:I`8srD>2ѩs1\O:_&ODgV$?3]O]_"%~b*-=u3`A }uP׸mֵu_뺶XxliHcK7mq~ɨ KFcO_2q l2`hG:Hg9t!Dg9MdL& IZ|t~$:tZd|rQ| CwC1Dq8uMtHPz b8D vu_#0csCtqHc?֯C&^{q51|'֟o_2m)w~ɴK?9ds%Sl2&=L!٤s0|tJLdN%Iz2|tJMk̋iups)[;ƿK'pd qb{\d W~dwA/F`/|UKgc2m#,2m#Gtk,On9Mtv6:Tٛt%cI?&|dM'KIg)|tG:Kcm 'z^]&z`upO!L#Y#u# _P"{4NpX! Xr!K c~Xu?Le.?Lu-uM]xH[]#~?Zn +`sQ@gQS`^?]~^??~tGy\S%GXy:BFoH c|$d;l#Y=zwDc.aM"kηqa ɪ1H)lxTp}`iC`uT[u80(( aG =v(:kuoh 44s~ bQzrd^끵, ,/y2xKw~x^$oޗ|7q1/zy,YcUEa KD| Y ؟㉿ 'Bp6_ws5{{|>{WE'>j -'d.aO\S'se;p`O/vQCNH- ƞZWx>&] lk\Hsd-E.}FV`[7^;QY#~$ x6lM2YwQ_&k?!ٳ^"{e-;_."Lw[SF] >MktoT@9[II]OɺXr3[sOiU>\ R ^n]wZU졺?lskSwӓ^ z@źֽއy`[:_>WGC̘oгҳvӳggգVK84=.6z<#?Gz@zhycܳm{gH^W.=pR32o&~wN#rXJXsJIˆ-c7$Y~Z6dǑq~:y;i w~LÿM w~ZȝӕNWc8]׏x֚:%ߓ:gstϝ:NԧLS;=6%1oI37<-$A[bpK\b 1cz^&1 VϺY=glճVGzӳȳʀsYҳг YsY+YYѳo0!MOLֶ=7_;RK k.D1gO/gd֞- Xd`)u3˥^ 1yF1!&>') Kp.#R՚ 8gtMANo@Sgt/>ȩu}NrlS?vc8+X8dHvjֹV>bg:!$=0&uqq]m5 .nc6v.nNrqpl.*l.Z*[d@|\Ó44E4u4ޡ1|LcAcVƀ`w2i z]ЫCkzЫCz%1ʔ1`}+KZ{ȁkEt\D%~Yw9YCggH`O= w=B^.y]?. ,y4XФ'us`!5~X~W)l+~|X~#Ir/קw{_`gk%xtu:{:{NJ׋\-Ig$rg5μI'=DW? \Jҟ$M$i +$ul0[QN1@2XבY Tozl`u_Vs)ƾ./rۮѓ/k`Bˋ7{:3EbT)~ޡ.yt:\us,n$:?s~مtFIgO_ڤc?.]נۈb}D/'~1"~Qò@Ls{k@ \4VxXL>9˄񹭤hz^8>(_/Bjgg|*=>/,wl^.1 >;鳃t&y9x9Wz9E>khNC33^ىtFHg6-quUտog]^%0◾+MB X׾7HV;%>w;^=^Z^X/ϪwJXInǠHv o6Xc xiG5&o1\gyd 7 ^oJl`T6`=C/ߨ^ lNjXn'ޭ.ߑ;燎%٭$dwig3}-wx-I+J]99p9DO%O㈧@p `}_ ^ ^*1|7rK`ց`eimc1B:Xm@؍w:=v7leXu})L.5w9}'v^,דד;dEK|Ş+wɖk$bMulʕs$]4!xkMn܅az8էO;#Yɩ䇁 +s`e,y X}.=e/ xdϕXצG5߻|>}Ly;W;9Y~/t{ovnRX+F:$FK_,`=/owYU4{UwN[ë}!;USEߵaݩb*]v"=Ir6LkG=QE1v\.&|qHo#.>Nu~>39}dwP4=b`w{֏fv3t$3tiE,)s\O:_&ODg[a!zW е/ܔZ%z/˵D|hF|`LCL?ٗ%9>|,Ϙ>>ciHor9\C.ck͠u~xPw/ >mO:SHg/9t>A:NK*:-}\B:KI竤=?щZ:+ЋJ~ tkt!q"~Ɂ`xӀu?xjxxjgD&F7}3=oI~X]2DoKBauloj4X͟i_`1>1 53`؈!qa2O>Qg׌`]I?O-}[h/$"G.+v. |{ہ篮1 .5*y'p]׽^`#XVw?5Qk~ \భ tW|m}w Q>a?+7XWjn{PJ ~Fލx&7#lMBb}qtGYQF}G`;vǀO8y33Vу5}mpsyNbÌvz|G["v81,kxїE~xkS _y~5ثw{572`l{572` E5Z;O`俀s1{5$gS. kRc.Fw\ ,~祿^_;G3r{̑IQיW̻k$:[]':zyͼμxٕtfξ- 0>S.N܄6&z[|pIJul5)jR<ԔxHX!C)uQt.&(>R:o9bRbĆo_!vsߘ۹VX>!${dψYKˎeG,5&\F|Rr#rJCD? J֯Fu_֯i֯hJ=F`!Wu_Wu֐h֯h֯eJ X}+0_W˙!WKLr)wn ͨG.FE§ ſWDn z#\9jk٨weVΗH绤s+E:NkNk'gUx:Gt"~&N/_)KyH%fo,r76 p;'Zrַ{[{k"$MRRKJXv:3#1Sa\ etl\p Eܗ XK.u~g/k7ηHǤs+ʛLkUZnUY`T`[Q_Jf>BzJ:c}3#5c6]]eoK^Kr֗2X/Nڟ kk>bͭ O&'v` }Bmyb9~ 1c-{ :ljb['Ԗ}BmEӁR3vs>}ܮkv͕okwqYs;^ӉDHO)%z&=Hx3=<}|EY`cJ1p]k?4pqįym_2#K2w3,XGËwg:z_Wg:>΂uwgR-K֢:ǥZVGsfثc`Y. O}sߟpGpGDm8^Hg"&:CY3;J:Ǔs\-:w{fMX{Q|]syMD׵x3ѷMw>8I0M(Q.$4EWzlČ:=zoYGYgƻqhWga-:Ygo5GƧӳȳjo+l;>:D x <'ބ5w$~Nk; g#G??޵zGw)y`}.=e/`J%@4|A4jc"w{ Nl;V#1vicq11g=y֓uld3'z֓i,O˳=g gӳ&ӳѳVг6ҳ^g5~=MN%#=^D./E#{u Nr!LpC`٧DKDncka^\̓_+bIO#Ķ l;*pg R̈́b+vB=/;6mC,l>!0fl?)a<'k2aE.+r+p K^Gn'zGWG?J<ۀo2뿩 J?i~;{N`Hs` C:3ahs7ކ}n[}'w "c-n=J{قD>-"ȗ˽lA=/[p36Yb.w_@e xAv 8M_s>įX^`ͻң>5i ^v{`ͻ]Ok?Xx.G-5.қE:zJHS+7$kLόD MA/FKC[I 6ly-'{2{%fJm }\Pb a s0['x1f&9bLO''v'I/Qc'˗DPwfb>߻~42`cl?qMGkd7!Kpk%~H&pNwlW7}r,ghe{kYrkzHb&_6pTl!)F#b+k${>U>%ڍ.ڍ^>uɶ!YY`Ckv.O=|}H5=$焑Ո^VD:X}=X׾!I}p'ǐ@" ,Gdpö{! ϡrCz^9614X;Xܖd$C8,E怎zj8K@__ 0n;zք^7֘)oB.L?d& B|5߱BNX@~C~x:~q; u&M:bj&}b;d=7K kg6*?V,Է,/ Y9 ,9@NB9-\'uU΅"@ad&05&'7%z ׼܉NY>o{؛x/IY BnLopsZOeQoj!p|\fR`K~ _*,.x>5Lq0:\L:#3tN5Nޓ4\J:7ΗE6WkzD^4R\Nį=Zį{5`E S)6Dݗx.xloqz/ߒ NsEg C|ƕ68s2@9-~yK'h< x-7§+\|N> R|Z>%US kߧ`Y>vwLC NsJ{ҙH:Hg)fܟG )I4ҹt!$oo9&S޾Xmuo>4k_.p1ģ`ڋB{[h/vf`>}Z>`^t.f>m)?#6ypk9Mn^s7Sk{٩q${7A*>fjM%$;DdLd\T%S-O=Tp _}p1/"cj%` >rV[elKΦ^&9z9pqDZܔ證.M~`L;u%b`sbw; 󁷒${d0lk=aLNeB"ڹLI+}cjM*.pKM8/ZxW.&~{=`2۶z_&kPj}`l^I6FS^⁳IO顳&7KJm ,,5$v`Խi7ԶfԚ.fE=V6؈УߗF-6~1fsgyҳl=i]9Az΋Ժi.wW9jN?c7n&ӯ~E*&c(GiXH?`ʑf#(GSk >cyi4o4 928ۼwx7/o{ؿ}iNi\\\\FKJCj!OE"^p+`_Ilk G<́Oh\@+n~Xs6iQ& uD3)5wZ\K=,5!47DD%ܭ=r`"iDi)2)X֠%${+l-eDLmD3Xtm[Jamjxf:,az 8}?=[x}3]FCHv,N'Y3f|߱}HsW"LZfx6o8p3M3o:yj.gZjg'<{-N=䑙xo9j y<)>g}=όǃ873qnf\>3LFo7yƒuFl8CV'̸ <ϐDf|'843wlhƠBi@K!]{lcyğOg-lI}`K= i9׵\̌~4-y.fLڋX s73JVQU$2ɖV"_f|J$.֧8ي)J!i'[ڗܚҷ%w$z'W_g}i+i?jo[{ߵ*k53XK21=e[KL+Lk[z|׹lg?><fgg_3:C>Xs,"I糤SXGf#ҹt~G:!R_3Sj7T[έէyu _r6 }Zb_D<ΦkMNܩ5;H ,16$l#nz6ߦ+s1n:_ja~Ά8r)ž}V6Ɏ $+%5dW$IdU1Yo\x>m ҷaצ5'zG| !(hiCް h/=fӰ'my=fkz3s1}ƈb<>XC1 :`fb̮g%~9l9웈9>f{6>EtOI x===sk]⑳y]=/h}XXq!+m0zt.f@1lO!kfo`f<_I9~~c ? 疋}=R7Bt=aį1x;"來s 6^]s7kkmuG!KKZ*g>O;)<-0w$۞dH6Sdѯ>Mdc?ECHv,yZsyzHs%5_.$ED/&~]/^^Kģ5gGw Vs `ͻc<=#s1O$>_bb#n6n٘ysSιQdYœ$ۊd;lXdgd\$_p|M>C<'?~-mo'[~,mF-ҹ9O>q>3xj#4yC71w3G~J{IE??"Hz٢/[$aCS$\j_TviEtD %x{7 X_Iɷާ}>}SG9{_9j~ޯvXko4`dQƀ)qv\e vK=Gbl$|T4~hׁ;WE TQb1fb1f^gOuu?k%Ys7.f̭5wgm54zVozsG.vsDb8Ʒc1L ,M5h̝ wq8w_a_o5 } \Ij%/.v6sT=H:O{.::5:ʼnN":λזt>B:Hgo)y?&]wNti].>Mˈ_zۈ;Ț^Xan{ 7:~#pe.fނ@_#6|%6DMH-6 s7>[Gd%_HV(`3O(`37}}}Fgv.zz~7Ft8qD/ ~[x$oGtע6w^2@fV51B:LW&g2a8O?[>ko0_(qs9L/'gF_1.=:uDl ܖįq{?p##kz{`s?P3y@k5?\y=ҹgw+zi+: |U{v2*^-nLwD9>H$+Z)s-; ]@8L;}Aף`:]7̥WHo&]_}& b巳巛0_S,ʾG_l9j?,g/;?eW,Esg05V}:b\NGkgGA6Q:-8X?t.f>7]~k~"l-Ԛ/maf?of-̟Lo^+YrQ^]co,p57xxk?0 X}:X}:X[Im0A:A=rf>rA),V;LZ"Cw!j~T`(x{Hmt.~ EIO>)$=Yr4X\ |*1`oFxdw<$T ۳nugYp#=ƞeE1f埵ււA1I9eE,ԟsYkY/ҳަg}BI< Yֶ N^L{+{1D33'gkiK<ӑxa%=R'S{߾ܟZ_G<_.$~Ͼg#o'=|;~̷M5m`f"gw##~^4zD|gY=BHď9˼<"s^̏-4]44K6`({c~;qvXZ ~Y 9۪"?Υ~l_c\my+:Bgͯuࣚ_ Q:Cx޻Xֹ<,=!`]0G"?t+l#ɣVVH߀OEћ;z._}QkbqD/xt^Ku_\"x9ZSJD9{_]&vאCР&ߓAM^xw`- vݮ+PKt!$;^d? {pгgY3 QGX#.p<:4pxaX(~"BhϭX;xkfZ[GĊ .kDU.yEUֈ(]?JFz+U:d&'˼Xג.|%,ھۚ| xx.:f jnjE]MC]2HnHl+oQ"v8AΏkE^$1]#f%#nY$nĿY4akE\L}tͣDFtڛKg-#Pt V`}]ˑ~X)7|wk M#SgK-z{/l֞DSģ'~=<##a}=v`WD@`e1s#;["/| BryW:/9r[,c/\Do:EG._ME/nr!=}7rnž,UƗ#Du%O<{ 6L-vKU[J ؚk1sY u~_x`Ԝcuc4{=zEX5r,^-< x ɾHY1x> TԜ_ =8N{/>W!GW'tUO4]w"z]8nB_emnM&6M) n7y$gŧ߁KHz4mtX?ty`oF%`}̒k#wKbX ?|K>u~I Kr`g lͨ&z%3_:r`<>'="5t^.QXj~ƕtNQ:׍  `juQC }RLFe?Koe)b&RL/K3c_:,n jґs2G:WHM3o E:SҿNk_?O .>͸xы_7K d4~dOȸ@7K?he3IVہ5:c顽C2dϸ Xz3ulm. fY}4Მw]nC7:.7v] |ee7nY6t٤s)@:kL~6^%[3锿_81WġքkLDtf!zտ.hþ)|{^:S3י[eEVKvCߵ|Hb[_u^n}}r}[_s6\l)b+AGH1IDucy"O$gHd,8Y;/AIF pSKe`Oݭ-_צ$0GG} ݆nZgRkFwY?C:3G}?O$g;[afEتpˮheWđl nEhIH6d{,nEo\VnFOeO/H gi\5_ 9+DnBn*(#%~k `=C!K e!Y,r؃d11c.EF.q0x7sF\RӞ.VO{_ݾǾcÌ5{.;Gb{չt!gΕΕ5Ε E'ޕ׊NF^ʦ^HggҙF:{N+8&+s?t&3]q෈^Fぷ%#~ s=LѣMw+=٣> Cχ=ك~G &gɞ!=5gVR3Gm"|FQ[:O7>N| xz5|gV_5&uK~"ٿj^vU]d\V՗uMt]w&jDDCd ^eQvmzU F` 0!Yu7S|UVlϿZl XM[5*҇,}(N$٧Iv"W-Y $&QfE\>G4&Q{U#zM Fm/jcO<t!!XO{iz5Kr_ku*= ,kJfe`]G ?wQZO.^(}`]7˘3kkd| pMEX~kmV %kģU<.ZUCWf}7Օ72_ W7~#5b.fuaĤY} ɶ$َ$(v6FwL1Z1!j4o wV0e Bl gT FWg>E6e^b>'|nUrf#`X`}d F#yaݪ:P+r;zCbrrN Z\z̛@O_}~c}%/2oq3~1dC_Sظ^s-^ؚ[ApM+xX?9k$>_&,8t!Hx9tZEl5VfB,|tt~F:}Nk5+[dFt2}KfmɎ&I$+weaCVڹ{]@+ND5.#pQ|8e|8e L+zPi{X[W`i q>pv*rs/?$@Ens-Ѭs-Ѭ zxu-uN0b ޤs(O:NKN꒵ɺ23@u'9O/Cj@fwKLڷw=z К6Xkzuc4[7}f=A OP7~_7@:GԁtkaZ1Pb֊pO `K'·OWnk0rp?A!~0B |g~3?"{Ia׹׹DJщfC s^; ·Igq:M6^T+]|2FtY#z3XDģ nuXc` }3;Pc?cc7H-5^7$z躧^oP $-v0a7]l !lb󗜝a7A*nf$~I߈,z "[|dOzJ^Tb73v.5hMNѵ'P6s_2Gģ XϋAt0iM {=wԖA~ :y \LiKs_8[>_lJ~s7;~)NHv..l"8)]I/$Ȣ/*v.h]8Z| 5%z5&~燁ܑd56~om\b.Wsg`o/ϓNړkqXruӐǔ>lcٻX9YMT<ێt&Ξ3tB *})*J}'y~RTjI!sш,adanƆ:s=<9:\:z]DLtstJfďՠ4".=o$~]KZ̀5 pڵPl|@ -_%ٮ$ۃd5[nz|-$YM2.7I>r .[!&fp_X_k<_OI~k=_OzIO۳)쏓^gSa'O$ԙ==;z0zXz$zCIrqb&ͥggmggUgeܳgeɻ3ĞɒwgֶY7\Zv t͍DDFOC ,}CHV K(7vMƒC5k? -qU d=aV=e + ;[믬O~ le`g5tF:IBҹt=d=dC|Dn|drďQ]AW>Ntm< I į=pOuGt,=NB/`Ժo\apד;?pr"g݁ۋ S<[af7bI6d#Y9Lߝ}ld IVZfܵNKdDڵ}ޏS'πJ1~ۈ>#=HWw_>3}ο7J7J{kup'w&-w8@dwucX[9 ,ʞ|x&l˯v6S>gJs`>n=?|:Ϗ^wʳ$Ɠl7E;C!١$+kHf2eqU_%wZ.!z)kݒ \Mt s] ⡻#OWSdwV oÈb{Tt:gq/s~n  ~30)~~+q>/>= sߵFy~굞G38St:>tN}tB:wf2bL ^?N:[-ď*jYLwY 2]sWpӉ_o?x ~B?wj<M3.SN\%֩N-}2Ć.xԋb+lndÜlv+MOdeO$ ɊaC-~sɎ ݧZa}}ځ9ӀRnߋxR#9k_Luŧ%ΧP3]e-w>=s<,5Ft=3?Lm>B e]˾e/`9h,"<X +w#D=`\ 33kjpf.yDGQk,lCvH|xs#8Ī6{ַ9ٹ^"M[M Ivn%R.<ĕɖW&ۮS'1˷WYbd_LEx> A>1\fZs7Ӥ׳&^] \b8fDט8~>=9poK<-?sns-%'G,1q3cLb=/4^fG6dgb]+ȍ EeI3˺9zO" Ocį:*"ܚdէw=#z&;ac#,0;=HVz$`#vx}VzL#'۫%0j^~s8WBC/rv$~9Ks痹WͽX~o ̕[;;sq:>K:_'Ѥ]щ~nWщ}g{k9tL: -'kʷ&sg]zX>D%[!DO#~3Hޭsb%k#Խ ޗkNK׹aW<3<z6'9s7$'`f^KdۑlȢƞ"F;$Ȣ'k2ǥg;xK@/eWZܝ=Hgɦz0a2K|V_~^++}T`]뼦ߙ_mb捁|=o"hy.V_ ᭝yRfuWtίtots:r:Stv~tv$odٝt9$|j9$|j&i7ҙM:sIrщt O+Ƌ8 zj,g]!WRGH%SJ XX}XcAL<2)!Ywwމ?KlD <.sHOk{Y {Cd`Wu1˱gD{-|&!M3-՞9'&+؛L$ɾ@D6]܀G~arc FtE>EOEIȧu-/w={+_] }[wW⿯OZl ^$ۏde-D> z8O 􎲯edr}%V#_C/_ordž"ڶ>ngBJ\AijR%΄Mԙɭp:w:\t.\pӹD'N ڒI[3tv#D'sNk_IM6 0[]:p[#poJ"LEXϩ F?Ocm`<4J]9F>9 }vD'q4O݈; ^#-oQv+ F+r Z@;@D==tjIdg7,)[JI.a].do/†fE;]z'*t98.y2j"9QQ/ JnD ,9$ uPCeB}5T)ꮡ3CDz) P ,a;}?Ϗ=Xm XlbGSIO:9~ ~XGKQدiς|5LljaIX}0:/gS/6<=q4Bo$z u^i گaI{i~7n']v]vf $ۑd;l52~[,BvT5N̊pp^q^ư7n +Vv1Re zc>Z9HֵSw."DZ+^l$~9Xc]>5_| cFwz}hk~Y9vۋo}Ol~ԳnV[ZyɮdW]dWYƫZLI$ێdn!lhVB;U/^ڏG?@쳣.}A݈ޝ%D?܏uxK}}|thf-%y`_wi 9mޝ@n#{icĿ6sƼ0Øə/_~ T 9mԍ6ѹ\ _WU{qk'ĿC'ſnckv$П_ujwѬ'/![Hg)p=Wx ǖkc_0ԘէIg/ `.3voX(Y;ԥoUڋ+ĉ)X%Ť ?_-ofF-w;_ BD?ɞ~kUkOA׵Ftޚ_2:=fŗ3 `:̠o3 3'o-՜X0vJw;q~, y Fߴܬ~Q YcK ,)~K Ka|*/2lUK ;㞵 5ݳA5Ogy=k Ĭ߷A5Yг>gg ggIϚ%j<{9Ntg]4\֊?Rt:#<*zp9 ~{; q[܋XML5Xp27 O*nCw k7 sK^J2M':ؿ8fn8uvp9N? 8=|\=q:/Mt8'fw쉙͜3.V&:aƉ2,`Uij=ʔ1 ğOEO3d&]&k9ǯkʬمum_B!w)Sںξh9_;嵷b_䁵6恵6ؿ\0rxͽE5 |\4^ QOߨo1td|5r`=\H8}S*wN!Y ^\Dcs M ZOn3-$A="`n 2IO>)$=!O^i/O T#)}ͫ=m^{֟-_נ)ݾD,ls6rE(Yo } 3A!71bAx7m~y5օ.~8x!pg`{g[3ƶ=ƶU7unluc[ۺ IcyɬyɬCc[AcLcKc;Ncƶnlnl[oƶ^Đz9^/gb%NO.k*b~"ӟQL6u.K@>;=fK=@3QS+S{ 5Dݢk:[@՜vꥉv"EvDj'Y`Y>$AY$?,>L^M:VT|{|{|1:6CYfeO NCHv4Ɋu5EYNN0m,6WK q+p`e _<9D';uMn K}S& ,~ `Ic_:%-ŏvc8y ]O 8;O ,k6BY$K;˜TR0U'an`s`3iߟG:7_1 k^6OȾɦ RZ%Ge-Pgk*.Xԣj14#i#_6]} 8öכ& VV%_f;ᾀ={Ǟ3_-Kgn΍7=7=y$d~>,_{Y/_{Y_ ǃ=l O/:C]ǃ`6\ ' WF 9 3x;N) "_maicfb_m p)%*ܳ6gm ux{Y۹gmQqFoxBoҳYгzӳӳ~gAϒ B왍Dֶ7 FK3҈.}e gہs_'tFm$ 8jTsԵ XTsΤs&՜3 {jзgVjq|ًÍ{l-ح6\צ{$9v6$gf]NGI ήyl{3}ҙB:Qs<.:7tZl)kL)Db83_sQ_,`24?%9'^fVcs֓efYTϢz~V@,gQ=?Yef̢̳>,<[lj^f5/c[&1i/pxG=_o-Oxlk{/9ds`{/9d,2|j6?ힵ=+>= zV_z0zXy_Y3Yym zFrvh1.9$M.q+tGiēN<'x$Ƽ ,}YLލA<[kfY/#k$1`ٗcPiNt!Y/1h>.eŠ#7-pG/BL;`1~̡sK0Cw?ݏ9CbHA_P_C}M)`g3z 6}78N[ ,\O1ſ1Knya<\Onc7n2[gyK-yyڠ~ AYDJ[!~fKo3Xk`%N%;/; =BzP-f!޿|_t/yjEI;ɦo`sX `ԁ[榨P'obEbfyQ)ƾPآ5^jԘEb> âxOMX#E}Y#YY3YyzV=K~qbɳgUgmm{֛ݳ략wp{fkۭ^z&~/ݗ=OJDoB #~?hDG\۷<3yZW>+Ob۱Ķ<[afkg<+;d"-[E 6-'3Nv[mPd1mb.k$SeOm\BR}9p%WXc"k-ImcQ- 9v[_b h۳=[m{+Ňj[ ~| X/x.6XjOuw8oF<2ؗ~}ɪ-U TMw:KG[&c,eͱu rEuѣO?㫽sU$(\o_\~#dH#-=|dGz<)F?;XH?ۚba[S'1K~caem =;!;#_d;qd5_Fg>gYe.[ Lg>g,58L0rr6^N9vykA|.=(Ş΁MzČ*z~g_wxx;Y|thtxtN:I}e_> |mvG:&sO:qbv}%= ^."ŢY^J2Ǣ7Y^WY9 'Bz؋z1B1" 8es\]` Ȋt؈C"Op}`݃+\A߭9=+%oǡX)1>b8+%F1˯v6;vç8qN|Wwgfgy/?;SDžzv:ŮoK~ 5`[>(yNzEO p@!=/HO_3L?ڕ&zRHT3,=w-XZ!1&!u*iqKW]X#lj.y !j8=wMfN@[j悖$&uoԇPZsAm\q`yԽPs֘D[c{ y_cvU"$K[%W|Qy)%`[S"y 5%IϿHO#w S"w S_) &=?jѢx Hz搞ŤG"|mJo/Z,P{,}D ѥN{8]IG:!ÝW^bl/z~[]"u] 1FO:8`H`5`~)9{ŋ!/v_~=_n v/`[qE%әē9[/n9[/Hפ'Lѓ A= =yș |mv˙mX*ť/'rq75\NWz6Zz_VrW`ow7J~|ij=jd;{ykZk5G\[M(Z׍FM=iNbxO3`wP#>}C>ꞧ@b`<ÏfwԊ{HgOُt ѹWщZqos&\D:גGZ9xY-7tuYDל6;{搉?x4MVHPHP0Xa*t_:9A!z/z?<E7^zs s7{-BN:&G$+g+gٛB?Xw:+t\N>n Z`=譈.gqX~#'@<ēL<ǰ֩K,`= uz.Xg$zIGzXįg/Z!=sz7W>ݍ LO z <x&s֫֫`5&|g `C s7$nHsڐEϒ1ǣ gA7ޱX߿ps 7j] ލa>lUw"zgk.]a.5`Í#kڨs 7~λ6yFzǴo=quO,5Xa|^nt|7e==l9p6g󉾜: D׺"Xk\K_7p5h] ,wpӳYMholL燛ņMQg\g"];> l֍ȥU)m=sÞXzW'MiSɫua${?SdKmWK:zDgr칥[֦)⋯#<ҏc RDZL-9kX/AGOYH|[DFU7ډG93'x&OHƷ8GOYb/=f}oEs;daģ %Y툱-$g?[nbiĮ-zNEm!lǮw[/j &tťc.["EOG/V$sGU$$`WW`TwOES)afo/xks9V.kLw])n [ewk,{_|+`:N6/]"n&>Wމ2նw'C|KT⑺49z` o vn55|yY/,o.'ylߣ6!ۿ\ r>[XfbId̾r'Ϗkc}#;qyW[ ;Os\_ Zio%gǃ16{<o =k +y'}J˹b|J>/xѷw5{7'~])aw'nfv5N% $;d,5@<7Pk\Vj1UW^<~Vo/|k#GQjh!t ?qNtnt!sA:Nby:MYҏQ]j0JF'Á5֜0L<bbbXc`Nvhdwh g~nOJѳ'wv~9p |*uv5[ׁp.{=6Ͽ=@oZ#/1f yߋ-OgBϚDʡgӳ Y2yYѳjܳʂݳBݳnu*=QYem[ҳݠKD.v\6k!wҷZ;[: 4K'_%96ܥ?X҈uHph/?XkZ%=yw;]v(z,=`kɖ;ْ$y =c+%:wت$E ga v+>w/0/w%nwOa.n W wk Y yub p:5_" By%-H@[K}vw7C{ֽGօ=#96l ~]'r5rHY_9ҀjƲ_loS6tk?ԍe\oK(%$dC~0e{#ƖoﴹK~3kٔO%;6xLYǃ5eCO`|d@-ƒFx C5s>wy1v0[|5-_P%|}O`gs0]b}:tN"9s \G:wN;w>H y5Wt Lѵ0RZ˥Ku-wӵ`K l_b_ p|wyAߞ? ɳa9Ql5re&ٮ$CdS?!=I6dGܹ askrXG9O,`,巵asL~[ێp?ADJW~įkX}/i_#_HݘX{ ~mpHN8,aɷN8,uaC:0ݟ9эpg7Ú67knM:uaI['>h'p1|q_oZt3ކWO@w`!o;|q'< 5?|ۚ㟑stN!rVrV㹤s N:ΓS=ԜzDKĆ%'z5ܙ#' J`}w{DCxīe'^,g B's1' ģ<K lx?! O$x:bb+KO"I{asB}̉4O3HV~ 64'䷀jҚ0~e-'> >G]z6~nM'xO⑽,`coG3OwQoV\LNX}'{LXX$\ܖ.srWbo=&ke?{1˕75c%$>o%{"K퉧w%[>!zIއD}<ۂmogozl1ɖ9zs` `?N1R$> ,cH 82ěˉGIVQ/]U2pk=U` '4'~Np }GڷQT ~^6ֵhMK$+kTG}yB֩uj*ccETtxϦCߣ_ [x Mx_Stz_L_Lߜz>]թ.Ŀſ=Ag)çw'_?΀\tJ!ÏCͩqst#;HD Sr1`N&!Nӷ;ctZ~>5kUMtow;zu܅nN-'Lp)~ӄx(Zy[LuWػO\7`Olx;Kl na洜a`dTgy cNN=,lhNs9x~Z$9D%WI腫e-'ϭ.!r9N ܃d5#^5bb_k<ld/j<q8\p`K?~9_|ϙ&~6!~:5eٜ"~+i0I^3ɋL2'}ARp` \/D#5n<6X28jWq/~vN_e=;xeٜ%~A~v6\N:7=(<+:Q=':3ksW9Z8r:ϵq:#9ӗO⻤?Ky7r'~Bwut]&p'[G{ a.=::% 0ɦlj;J/~J6/^-~5Tw\K/s-,&I)BĞ{y8nu:/|^twtZ\x-y~7p!7R2nw{+IVB@0 4 /x8A=Hj<ָ= y0js}b?. w_FW2T/v6/ˁ t!g΋ Dg!pCщ=b#N;΋9$/"`{Z\|4Ժpk? ܒaį p Xjpw@I5z~h{bb5.O |-$YɰI#cue. m_}J/~.>%~IO_FW_W_,;y~<ҹt"夳:C}EgK3 tOg =?'H狢- kP_K'9t]r_L/?*◵X+SIVWvw\C;!אF%X!Z`fHf3$}$ X6KKXl_CCI `__0_/??sO[D:7ytq:HBHB4r:\tֹYI) #ڤe'&wɷO 0D!~ɷ[eKdJz1{b X1,{Ywl&gnsi BI/n'7_a4[/*~|{OgZg% 8t!IAy+|ZW(n=q:tmtmG:;\<&u_,~]|(p%5? 9zH}-ps◵aK'?ޅwa!!]XHe5N% $;d5ָ}XS+t.#}ɯ k!/~i#~_~~D2e9 ݫ> WwY/wYNggEg6et]ÉyE`5 O߽]Gn$+ɯQ Q B׀5 \DN6x~X7u.o#W֋/:xSC//_$~Q'shKC:Wͤs/3w_w1$'@cA!o\){YI~'{e#j<'kXػ:}BG^ %~ 6 _PK'Lj_~L;֟.~."D/#~8|?S '{K'nb*w?-*UZ ɦl:j< q`K_ՈO> i cKoؼe0'_&&~_X;6%~)M:MsS=[-lŋ:'g$ۇdlx"N~$LF 6 Ms2-]%&'z3G75}M}_S'kݸX}X_\yu.Aa⣣y >y^*zVM- HQ}NdYIp}dHcE]d1O.Z_ȵZonI0"z+=t#p8OO7w$YCk}ǵ /s3IdIV=Bi,;u.?}BX=x,p߮ubL؞Y?zwCΡ t\tt-:#:!:!I[3t~ :xl$uUWV.aSŊ-`PD7 *jİoa{XT@TTTԨj+VuQTTZiK-.9|fNf9sw%'앇 %8[v dio90x+ml ,״[5rMA?`+^BPZv3Ea70w-msq R~þ[fox۸u۸+bm}a.yۚ<@䖇"|x'm?%VGjU? }K:黍}.?ƾX wO<kT3'礀")ߜf>L4oօ; sUwk0,0/9-ۥe*o#;0Tͥ=51#n?cU,'%Jp)2,֐R2#.ed٥\/:'y-:Q'A)˩99Vtn;EѹOtO"&)4t rb'=srNWp)ms:|:|*޺>5ߜ`9=܋s~G k3حS&8@t֤=kd&=#`I/yIoi84ȽMK[9mQ{?&Y?ͱ9Anq șosg|x1x"_6O/`{_>J5Gv~R鯜{/G$޸kƘy4? i𿚶i^WA5\d/H_-A_imڱgAsF@nkx-3"OJ{]׃LicF䮶ևjk&`]ccvn#'4}2asqM߇ vMM2ioGl>kv2լQh߬]:=rWN>]`{fE8]|BgE>@䖣۾8td增xL\;8#tyF}ӥMKNm 2;}N\_8 tbmzIvC:!rq|ڲc2 ϑ5)ͻEqX8l8l7Jۣk>>jCڗKtT]'PF9 \?xFq=^\`m._ΐcsfsrk}ir/Mձ=j4^k}ir/MOQ?wDbsg/j΋f||ћ~G?~9K_ÆZ`-59-Έ|;/k8l!l;lqab輎:ZdR'Ά-F;DgWtKxYۤr'\|zx+D-YOUd:3rQw)}Y增,[g:ׇl}(r5࣡oзKjۅ~`s X |GQM}\ ˣiA|#|D_rfA3qxyf^Ag#w&ȝ):Nj"9EtK3FgM\vBb>Di..u"$sosQwa rǁlEζ]l_g N}{]ԮIrq.jq}mvjy|ϙo_ޅo_p~M| C|s䗳o{;N_jgg :tu~ys8uցGP&uvY(:3Db ~&g-=!~r 7>/Ҟtn!"-EoەwnW[ "o%`JjYY>~r?y􋏟|O0KKZ2~`g򌠳eeϠAg+D'>r-?ky]t{D ]KƏIXn)" *> 0c gnoy:j]@7@7ގxȝ+w&XV/}Yn[ώŻ[ |qZ>⧥_|SE?@g*#b;V`gתq٪C٪w `>rXGHy,YZ6iub3uwc+E8Gw%1jK{/3xU`9tgQ˳(|Pr{r{~~s{X |qZ"VOiU^B6_J|^F/_k#8;;w`gN :]jALt.997Lt*:DdY-:, _&n rj[]\#%j;#v1=,$MOۇ==H,lql1,<>= _lǽBͷ/_o_?5ή5ήu :[w :[ :[|>r|Z_+:ljY!:ԉڬHIEͧ{"e"'fx|H~Qk#J_G~e3@/&:M^rG`߀-|h0aq/^ ///__ ~~;8K;8K=)L=+LM :S|>r|>rWΛEDY&:sYHIO.{ӧ<%m5iwv=p}` bb=/x MHw`ჱx!0j K _!T~ l~gw~;T;6͂666mx>rmx>rmExY$:3YNo6N!7 <@ V3Y/v+p}k]3D o 1Ǯ ۹}=~?|h3;aqmG9a KSW􋯥/7]ǠmmǠmAg[>3\+Eh9At{E,Dm6]sB|9}w28)r~WZڳf; \+mc$}55t.אy}yn;~wqw:1syM%M}\wQ}=lr#ת?.7[I_vٵ;찳kwZٮMٮ{墓Ga\6љ/:DBDmnQۤO^wͧ}ENyg͐ O6; |}v,ll@^_0c l0s`^?p?I!?|up!'mmVkO 5OcoSC-Ciܙ}Q۴"}KAҗ׍aCמ׍\gY֐yB:2pȹN.ofiϳL@nio~l~Wͻ,-c~a횗6?^3L]yU`|GG&>`hDk^h6kwm`g=yXt~tvhtvhtvhOs3c١_29LtsHI'aOo"?$-GK{ֺyyFo?ֽy-C x@ 1Џw#uKM`yrx>rDg,:E'yt:]^{DnudY{V "}yW-?~0k׼*-Bn9S`L0Nf5"\I| O__|i.E~]Zk%t:iWE'ن\ن\Z,Us\):,#No'ͧK3Enu<J{K{oy,op=y!xt)X}'ϓ{y+or/˽`Js-ׂmO~oI]ڟ.s\ןo#Χo#>EFv5;@5<"0b3y ?-:_W1&*u9 u]+_/}W^G.6mۥG O#?N9뢼-"(3Ҟ1lQ8E~,5RS/5^m]< r7۾490唄u9>z$.͑%W,_]|mh.wE2= ̠_gΕs|Vt*:L=)=߷':?GEAgxٕy|/g6zB> 5pzK'K{!J{;g \ZK@j j_z=0^(;.ھk^o6߃a6 :O[/F~Z=#t___ vv]7/|[t~ :$GW38L :݂Ĺԉ~&N!7o]7x];J{;g ''A+ X~3`Cſ5k4{1<;Pjȵu2u^#C^x@]Ľ޿uՄ'.1~;D § !^9;$Cbgw%vω7DD󟢓!\ng: :]tvb?m;c1vr;##_w6\|Iz~EѧFbs ')Nƾ]>߆O }žo[F}\5I[BF.r[@iAbq[?k@``>`66/8&3E 0㿰sZdg;G6s]~쨋zM_C_ t$:3E/Eg,} DrѹItnHIϗ?m/5s p?s g7Rpe9x#~/gI_!f.//8 lq5brX,~| s= y9a6q= _L/8`^gΗF,E#_BQ)m]/>Sۺ^WΛE$љUs.uӷ/:DkuzHIw3+oȿIyG|g͟3x+m,_˽^[ lm``$(뽄n7F|Sd޽`ё {_9ao>|Nswҷ}Q.e_ew],}ױ/uQ_?XBnknpRo惫D^-Y Oo_6Ϳ`o g2$^6W}2ۧ p2ܗau42ܗ! 9eȹ/C}rːs_Fa{?5,x3o3b+r ˽sMp6iW/x⃬[ l5Ⱦ ^sgAWq^!a1zq%k=pc0<1 ] ya}b O;7rWXu>8+obGp&3;Lԧ}5^˜Ԅ1Y+c~TƼS-22ca000njލcwcNƜ~Us a鷅11W1W1ׄ11o11˘gLfVzoc5ޠ"+rKҦ^6{ sQ@0k6xݦ5`w Fy&9d墏lkhpC53X`y/i4dv,% ^`>jc1!RuCx^lx_ Ƃc |_]c.67|l>Js.m/[C2%kN`αg+幣+幣+幣+鋂.*2PWڵJyFJy?zc1ԕKGW2?Lt%R* 6i`~[}6} Z?`߁I,ڼJ\UU Ns'wKP{5}Q}퉰iAs|j>^R0̽Z0k-z)r `XjΫȏC ۋv("IyF?`s1rۘ{دWq6oI!mTp('#Ǻ={I w]_ |-t"g8\6A6\50d}Ѧq}w!6| }ʘDm3֨ b}Tl}׮._W¯G{)P ~Q )roCljn}Erv[ h+ggKK/#>lG}H[oMpy슟 6@n5fpYlZ08C6 NFȹu[> \ޓ}We^l|tFFgmjU,t>k#ڃ?E<7>vma+7B6k8Z밧ÞnҷRVK_>|}|rGEn}ȿ m\\䌓l0$> /Eng1e28'^c}]kYe<z \G~lu#ZYrWY4L;4 l1|{.N ˎ(&~>z, |:B>:[;)NjN7{_ܤvҷX{L{ⅽ! ss #'Hli/m [Յ8Y3^ _$?ꯇ c!xIA5O`!)8CocT`pq;`k&!'`aoBO  [ ^ O >k]_:噺Lp+0T!#ë} v:gxȹqnμP,>O8I1.sGۀ q!ׅFur]hua{0SuBBC,qv+:g,nǁȷisE3T :a-3i~3[dg~(L/ 6`;S\i"0LԄ1qʤ} xFZGڵMɵcx<>R9!h$m^?/ Yl2r["gcxd}9~39-˜cޮbs ^/}7%߯ C2GvX{ANZM3Gb_X(jp0}]lk QGeJ8wu8)m }o6fQsȹ.3P.̵\t khl4Ns=!"9NohWOQ!ȹ!_-7}q[N26)DF>5& Kϒ=Kn]r{m x-~ m q6}SE%7n1x·%K>,x PLOXrɈ_9;8[q}Uϣ |rg~ 5PCx蛛q.p vϡ|;_=mbA~)`^M&\68^6@lsGM x L`ދAry/˽m ٦m'sK0m`a{6د]}Q.~6|N˝6Kfy{˭eahm6 |0lf'5sSl4Dr_bf>bKDA"?WO/!"V`}M,)""׆;auXvZ5;z=^~'5baiail`_)f'g;y] y?{EXwN| }χ|&?8gi7~ z='?{isb m}'~'絉XX>c]痁? Okx6/#0HzX5|c#48"'2!_8N*rEg|#mFpb,?? 4v4>$ŧ9b'17izד7s-736qFuQs$|vޞ0ۺw/&?w de\>3_3Bt|r|r{#fob_A[,}L, f\s/l Soީp2sųy6sH="o)SMB8e۽_|ۺ'-BB {v+$}ϕK_~>rKpsKq=?Ũus2Egȳ=k7UҞg=`݊Q fX/c1j s/b,LX7c9V'#rNFʳr6ɕI.cg\~Mr%2QJ *WP?Kn.$1cyReHy3)lg_e|.C|kqb y뱆Vk[rlGu/ FYN1Ѧ0alE0~alE؊Vt{[QA[]alEdl'֔+<\bC2dl/~+c{Ok؊O c+>+džFqZ46Q˨򸎊 |j1E۞%?!m8]ڳv-/j |]@ۺC[lɷ<=خ>$z}uK`|%c jT_YYZ` ꨂ0yƻ@,w0 7Jzr30*8(â<tr/i\JP c+k셣,óOIK0Ik0_X*ރ뒰rŃ_IuѺ(kXZWZ&Z ӢFLQ ÜxY!z=O#=aW^y[| z=@k9(ij+aB\Sb% ?m=냼 ]UsgMS>3 6[ĕ+=[6+漯K?cLAsnIO![n"?&mmvŋNRB"朒>`EOEvfA )ٿg`PT-zY͢fI?g"[炏yÿFAgq󠳘0k alR狞ɢuW uK="+r >9풫>nO]1p/:RhlwTɮ(9ƒ}SS=L}K){iHXr"+MClӷ>f r^D D9yȕ'#S}dN,^rzغn)Ti5R2 .s/(Yd* %v qXb%JmX,}e.=űx)NRq8\0 :Ӣ(] O͟` =xV!ו9 lJuοβӃβAgC2~~qe]βAg 9BtZ6)mRk5Ǎ!"Kւ3E>J[=-Jց-ցҗydXji]{<_j!0z%T }U뙒G66'rfWdu3eu5E=x}sQ}sz3sl>ǃAg̠31LN>ԉ>t&/D9At|꒼/m,=!fPя'DN?-7X>#iϥ#&]d?9N)j@gYd$m IN$i+nH6)=,.v_sIʽr 8c(cD_DQ!r{s)R.s)\m.MK)a.:F5Xa0_ {.r ϐ8<3a 9a 2d |k֕9RYW@ư^^û21UmCUY*N8WV0ϔv׈r ΛE^'Y.-OpVS5X Otr?* >(fvq^FjWڬY)2CCDga"~l5[I[5[i%f+z lg0Jy*29{%gN<9CCD>Tiop:e/\&\&\&\&\pl=,ρLeN e$ E|r\+CgJ >[۾yų7䟊`_cU\5&ְ*nmaUdA.ְ* źuW1ÆuWźX ~nk\ţ\w~ n1$cxCp@2*a . ǰܕc'*/cPP00 T|G~p|Nr gg׉r6omJqF^6s{a>~y*][wW a`j׃Q+VI\\NmH{{W>WnTb?8G ;]//Vn*/Vnj/}/žn*5_-)s >N|YÔN)}lƙn47 llC y~,~O\{Oص) `+7χ<&f8Ni.rqޜ*rڼ)i"Otx(}38N"}m_~l)v "NU![+_OqnƼ lc{ԏf7Gߟ F~|u1C]~3#_`gs,٢suS'rs):}}L3~_>謎.>pܧItg^WjsE^#-$m]ZԃC+۽n}v^y,'fޗ!}y?5=`˫mc0!Ů(&GR}l|j__|_|H0~`gW]u*:w_ηEԉ3Qԉ#wC9-%蜖tN_7ߋ6XJt?xҷ{E<Aio}1P6eQ.X31p3J[ G%/y~{[ l|0iWg(#Le֥}~" 즭_DcyѹWts/MǢX9szszs:N^'ǐO>-=W5 C*^{) *K4*nC|]eK0c+-ꝰ&8t_pzs66 swgV߁gKw}&[׳Q_M)}#}ߓo s9ĺ1m] +r[߀zd-? k[Zly0϶e?O>M\܌FɜV3>|qF?#[00͸LfJ_Je_y^;[r ~.3jzv(;regWIܣ˚4eE^On#rIY }AaD(;{eg+`LYX|j,a*FY`Ojyq5D\Me(k ";0sBYk0`oG9?ȸ-f~SY:9\<١M,^mO3zY× 8sʌ 7cWF2Xmx;>:m3P'A@>`(uB=aIL2ζ3ݚ9m?<*għy#7cY6sj22-2gdl~'ci5f7MFel߆:5mYalf cuq۬f]60Yal*8mJ uŬalfؖ6؞$c{CG'2el cՑ+l>p=b-/],r?Eng xwz 0!A`9m]{/9Wiidi[O( r xwUK:l6 oŧ9hgFy*luoxY-z6{cƂοݮ[~8/ώ',swfc?-$O#gc?-4~]\J0#:{>(gyQ<~ <$| qf=,ġ]/c#÷a sN csVÜNa s1̹cZ3c:sQÜ_10092*\Caa;ǰ $ǀiS2=2e 1|00-vcۋcYfnh >NCW"gGY.xeCE>LdY6xϒ6} yu|p=ll,|nz^;\Nl>"`vd Si+w }g_'e}U%}ysy6~g< )rƲ{D|U6<@Enp%}H{}`5r,?فgZl{`c͏3fxl0a6qNΓ#;R?=Zw`[7jnhљ#:+Dg1Vtn/7DE'NSs~sAA|>S43)vk Bnkwb'Ex(=VJMf&mKW gg?ų5`l1E~g}`yϖ۳<KE^8Oo'ߣgqbgq͗Q̷"~{ΗoP|ۏ6m|l$j%"e^|\\Nϑ|ڧkp-N`a 1,ư@^0J3{_F} n0or? 7ہ'ee;~ uҰ/4 n|Jn 7_g)#ϻ<_w{6En6En>10}^vծ?@N -rF+7=@Y8y2g$OWM5.5TOX',O9sB p0 '5ܳ|>u|Rc)`d31MOy xJ{@-x6|By>y;!1_#w3%;~6Nuσx_lX6[MVE[U{K߁q5aW3ZH @ ] ϥ8 =!g~N 9l78_Ҟ5O2\%E/hEmwcܛc^6W3Qp/u؇=ռN>l }B߅)n¾MC߅iҷ}-8ޛKVrY$/ygKf3(i UG|hr99uKr(pAk`f>#-,_J[\F[pnxw۪6pn]RnI_kaᯥg;Os9v2!)osʗJ^Nysi=79 &h<$3h]sx3k0y {k60J\"dF>Z<2"g]j V$ԻE|~r)}K"{/¢{Znfߖ-싹,JX3'*<3|DG] 6 m~N怭 >Zj.l6̼yu)]`;!.1:f|6>9sՁ8g-z4aqw_h#/>ǺX|}}{|F$}dz/buQ_?XdpIm}M"gMykɻCE0)- 6 jٹ \O->g _n|96y`졋LiE2("&~y|"_C]G[[&Y3 >z%.Y5Yr蹄z,H=G\*z=DO-m_nK_'qfYn-?/WZ[\+^3`K=\3+bZ`y&6 }k-W-}Mni_O~S6n_;b+'[>|q3ςQ/?asqK|)ômڐϻbn)wҏߥ87f_:H_ޫ 2ޫsYv sW_9\.+`eɟn|f_9[ ڻ,wWȻ+m|F~l c@}JMO㼳 }Qoęw-V\G-6_^x߄| zބ5 /=0? ? _מke/YhÏ{?& D`s蹕zZ~sƏߜ9ɮNUvFxRw=}ujN*{zUUlG5[c}ޞj??5^kv#6m;j_lڗ>}Q7V`W>]}W8Eh;ˊt@n S!v|\ڬxl߈V=rbՓ_yKV?cY&asq+>D>Zq%PdaOi i+~sw+ݭ(w]þk0x}R$}˾8x#07Oѿ!Yo~ !]oJ{߁H_@߭g5<*|k$0w͖iy#0oʭ$z}1Y~:1Y27s/ǞŠ%nݿ?#?<Yy?WvxG-G^}r+_nEs :E'+ڭd}_ѹFtnψNĭoHy|j9slyPN.o %1Ҟ~/oΗZ f-]*:wN>8ĭ{ qx䖗.}f뎉/RB: ISC:$!,uv1Pgq~)rpgS: [[`;zg[N|5`p0έ^O*Eqaȿ}w "q8 jE]8j!V_":αs,Cڭfnu\$:׉GEN8DՌCo'H-/ )r[7Vۤ=X(0/> 8lx%8-000TZl \}؞Fn=7HN`9ٷ<lwR,1\Fͼadg|:2_w 4"9<:~rkN˭Bt :Dg[tN%Y ):WGD3{ЈMּqkə*6 o9@" [ä=sZ#`[c/FyNu<1_8]\/}&Iœ`溊brS"$yMπ;\σ/Q˭kֶȈ5|1#kU*|R#^ zM୑:?:?NAY#:WN3Z3[EnXt:F߆!M 1QLnb.<W 3E~@3*悏H{淊Y`sǥ/Cr!\}bl%}^Cr/!`潊%`{1#!3WW,3+Vm-3+փQ׭k0;uQL<#Ǚ׍ϊ|.<'r|>|˭{Pt.DkK8w<,:t֝t5N*uM#&uBL5baQl[N'E>Y3* s=[E~EVr߯([xxXγyaRv2$>>}DiI9rxخ!&g!\G,W\}}`sŃ`xu ͎bn8'uSحu"_סf(ׂ k~; ruv궉ΗDOSwLA :ןt?3\tO:N-/tz8K|rԵO͖[l[=[$Wo\r5j-QnfQ`;"On&rrۭYdí=cyukdOr#j[팆<ȓ[ߔQ0l[c]>.ߚx΃ >=KDO1\ r0R1ثک?AT&Oa'8 `r(㬼qVsTbOy6+s̕DxSJ\X۹WӞ8wlψ9`KOMRq>S\#}ιvٻ޽90X"خ?=e '_۽c`[0V~ lח DnםGE1ksDn|Jꓧ҂o& +$>OsmVb/~ӿ#4Ez/iٿA7yb[-ϔ6Wۧ-p} ߧkE]i9<-g/8>m_;C>;8rwX!vg}vg}vص:;8~^ގC;QX3'0gd.\l\-`[#W1g,w/a|Q6Nɳv1Vl9 *퇉L9J|=[GW'DnL;}9s%s" +p^{l2l=m"."1偯bm.&9T=ď"/y#ݨImxY;moہdgX_3&cǘq>u4Χncwcwc'o/ 6A}a "9ΛnㅑN7hsm{hsmG^lqkwproU,͙Q68Gh6A>mwM{ jfqZ58m 7AD-6.F f-c,pdͣAmT$61n#k 5<ڌe ;MOx{mrl&9 ޏ6Io rmf#Qn_6ƿ|>6~^EՑ/6A6A66YAޒm[ߣz??>߅VD_#ZR<)R<)zjQ^oϰכI;C~yxzbx<#Lփ.V:wd pq|_ ۋ.Ʋrǎm,'UC{R\ld[5t~kdI?xMgΧY߆;RI!9 < 0WKyKŏu{ucƐ7ԍ!Ot.ulLc`1Jъ\xߘo[b(=c} 1v<^aXUX,v q;eC/8Ĺ̹,sB](-$kv wv OP5ɘя,iƳÒn K"tw[+q`;p# ,}*p$,}4D/;`KdozX0X嫥>'4.cnZ|4mMmv[:n85j Yj c z̽1e.9 [&k}2ɫ2Ny:+X&hg upңΑU;=13ܘW4'#]l-9#gywg9z%~Zd勱c3}&y9pӠ/~gbkm>nbgN&F^Bm5yO>5Sy>9 |֗O?Oį#yx;]8|j&bgiї5Dw~#$T1W(z◺/lxV\+ m77PXrjP׭y\R_ǀ2>V&> N*nd'Sw(([|?eP?E> OeHGP̟3QtX+!\qE/VM~jUاmlh+ޗdޗJ %;Y@x9E~1ߟv:w:6s:v:F:S9m=ԉ|5_|^t2"T[ă:ZB霬tQ:CJg!uin)'JVc_:m$n.TNbr.KL~,q8 8Ӎs]׺BE/RbE}p\&߉]G?Į9}}@ָ*qL=C'ӧ5Bt`v#ji= LYfZ{%]>dQ3mxw7)w3Iai/Ǿ6Ia-iM kLxo7)L;RVuw p7E8\yW 8ZW<#Hx3fǡ_X؎C1[ + .Rq[I}r琱G%砯/:|:G-*T:)Oo`ŢuxC\;`- \Gq=9w{f5= 9m/,k \b%+-P< 6_ 76p:7J{#+=aύr (6],5j`ٿW8:9*w#]icÞnRnRnRnxCC^&`ُ6Š%fAZq/}k05e#/d܋e܋+N=80}d㼘= p3!W˝CXa % [+ wsYf3Q iIifڷȽv@6\`](`c i[A'6Wu"im-S'9'!glg =Lv4$M!Gj6rn=<A1w y 9 y>N _AjC<ĭǃ4TzGa\*Yae,so\qy`:W{{n-ƣeߴ2Ra= }LQ8Y' @#/|5uH6&`g}s:s:7u:r:wNԙ tޯt>tF+Õ9qJss9[CltC tq]|=s?ݔЃlSa^dYĽ , f[]ckZ@UzОm~,c <Zy19gy}q53|1/föf:lkfrzftVzJ@A1z:?TzJw |gfl(=_*=S9J_VWb6c)cL2t۸Gǡ6Nѹ}sܓG|nRvz9/mZ q]b |sY@lhfE*`[ ? ~1|Ǚas3/lnfT+Ji3i31%;Dɾd(<93ѓsؐ^{A):kL ETUgGmGQzӿqG(: cbc܋@l`^,q>X݅ءr쐘Dl(sySjlFg0 643'_y1s o2#хLх̽J's9_LN}'doU&|grM*;.mfgwStềe^'(z&Oٙ##vJB\s-N5;zɒpEo]sI;7.DoRMѻD/w,Is, K$W-}yr|B56K}KuTܘwvpK}RRc]OAEW1YYYyʍs|\Դ#ܳs=_e^{8w6R<9'_{{{Tnߣr{_m>hr^F.qas[sRjȱ; Aw|[O3iJv]d7PFOfl\]y s}jq5f`Q+gxF*ب[U.UTRKU.GVTRKU.e|j K?j GgUz{Ş\WX/{Uޫr^r^3Wj \=#{Uޫr^\kTgREWzTާr>\O}*WX}A\1@%W\x|\O}]\O~\_*WWzUޯr~YGr~\_*WWzeգ.fU8=L2iw`T.l^-SL2T.SL2T> k'͇Ɂfe\=1r7jQ7j.G{ȟf! YJ%;ճ^dfrAt՘ׁHE\G)>cTL|KX: #\,(·Q};;kX:|}0`|}PbsX@lhfw9sž;|/qe׫#G;`X%KQQ;rÜNv6;3v.[s9a\4E̙P) ASr Zj9jJD<p ꂻLVϧJv_cM͞R˾R9CR{HefĶK !uOPC>b\1_z|y;+t|k?rg.;V>g~w,r\>貏, K;~wiF}z1{S_3sns%?| \NێvX挺Y?;b8 L6b3s B@>.] ;"L!7a9*ƨeRÿG$7Oϐ>47),Y{&sqsf3aF1s+ =-{ts<=6v'ہ%ٱ깎f깎 EGUmyTՖGUmY!'+gWd_{ I@1 f)Eyy,X[".m.鱱`9`^f!s1 ʉ\_'[Z.rEc8O~_w?v}sc|[_ .=Ӣ d;}?6`wnx)&u?x ޟ6\^N`Z`l_.`LNNN;}QʺNOek2doQ1J6Mf=c%Ϛ⑟+1R9)~,Gwqy$oI ^`G@GZ8q~Y8/ď3w?p9$Ÿ/s;Xku/:EcYS&-k+T6ğ`_P~ ;T9v]]|+0ܵjcW3$~.}܎7ܼ:y s"snsល{nyKlsB[;ZL߉O>%X+ts]os=S \r'9ߝ9ߝRwNI,MAuR̍Ӂd.&o?leW |ѥ7] 5솹Ei+Slw%ۇR6d_VoR6-Oe۞|N7'(Y.llEQzĿs%[ſ7NU9? `Yk e?.^W/y M̢a׋Ϣ`ٴj 6eCȥ*=_fI"gsqmsUNmYw(+*+aYA#Jtso!b~yJ ɍA\\R W*)8_ Mj {G~r1K%oofXz߬/ 28쳚9 ƳaS0xgP+V L[aVw*>OYޡ'KJv R5y(ٓs 0Wr%|8 8_e].Rb/E[\~J/= R_K?{&~xU.zow9~Xw{!⏁ņG%K=TVAYU*{Gwģߥ_&bċP.Rnzr}: nB2NP~s:u:\t.\rӹ]D̘%"b,t>t>tU:G*gěYx6Yx~G_%k p;XEUY,|bRw}a%w,9`%FݾڛYJheapV s7KvVw+J%]zeW. 8`]z]zcaCߏsYڍ9k$q~y8a>Rу}DŽS'KLQ<ي:=iLu 3_%t􅝡3G%P<Յե>e.>lc=~ng!3!7?XW'4Z}nɜO. ? WtYeWs o,1;|^nN 8_M4#K@q?酗9!fi&sHo %dgUjs&ұ.-N`K7g0y-:\a</sxFШXwfi{ֲ=,/fNϲF~7Yfaey{\heM} ;ss[P# Wg; E(<:Ꜭ;9us]<CuN#`A{>yn3_Wz>|}~+`nY,{qbP$Waw4`;.}z Ͳz6?ge?RYJv;bYw`g,d7*R%w {ΛqE=u `M?*%7V3R( /K^`ɱ #Icb=op%?6rDƿXƹXY4O7o&'|{ֿ&4.}/#{}#Q[s'fH,1`ǁG('뷮|뷮6[k-q 0CS۔)'{^,YԳgW:{֊+ܳV\gY7vK%GxHRts"pXQY+=q0~~x` ~z %ҁV\̊H/fV<ga<ۮ>l-ݬx}G~dlwd)eJv=e{75%謻=,?E\1`ws`THr>c'~,u5p2W؇=Kl7\y{Vzߔs7+oFW(GS 4eddG)Pqr'kρу^ }&j@y~g9vGO}89*Y,tΑQ'BJ@JJgutZ39ӧStY)zwE<xGxh%Z}p"//>\L ؇ @Z؇w vwﮩ)8D[6.(Wg˝쪫)k(k8U7+H%EYk=\Vb0tWW;\k+鹒Wbp@id%VwPR{G9^j+UyM ܅~LbW`^t7e) k/'nȼ7Kkv؀ӬU'_ZAj%U ljUZku] ϏYtntnttt>OG~J J翕xs9:VB ?U:(sΥJ:su_[iyFne/þ` r{q>^^şx$WHd- b*FKY,q^yŬ vϚx6\)l0_ӳnM[R)0ʢ>Y3=ּd%;?d\|qArh߀+'c=^OU_+~*H{}b3>C* mҐ9 G[4"FPG4P屆*5wlW90jyHbHޑD|6j(Q;7F 796fdG6o, >=g#IMዬ">.t9LK#>ρ}}mcYۄ~\\\uZz4uZJJgPPRLNtZ)tNRO)~@ >55u5ܧ.wMk$[3%fOj $n>zԀŬ] \z-az7rF 9˅OVYZNzX|o`SIoG16s9F~B-d$nKv>2Hq]Xb3pߘ}Gn|6v ,`^_/8ͱsl,9yqZ.`W`䤻黤`kSQ<'H< xoqnMdM;ÛH7Y\@߬kcfv?x:֗o`Is#O[5`uJvݯdSv> ֲwGȮλ#dׂY>+u__9yP3KYϞq}k=gJn.\`%VO3P V<2,L{ת\ ػVrD`Ye=7gI͛J8i*gtQn-4k)b{hXb.sTV15UmT;Xo%c7kLj~̱sl&X-3wGL|1`π黤G|,.Ut T<M>nޛwv7x#L_z_71nŚ]?k͞Yaͮ t{f5ߔv71G*d%ۚjfD:3x x'v{ƳY@f\qwlql Ea ,`%!xͫ:똯큹^`'hb~ľ| P#g|Aˁ? =n3}q[E{MQ_{MߔJgҙt|dxo>2E+Jbsҹ:mN_EەΣJgӹӹ*suԙ izE7Dxقk9M]Esѓh`(e WmW23|l޵HsB`Ye]4F/-_o9ng>^>z?z%]om^@i6^ߛҜorc Ox{c Wt_9`4wG m % ks H|b./9O~ H|w|(t `9+]xxZJ[㷔K/ݘ[= ^KI{`-[zN3>r@Ewp-eSZJJѹ~qZ;Vfj[ Gۊ ,1_gn+:S?*̱ͥ Xfɍ=n1!Q.uT`-30 > W |ొGz+~B`Ar]='%n3nßPt%W2b [,֭4 6l]>IֽqXLʁ;]`ʏ5ׯ>mM$m=N+:t I|[ops[~5H,sr.t9O`9:F,j6]buW FoQ3)Uߕd}Z\/G y%c߼sIF~Ӓ{oaINcl0$<X'jkme~$Vo+vC Uw۪mr ɘ{p7v 1Γg1E1.=d)BipOLFn?EUC^y+|'0c,^`֨~kxY%)#aٴ {<'(xZPo>i<[`_]rj@ĨuKp#yuo{_y=KǞu=qɨ;SÕlܓ'sɨ];aQ'w>v n:o.::vc#=0< 8ʍ@܎Cs;t(,Ց=9=y8E瞘c5vG`dsErgη\W1Nǡ}-9plJVw_Z,s::e:uv$ICSCCCg19XCg{b(ԃqpEg=8M7/H.ovV>tvV>t~L _ld#N6sOM"N rQ6jn`H)ƐƐ uuKm.sDviՅ7`?Q.=.ԫźOfNH ܅v;uoL7.6fl'otPUNԜsɧeUv_]%aݺJݺJ1t }bW92])>]Js`^J8ʍn8я6L{Y=JOSt==H7>7e0}^[nܔ7|;d#;;;=w9;ܔt`]w>1/FRmĨՋw{'vxmoz;EUY'*J6dxLq!x)?#jSQiF2v[xn5Aoۺ$y2&_Ӎ<yJ}f<{xS9Ozyp3VS?Q蕊<=N㿳㹓g)K {'8~;iXw2ץ|,?y #`Yw¼d.fsĉoV|psnCY۾O[Tӕb-l Z%C}(lP5s)?}AgKA{g3NHы?w)r#E-}R5]Gw_)b͜ ]7R&Ƽd.fer50߿w[PLlt`f ͖(%}Nl;MRc, aw:R<2 xs?J?ܔ_|:XOgI{Ww)?K7Xr>QؗGc_.`ؗK}WؗScƐs#t9fCj*G=XzX}-yTjio |M}ԖAzk-`{_ z땞G |ӹ&skskO!su~:T:_Q:V:ӕ*_Qg.מNk;| gSVVt:}P>\Z^5IJcRc#zȻ툇ϫKWX=Л@m53 s1[>K<_o]6,}цǀn=[af*VnkdP);S>d\=qY= gsE Z)~9A3JvMAֳ◳Ꝭ#zzJ~CSiOM'ܓ5k[>$` ޹;n2䥻 n3nwfw\c]om^\m >JN ks\зK\_Gg֏fzsy\v:u:7Pg;`tnotntnW|T7lf&۟aS{-3p>ux(~=RH=5b JB Dɻ(mQзFE{~$Jr׳ٞ Tx>m-s6 \I-lyJv-QE-0eK(j' '†f1s;[{SOPLVS=[ש?kԛYs.T2[NI9Ä m\שt{{#0ԎCR#eA]I@cvI x~ pK;R[Con㭗)njo`^;v6;**3fgo?;a_v~I~y~A_s9UQ\tnP:wQ'ԉ~gYt4q:KԉUimRz)3.~\Վ^R^:p@< ɽ*ܫɽO| ZJ_Z܇A[Q8VLn {1Лz`GK <^=㷽Uo{z8p{s@|jJFb=K^,gjbm'Ku%j@ĸ)ƕ}5ﳔb}JYճgPY=O]aY UܘBM{֮[ܳv>]gzV=g!ͮgYΥ 8\x.1?񓊚HEowW?SL򣶿Og0*up)1j)ӀéFL?Z幨+6 v3_975_F~>*~>BϘjw.~7;}NzNNVNnwfwg}G}޳`>o$f7;fSİϞcRN]i6p˚<^LPtL`Gfg+#3(l`{Jc}e؃R?,1Xy?Y.[,e)>C>GH kIOz1io&<1` }L}#}BStT:q:K}NgiYߤ;Sz-8)maSz,ǔUY̳#:`KeXzH0KI SzއTy `|cݕh~7 5XaUJ` nj/W{~/~MYbc`ҹBܤtU:)<_L)W#Sz[t_6o]"v AE1>V˹Lşx$G>Xaa}-1`}-#j2`٧K/suo@b|mgm)ڐ^~ s7{<%L'c'cnPl8?<ٚy1e] Oe-ъ纩#H#k`W徲OZXrÞf}q. s1}y>g}=a!f?}JvdgQvlOeOйg"rv* HEg>OtF_L_Vz(YK.f f f Wc106oUSUMV7'p)q}r'mv%*`CC`cc`[#N#N#ov^y>B? ?o!ixn 45}6Mmr5 jlVٱFLg1eʮqc+эw7V/787 58H96;qjl~Pc UcۡvH5snlnlcó8<В$aڀ.1pKvN7p)Ɂս~Qn=S,#n¼Zd.Q6:0^}z86p;R=[a@mu 8]~dlegy90[+ Jg8y\3=#i8_ѹHыǀᾜwugG=h0k'; `?J2sOQG<[D?-y:ؕB~}H>d_,ʢg?%MSc) q5s9}$v 6-8GYߦ*zHOӀ?XSz|YK̺1}hE?#]10j z`ϿKig>gR4ڙ焰9sB=K:ʴ](P/kGx/~,_Q*=<#M[ ,4XJ`Yk6=;Y^M:c9o&<7G_ 2b)I,T:+ΟNޙM9<<|yyyqbzXqI[]U.@mGP67QO`_H  1?P}/t(2yv.qR 5~ZEkgODx=r=r=r' #,lhܠd;+(%ۗ,rkGE.DK?txX>H,=>}R~kG_&0k<;#wg9|~Y;azf}>zb5푐ҹQܣtV(UNY\:K/s:6q:t:vr:T:NeGtZ|B7]қW?p Wuc,k3] 3"7s/KiE8A-[ ug`P3Zawѿ]0A~p>= y:AG Q&^|-~ 6ߏ7m\60-PoMEC"tVtt:+z*)01`**(o+iJXsuimR5uNs3'\oOv:ߥ(~/3|?Z(~0%J0`9KA<%)_+{)y~=)Sr/k0ׂgziu:}Zo`kQJvde,syXեO鐒^>uiӷ}n}ۣ5k6}$NL]Gy®hƧ]G3S]G/zz/V~C %}o~Ws6x+M?^^<#>ͱ{Ϩ7vc86؋n F1$1÷j 3sa-c칰̱\5uj ;~uc8~n Ǜ1opwqi}t<矲/X?ށppP%Ƃc}◽#8Sg)t`[`[`[` ']`G`^]2sD/8ɳq͏xv>3.nd,%G1(;xݠdw+#|ԓKkT@88JypEgLO+=?P+}'19y9l`ǏħD8#/VO\ 3'"Ny1sjO9'g,'l `XN3E<1Yg}5K=+O=kz5xbk84'gV={VeYݳ*#,.|ʮY}ܳ*PzA=YԳ15x,OKe ]b si>Zѥ*sيU,: ,ssɨ̹dw?W >?,qp♣x$Vw,_Pw,_Pw,_K̏K^}Xy 6O6@7De#F~xKϾxC], q3DzIF-ο`gG*JnvoǓ89Ӏ1S99ޣtq3"`~r=6z?M%h*:NNd ʎ<]T>r9!킾K!I~1oNk'<㭡k*{<s1g}\3 \)Q>z\^|\ [YOVm/eLлj}a&~- 9]ɞyleN<2:%I{#9y:7A =xv ̳,͜YfNds"%9Pvpݭd+leWO{5s9so@RPљ3FQ_2KY{qF<=8GɊߓ_R~I}}P;z[ C#(%=1P}Ju=4^陠LQz$ϼ̞1=R[26?;3X/~δx.n&y8=)g#d۶g2gM"t(cίN~/6g\ڜQ\tnU:˔Jw' N[3׿:'ˑ8Q[ZxM9%+"^ߪ/K< ^fݘ5C&r%{ɾ"qqJ>+}WeLuYSeF?s. v6g[8<Ͽg{wz=0g!|,_,奄l+iJGJiJi.P:(ە΃JJ'G]ڤwoA5+Ŋ6cp)~=c)_x$?Vzwk W_roX3Ї| $N7a^ǡU*ë,6~*9@ h* H!Hқt MARi'=HШA@QAQiJ4Q)Qy5b""<3ސ~\ݙ٧T \iϕ?{~bs}pVN<>ϿW+_ԴW%٤s)|tn"DFvYA:$ΫeΫ4I4kկ%ſ 8O$ypʀc_W%1LR$Sm3]!/w10]b>78|(=(=hָ!55C.qP~uR@_*n/^j6++߯~kpl Km$~K]p'8ʙ7a0Xc sy֝\XwƇ.a굁͍67PjS_åM> :f X޵'_9P>y p$oCeI܃>)X'S_uB < x~Bj'l\@}S#,/[sf\vVj_b Tc7/~ڔO}v1av1?|67wvt^t:+Tp:+-5E'bB-mNg6NgN/!:m{O:u,cb "D?$'$KSfYCm䬑X,y#vM,ُ콕'>!ܓNu-\ӓHj%:ɮ^0=^C>5$bIp.xR=wHmd fzO7[܄%G쿳陽9zv `9`i?ɏsȏsȏsԏ`c1G~S?|~8#Kl'u~\g\[^{_2Nl=NƖT-0S1Oi~ D4 8_$ڬcsWp}p>Sk^Kۼ rk[[܅\d*l5 ~G}S߿BImsE_gV_iXkua*V`]8$!m{(LEFCEFky]w!| Q?UH-^Q"𧊨~j#+;Q4=4=&^`c^a6ߐZ?8uqU'qxMx>Uinj#x.MP߷o!xETm껉nEw;;o\8ȥNNDl?=亾Ǔ|!=q.8RY txz H>u//$oBr$oKr-)`ԱL˰mJ7\>lgJ8w"JhB{&e氡 }ElszBszB v!}CwR߃ *3y_;kKr9%"y"}p5`WcC03P <1Xc`/twn;;W:`ՅTo{` ~TWy ڳa`m1bE?v6g_gIg&|tC:ۡ.Ls'O:Ӥ 6~Mjf͍87ZgkHg$/q&Q83|=O_ϣ^N7`ak:~S#[}F+pgXOj oVcg#A>1Τ o-/yT:]M}7w`7SC~st.d] Q[5q^<5WIAu͢^ލueP[C}Q!|/^5}>5< 筗M䚚|/lj󽰳y/A: s+:yk|ҙA:_#HFҹEt6ڤ55ul8;Lx\D^kԾY&O0eYfeq>]gvOh y涀,~[gZ!qnOxv%5Z[cu;>H}N`SK~61PII+ Zv.a] @5p.u?^N^pux 92x;'ٱu*/}9^sP䤛 C|;JJ* .T,J F01>{~9l~Q OeoԺ=ΦvKYYv=NgNľSݟt#y3t./y:Mj/~]'U\lRMp1eoM.!)j/N y?[εyVjZ`=ϪgY{Rm\K k jt(_RϿP`<W]:>p׷NM׷NC׷Ns[Ko+/:2v.uF_n\lm5$4!^lR\De&5KNNj .[ѷ>8 8J0䮤;u-7\Z }Lä[=IG q|KKz#gaԑ0l|O:sN)tjN{1r>2iZ8E:·E'=3imb&\: Nۃ/;NW"ߵ^ꮤ^ߤۂQ_YI`zy2aEp:u:ú΁s4{ {&aSo{\&pj/5XR?4j/k?Xy_pkI~b`>XXu Cb{}`p0egi 1Ӌe^uyo񋍙>◃~=,لa&t֭t5NgNgs0ntB:1s 1_SWǴ6wC\|dmCr1|/ǃ7R{Ɓ P_Qyyye/Kx7s}_8jXvXس` Dz_L}@:Ѥs*C:[/z6 .)܌mIISw)`h#o!5Zg5[o1-q}49`c/u./P^/'_bp⤠T/r.Mag^ ttq:ãH|-Ѷo%Hg |t>C:H h.IZǑ\aB'R{}wG+\I@e$Z۟$k<哛m]d`c':/>&8OgM9A~QBQG w|p#4h.߰oxlTlTl$⃿L#e5t:t6D:ΑOtZ4>q.N?&~Frzܒ5 `.u "=r/ 4$U#RuRRէe7ɏTc,XXF~L#?ȏi4c1F~LS?V+u.d5䌙\B<Ɩ.> .6O6]p>.r}>G-OL# ^`LN0Ρ;!߱Lo%wm料?Q?lE@`mwynzgfeao<;7ylgf <;n.4oo[#}ctE\5{kJƾg$3H2)YkIZ>EeOƹ&Kz&k?U̒E~&g߳8dGQ_iֽ/8d뻍Q备l[u]kr{9`당i|??~ ٳl^=*~g ͎OyLU3NgrNgNg[M!4צ7A:!yOIx9i\v͑3u`N4cQĒ|z2'ڋSy jԜ xHAA#r܍x@ K`g]Epwm jER"]ő'_V:M zLk5B!76v6͗§W8lko}gJ/Sn5C4kiyWEN]λr:j':Q^tNG~3tN&ONyqbgiMgiʨ=C.CJCe''sKHw_^㡧/dڶ7Xc?uYLϺ,g]SnIƋbnXΧ)ukB>Yt+Wja`OUs嬝 Y8Ef@lZ|u q7|g2gpOc s:mquK˴/L Ng0mNg6Ng()אkR!צe?C:%sIg"8\6iS&@1we/KAY^ Τ^I`_9WjUs-t1b@cg\Rf PK Dc%R}ROz}%R,r-ܐߞ\DVRZ:#񩱱rp]r_9˺.8@[R6Ԧ-6ZkXb0=f#beu)`%`zez/OUWt.e`Xֲ?,kXֲX֯>XlG|"-`Li. ypnj^V)lGg<:[*-X=Gsϣhy2*?eUpH\Bc>a{pp#X W565֜ %[JxQe H}w%Ǧ|Vu}UO&~jؿ*jd.UbDA0Vt]ֵCCZ7n^0#7ֽ Wz/ 'C`ZWC"o uȑ['Dp |"m^Gb |dZRefx ^6;k\~67Z}=Φ]-׷mԷ N^_;vrȥǓ\A^]ھW@o? [ɻGRaNbWx{y5}s״n;lbk&wYV,s,{% K|%5;\@eq^*5gpx;U켔ϥTszCHԟQ`.]z g7Gu-ƃ a  6==xgȾC#G'x%IPoDʵ5Dʵ5D>O:e)!:wNȯHOyPP]ttZtyú5s$kDXp OQ{_pf_s헕sm5 2F-q6_&wge8//CP+7"a+wܡ'Xv>{On'=`lD}S_`A1tXA}7P/ڬ^o\ݰqXkekHR{]8,+kN .x0އZNC-8,8J90|kzk!X`W2CQ@c:\J<GS`6݇}þX(x -;Ͽ5n5/ֹ [=Pί?z K1~),~0X"Φ?;Χ.e.՝.8]t:o۶}[ًt'IL)ז߶ryڤ OA. #Zg IHGk>? ^I}y0ƃC.Bxwޥwޥwxָ  O׾ާk_ V뾌xsIrң|ǃ)>ߧާ֨O'%&SfM375m5>zdMkLNwN֬Ws4yG# Jkx,qhM$o=|CrsSߵf;E -qm>#y%CoI|y~R=6$Cmt= L5ڃ'q~KK'[fИe0>,qHf #}#z#v~|H0n>Z*qcym%7ank'1uc^;׍ymZzkaZ.7浅nlkܘ'A7ݘ׵qc^Սy]7uUn61\,,y#/d(_ ,~H$׽ʋOL(_{jOv~RoNabBmcZh?W{^q}U8cvC]j&Ga7Q?nu>ڬ{7Ǚnٺ%mPCvk!mS=} q|_&U.Dk}Z}}5Ǟ穽8#l \AD 6} mo 6އ:I7ЙtI7h l6޷Q{LQb; 爍*|%*cI>q$Kx/$7΀;ԧ(I_Y[,.=g$r0 |Vb}?c[o@ kۧ[N;9wo.3tw8[9p%#HDڭ$9HLC(x!4;6K\!n,jS_Y_itc^]pp}0_}L>=(-,5LZp["=H~#痴_'>F`3iK}v'86 M|iռX_/U_!~%~G>=_ EߵH1y|`\Ot;6w:lG:$αs 8im럙Oku'=HyxS{əi>F%Zy`?msIOp[-ON@<|'KP7~q#&n5 &{MۛbI,ң6fHCMM2~[;mZ 5զBZ5& $mMU g[Sh [@_AgAgTi 4o*м,vPɨ doJ ԏy81c\l$V_C8|l>h %nHl Z>'zJ]uG_=q_=Zz5[|>Ck*8_/ʢ/ykwm{MpTka$׸}I(j/uxj?X4ҧtT9mX`1$?Hr$?䟕s*OPK]6L 8$dp'S>H= ֽ1 b3.L1p Y"'yl0PklV9?ɋ`qisd_=q.M<_\| +NOjNOpW3W[у~jGzg2g;k6"6zŋtgE?j^QA=+kcm+8]b'\cEp$5ƞ yj1McXbs)>Kk%5Ƃ`LA+#s1pC/Ӟ^`/V^Ǩ׷w׷H틩Y :}Ag/x%kC 30:JG}l;DlGMy_s7}Q;wW`G>PT2}SsR|ǐ$?iy$ϧzگ6Z/G u~=`]_弐1{'b+ÛVw]oc1nu}v}6r]1}"co+ v.}G_ҧA.nLp '\ҟ/&RM,~LOt85fiz`\ͲfӇ~bfClg3&79=5YԗΏYz~g(^w3ӳӳ%B">,9'=gz [,5"p"kM^|7-ki4Nͥ⯴`O|Z_93.3_F\b_}*&<.껛EW3Yo_PfS`v}5pӳUs90 [fJ5Vx D7߭A7n[\{6ƲMelk,G6Z/>8Ƽm6CE\L^Ƽ|||M}1o+vcޮq1o{v Ƽ=Ƽ=ߍyޣǘoyWˀݘqcۮPc/;'ƼƼcw1P`;61Ƽcn;d 7BvJI/}vG;5xґ+vW 籿..`F`z+z+z+`CL]|E].vs`-wSw.ս)X} ʍa=gk?9m֘l {_ӽȯ^w5>ۀ9999 }`v`zk5݋F=X'L|C|C 7ZGuKHGF'VΘ*]jk܃}H>T}8 IA<۵cv5}EJOldkA}ǂ?1_鵠zu2^3'?+1PO|#,6r]B'&mL?dJa ڠ3^u_߲ymP/~u6Lzh5X~rm# ӶmJN'IC6ڠAi#OM?~\muB|?9"o~r&EN6A|~#67ol=o-?ccd,SEː(>Nr] أ=E^rcݕ\ݒ2uw;­nzwc `ɟvSgMD:nP'y:ak['쑵i='; <L)}O}5k~ 3>C%;]˶Md`f`>g.˽w7m>*pW!eJ>_Hiyt2NƢ저Ğ>?NA]I@9t>81d648x$y}v8/6Z5XG]Ak8_~MHތZ?w%y&pG<8oG=? 2fxq5g⯷; Wwm of>sqz*yh2l'aD"ȓ2ȓֱ[sO?%ߒ΃q$KxP f%f>/ڍb98ƿ%_blHy\"+C̘!2ČRHkHGH??˵ Ğ"ׂ{fH,'ҿO%? nC>5\v*57K\el6u} >H}%3v5C|kσZk=1w{a_ug+zZj/'u yk܇HMO y,\ǐ_3Bo %Z ً[Ж^  fPy 1c>@G))g\{f<3CI !CD?_Cy݆aCsGr];|%59 BuoLe~2?} [ XcY,ge܃ZzsY5ھ_|a`~{p=8 U_4O5"yu!g'mL_.#1IbR{3廗13| o$[IwSN2NNpDS}N^bތYvD\8^*j/3x-kT-v+/K]15u8­?XSے<ҭúaMXSu"rkY7#Tg:򿪎Kȼ,{VfSǒ\,Ag<$_N$_}> kYGth<|55b&zח| poҋIĘUb2F:#:#9#p7pGpGF:#{"("H'nXSm < G}+kJ^s}`ͥQ_`s9J5p9JY笎sVG3:JYF5oT^n`b^zuOgf$ƋՑ_?~ VPϏ _b{p;ﯞ/3_ˌL:<&fDs տ#Ak\Q|5^a[(< LQ먿uc8ܞ=~,=ևjl z,sLk!DC[KzkUǁK&Z}MNg;|t%rqbIp/7NMHތkN r&|܃X~\kuxqoKW>8ɕQ?WXr~eӏKί|{%7革革ߥnɜ9V}<%+/&r_)Ulj~>88w@ĀcgK ?_=Ï&0}999vDt6tnO:{!s.:[tZ~LSd5e\rWfE^Lp  ,.3|jm 9AqrB>_89,b'9bD\gOv$gu^9"$&Q{Т&#z8ok?dښ}&5b[A׸=SJ45%TE/iI6$oK(gb]\wDB]M.ܲ 7#fFg!*ѯS$?@ %?Xb)}?K\e/ļ :3'-/fƜ^}l;f; 71w3V9{v]o1+J}SǤ ؙجzKu+x-7\6ǩM 9EmwY}!Yl3Xb[T֝`='y4cI.>y/9'fW}`5o| Χ6g}s/xKA`|!'}IsssRc8F{Ic[^(\|%_`=Sq>=Ϭb9))Ywv9Uة0TjI}Hޕ1f#\a:%s*?fa]ZIrCMBj_˾Uysyv=]΍cOu$쿧%{v:izuW,uBVe_șrngwgݘD<|ngng19|z~O!+,1ҍ6nlpc1J771-|p7ngi9+cBrVlVu/Y5o/[-&y ;?sq.x@seknvX"\&^C 0x_o }#PWÌy9g ʿ,oP".LYo?<_kGm\jHm&P5W,z,3?$=q,ѽ?]sY8o}9soσ5^MjT}s|Qwy^J\a&{X;4V6NNNmZҺ-Xj ?@rQxj#{epHpxw~W/j_UkVع}{Z$ryͽyyf&(z^C:čԵ|ak:`l;Gճeǁu+ڥ<!ŃxO],7x.ͥ˩vyz;=e|NKb=1f.ee_'UC2Z 8a.<㭯k{Y/~!Eupy/nX}x=L6-Iu_mn__^_Gu~Ƈ5>x]B3]Rێo-kPm r^$Hrɍٽ}jsڔPSFBv?&9fK\eqwψػidʾj}J `8{>ߪ"Qo6X_VEv]p9ޝFmdGP{ɇ`{{Y] U\9]NrOnd^̂z_.ƍ/YNjXWmG4f~Ⱦ,A>yW;6/u{5CyF0GksDaJk }JO)Boݭ/52}w b/]kČ5b66Oڬ6?z\:ǃrF$vI.8H,eǁS/r~\(4x |}/w+:^YA˳fo(WT\XѸ6%_kܾ Nmvz OEw_HTxxR0J+Qί9 wXB W!=kIO!ѵ&XVJf]k$[=,1`HPoTFe7*7B w⮓C4 UuXcl X$yն;kI[HHz6Db_I7>?h&&4ķ뼘^br+bl>:An= l'8goblGnD}HN#9twDLj~!y=#1557#&o"gP.AK~=/#ˆ[^#BwO#$?bޯU\W؈*y.qV|^Ѝc񿪪F<@rQp!pG<HU#bƸƃy$NjGl]WbnĀ /$&wĤ,1ȯ8?rOOto5bO5\injSDr?k9>Km4sSj.Q~b\lWsfő\ %kI5:S} |(Cz>T`_U'5_azZo$' ɋI^BS$?K${[!̩nhx0yO/'_^LN;)1SY\ y,>c/&cf'8WND&Hq[鏭&qƌ yV>snNjk_הs'X{N3)שrZEz1Pr=,,8\-v6{q8~pϿ{w;=Nn& n.2 Hg&|tK:7͢8x,I: GHiyr<6rCv\<Ǒ|. Πo{sFN?GkZ kKW>8ԐזW8JWʇ]!h7ڱn >9V0J\B惋}4P)wݼӑ˵) ';hċqƟ,&s5t~):[E\6?t^s:x}RLr{:9c}:pFr]9$P{:^!gXr]^\:tN:H< NwuֺXSbu;e:2q M wc0su^3z 5k FGf6$0N4i(1~Wç?LlJ}_va_'],+״jM wkMi]irLֶ䷷=>]7,8~ỺHޒkMER]ρ[ud]ݧkY5"X*'\y \̴g`^LK۾ ۾^ 6ȳnli6[D}o3!+=N/N"}ۀJ_ez5GEȵ>Kr݋|N^k_Oa^vX8@}5o#գ3xwti}r`:gգsV=:g:{4?׹ ׇ>fz+|>S>_|&+SfTB'7xE+=77xF=CuK`{kvgJ<K7uHg1,!=.x:fEs\_\ӹns}GY G/o75? "`n?K>R1wY'3^ b{5{Ltqx LgttHp]G^΀8 ֹ&\91yq~9%U ?/<Է+@:wHyt^8":q_tnpӹ Tj nKIg+\Q|25^`9#,c(zFF yOK<,Aۀk "XvQ%E!`K(x9l=10|Y_,_ [~\Fkl6|&~N:_H矤ӹWyWUlmrhF84iJ' (TEHN!*bAB"~dֺB=Zgf5kʞ̭tVs:s8HgGw:Mr;KȸK T.kf~`P} ?EudnJg&'~*e_ XXB%+&}r߉$m};\^l9%!6 P6軗+kd&ٝ$+G`/W>^Q..s`["/KX&TA߄zT.98Q}o$廙e-X&X}Z > V0.":@!z~< 7Ɏ 1$ rޛ{XҳC/}HoE l=Cиm־4ǐ@Ar־4ӹS;EйSXm2|Xց K;aWò~Hx<qxWHc[\%P4<jc{I,⹚ۃQǜb_$ 9jp@QZ6o6ќb]Nߒul}U,x; ޒ=2vRRۮ-͵mݮmK#\ۖqm[ԵmSmK-}mi[5i"@׶ﻶ-ږLmm%m3m/8j_6ɥE^<{ұrv<5|6׼,k`_:5Gukkz\(|~WsT=0v*T%:`Yo'Ă;,=oDϛ**'XTzSIZs*scJzSIӐs*]wm\ܵrY׆ʒ?z//IΊ+Yqe];־āINT'YE7 u I;M M iB{޲Z &",3;#ٱv,{u:رmwcg?Y6َe;v;˾wcg pW;vmcc[QrMԶ_mgmW\ϵ-n׶]j5qm{ҵ-׶mX mCn{ѵ--׶]>P۾-S6QPێQ.Hېm3M95˜0 <5N3!k7ֽ[``Woב~W ўJ*=oH0YBwVН*y/< ,v0Ln2ߍ*/[hAng-U _B_{}LN*ת~-}>\UiUnCU33 ixBܾ(Mh|y 6Η\屨寠|Co8_nr`'-Oq|għsg_Pr k ; Ԇߨ \VkÊ\V<(msC +6hڰkÊ\VwmX1OmLm50ъT:f'd\$|RdO~4p$՗s)`HV3S0hNFsz5-uNM$duL>(1.swB2X[>ފU|omV|la|S~<ǻ_`g/=N՜;?"IgO郟H9t~F:Dg8lu-g,+nCӄlp7*I H a&Xs,g. _}@u@u}1P]9`]u'[!y5aX+`7`̡? }7Y6~~ _NK/,bK~l|jcg/c?3әE:ے _kHP9tN#iKlcPd7"OPT>b xs/"Y]ou`bGtϾ, +tzN=~$N8k kׂV̟RxfnZd'{?. eeIpJeߎʐ*NFN֤<|Utb[9@tb[|tN"Is\(:1̱:MV~sSGtxxFT_)6{5uߺ,gM `ɁEMɁDM{E!Tw')cܣ%n=Z3(jњVkZ14&wu<kL dܙdLVk|mH܏Xov)hv_߃6NV='jxUu$6:ZN7O:NyPYF:'9t.$D?hE6Y%MOji_rݧc_P;kwkk.:#_iS8u= 6qj6qj6qjv!kC]k~:fRG aRG"nՊ[u>-ʜ~NO$š'lY_([ÏO-W-I39t cNĀX14t&IwGҹQto:M~,yUse;ԙC:^s\ۨ`ͽFb1οCs~I][2/$vZW֥%Py7uX;p]yp.놩mt'. +}O },>Fm8Yµ!wm 6DF6DF6DRn)J,c!$X9(ߏDT~ōGe&B,m ix?]EL^kظ]#&\m[سf_lX6gu`F_Vx~~k8O2o-Z%ymO[[跎o]֚;o֚oۮ,qˣ[/,%'Fl=z>[֣cac1zkK~Nlsg$'\&`5CjomT}kom3ZkX_~9Q2譕2}t%ItҙN:NsEg$x#Inyt.:/X&kqOBP:ʏQ}˭W$F~}Y&k< 6}F}G#6k < H|g}u]8⳾>C|F|ϧ6sCۀ2_'vw@hg]{ >h/R{?GQ6> nn3Aس?w@yK{<~V?m?z?c?P9t HB)ĀkIVyt%uN:MvS|vE\|<ʓcca/s.6йPC`/+laE|6ⳡ6!אrxC /}O| LϸFƺe޺iWw~_ >n{X3NJ[Ï޺ 3t!I*ҹEtomtt\:vE6YP5\|8܆;P}Q}?u`b .6i <8i!>gcmg )7Xs0qXיG~8g|ox|6>wftQQ.O)~O~odSV '~~6|)~C:ΟINyt 6tn,tn,tntntnou"~ Nc od| MTp/:_g7Q}{fuM Cz&3w-'NW3Lhgm9L/wr`AfwtI6ax|j'kO~}\aØjyc*֮Qzք111wS1ڸ6DѻTQ.U5XNu|G7*ڠW97$Go6׵ʷ`4qd;6N*:fF6.<u2j"p|>8Kb[]X6ʷ+-[[~k6~k6ɳĿI} Muomj~kS'[zo F5~kV.x-cMI(5O8e,$nCy㨾yS}],Ӛ9y]55 yiNkiAkiAkiAkik`O`րiӂ<-hBEz0M&&[g§?ON:;^/:*|tN 3t~-:~غ46ٺPS0I\ַI;Py ՗\t8:'I%t8K<$xH,Kl'#Wl i_IŬ"6o| Vkm%Ym+om{[a^':6 V"n"9k$۝dEol7"l$ϕd,'>!c6,K>O\#$ISI2|D|YI%%UKNKz,9-8z+}e>~ybI>GUjeNzt[k ӽt/5Klc.X(X6|kYo<ߚ 5 |k}<:_y5{zA栤z`FO'-<(p|Q/c$#&3ȟILm;g-w G Hj%6~B&PB߽ %ۑA I6d׉dz@H4)Xder :>rg{{Sy97<:2Ɠz|T)=wufRoӌ4WBا/K&u%Xk_bwb+̏CGgVa׬ Nzڪ@hW {4+lA mHl-"PКd{K$bW0Hdїn戧5>ǀ/Pγ뮼Rಮ~TGƂCGmлxmt <q$ۏd"bhE_~t ;II. .KApE*ɥT>Ց913;9uNr|Xr`ŧ i_G>ڻ \RlUHK~B߽[[ Nv-Nv_Y'V? ؋{d#IɶYYe_| %$ۨ\b89| v%|\%LQ4u(*Xrr5G`}Co pM?$!z;JA߽}dדn55;Nۜr"h]Ve7%$7Ort*S}|LQBG12%7Xn1,>M~|HoԳ>1kO}+bV軷mCHv ٰb>ڟ-$E$d2l{E}vB*nMqT_cxBud>J(&|CQGɝ:;uv|,9|_)%O[[icmu:X{~ hHmHKd1xId1KHv NYG>Y7@e\c7"GP}T>g✏L/u̚: g!w`hj[luJMy6{tow;ك""`%OHV z/;xR)OQj g.PE/sM .m\yN, `)_)26S0t󽔇w]d̦T˘MEl .r~yK0.2S%Rje`Z`9H RK, vq1E!ƺ b@k@ENkvt] jF`7UivH`OU`v;e2i ǃejg!S^R0u~`.Fu{`7w4NIv N'Y)2禴Knz XryNMKQ1l}מ==R2g<%!$Oo߻9^ʓח}3ї/Q_(҃bGеCp mtG_D:01:O݃N;=t`5 3`j4v smxv LzI<X*'x# N6Vl%Vl K!c;8=X́+c%fR0'.ĊwrbgSĕNN$⧧|'Y󝜞wrz݂ȫ=>ROz箧S!qjh #{{=:N=u"{8EbǾ`s'kߢ(ƺ2sQ~S(7z&@ѝ_N1Xpٗa`o3kS٣=n:`m+_}@`s{_Gͽ!`kG?wG3G<sc{[+cAjk5ί[ӰdMu |ZTgml{gC: 9l{ζz:zζ>t=4Pm-q=vgCmv=ma1gRζm 8s-ll[Al}DaGEp'g8gםm q-l[l[8ٶ0ٶpmgζǝm l{gm?l{ζ[9l{ᗝml{=gm':l{8Gl{{;)-Z"k^yT/6xo >@ 3{<ܛi[#u4 s7|ocB|9i`K btxhhtD{GuGl;wD>ޑ'H;d*l;/Gn''SYƂ<ꇅǃSI|13>weݘ1X֔`Y| 6}+}ёcVabb+wD?KgI=*};٣j$"oeM_6G (L8$p*HuoE㩎a߁53||.H``ׇD/ѾOѷb`$sSVVw4Sly4d!IVxGkwt3"${Udc^E}M>_kQRSyՏ ܁P]7.9w&8 :s2Sk] >~]i_ca/5kcf-1s௬bm{"I@3D֔')O$9$d l;6/V%(|ݕ^.AAWEE~ՑaJ>XыzY/>k%X*޵TLa`ͽuMTunք>ޱ+㷁ͻ~X`eǫ͜Yw\,;Nz^"=ow\1||FzI7G|_:kEkrO=a;];.w"-5~v\c 8S.AAW?Ncl78k\Wg~QGEŹx{=$9NhOZ#黍#rƕ+X}4OBg(}]6mо`މ'Gr̿6fNGNK'G.3':wxNb|;M: Ή3t;N"ߓUs<@:e/N^O]rRoPI5yTO%RQ#*t_xN ,˙Ij pj}͉!w4X0l.fvik+;Flܖd{$;Td?9Ld?9d'lV2OI-rYNrY{Ϧ9T_ԻT?Oyt]t>zIR/>mЗ/B~ؤ>ǣ)w==Ud;%&ީf$ۑd{ yNӗS޸~H}NON B#jT_rojU ~Tᣗ^RiRke2h4hFcW󌦯<%g4}wkO_KpX1sWo<|R{>t* $>~,>G-(*6g#ȓNX_wީkN"ל%:+9!ຢtyqC:_ H09 <469=Bf'A*1SyE/1 I5GS}S[\ez.`a/v1j/s16/_p16bzF ɿBgh_ڀu~bA.&_:]OO ͽXsbp:~l.ނkװ)p+Ek;5|睾t)t<r:D:gDn.:=ӂtƐH@9toČwF~wSLvG *5Ƴ<*ϧ C5?<.>F_xGЏ⡟CX׼'{p_,*m!.npq/m?ym.nR;󩝔i^kn7ۋ#iOמSnO?SnO~`W`k`Ό/:XŊa_^ kX;zc"Y%x|U 6qx$杽1lxs[o+~ܽUrusM巰.=(yA'Qh*ױ3܁cTqT/5H0=}A*}U]߾ּ~U# ї!mw3ɹ7o[{M}Y۞ojl%8z3dl9l❓s;d$EʍRǡ\s”@p@TA*/Ke?18Du_6 \:a*XÂ;M4GB4>9~ Xc?@#Bsz?k>kg5w_n^84g9yj*x|q5Gl\ o{%|:|GO f2<&Tc{w^=J:Ǔ9t.$hĀw^/'[IAyt^v:E#~{&(iu|5՗H] .{ jWG< 5a ~˚6'p_*O[ D#\z` j¶mo`\kc&g9׻$͡ޥ$ &YV0l]o&ޥߝbNr'{Y%]_irϾʠ\loSrMT˘M+>FeyX֟it'Mf :1/$ο+w:Wu:TVɕkGi@pӚ 8M "Տ~KVEµ:4#i< I>O x3A$KAu[ꁵ/ *!w-|s˕yU+/_k_JwE;{W2HBҹtn H%Ȼ"_ >#ΫŝΫΫ8WkN7>bu\yS4Ar48eNkKZGQx( $+{V`xk4o:$q`6 i5[5nk{}i[ }1E?W7~jrN3{($psK"e ]%~ M:դs;ͽΉ^?JO:@Dg1ѹ\:SC:_'#Eg.K{Qk_+9XM}WHT:N$9X9'6s2D2s1Dr9?w<OXu*Zrӧ'mB.$w]&KNּXY+XY19 [b7Dng19S¸əƅ_@z1ցb m/ȲC6&c!{ӱYecO72[S}GػFcH7Hzs2G%W {W/7:n11v~ [_>|:ؼWyX[:$CIvoYq6A=C6s!=岾MH2һ\;]w$w>Ց,X;މq>zGrHz,XiO|_Py.KnI 6R;Tmco?c|mk[a=nwc9Rl~sdT?) vCKIvW¿S~ݹs(9|&} _2_ ?},Xc`wj LS K1.5&I6d琬S: _X* [}`6Jd_26c_.d3\~ɧY iI엔;~J:GΩScG~Iy %IҙG:דΝ>bum8 k> ^G7LC1x]`l<Oy{^Ͽ5n5a}9^ [}'_l.~)N2n_M{_=y/#agL3ّt"I/:g?sI 9t.$HϢs>xilRfMs Ǩ\*H5?,|w\~k `za92x7g>|C5n/5]k_l}2_:>˖s|lE}5w/le;ɰ_V ;e[/L:'DǢsnɤ3t'KIZҹCtb}[ؤlMwTypGS}Q}we(#YYf;:!Fk< F\`]HH9X6䱌`K0ٝ!_vg˕{~W0 9)|qK/_9 zI绤sA:M>hSg&\D:Wέs?ц<ؤ'wσGQyp,xO3zT_~FOwρ瓬Qds1e45xwc"(xָ5%ek_˝ }3=l0Y뗻c_z9^+޳(i}?g} >FY(MwLt$:'WN̿ҹt'&;s:io%aLj37QYB T36--Audws2Ym\uׯq]Ƶv,{6sm7еaO`W.XrxssݵgX}7upE* Ouoeg G nMz<'c(x`񺞁ƫO5 ǓǓǫGՏȏȏȏȏȏȏȏȏȏԏՏ/u^^c13_v^tm(<6v-c x8d'KJ5?`4rKoe&<. 1`??|e8k( r;/E?dǒg$)Ycl9reu">u{ȟƅ:uHնDkl ;|s &T4ɧT_njQH 6)$:ךDZ4"&'z kM&aO i_|< >`}],luڼCyܹB r }+$$ێd8W{ఏ_!dpHd#cD}0JQ|xʼPBa|_:23?8}LwJ?;KdV8|'0xS7xOr-ad\HWX,o[a@b+{T LڼaCaCR/NOwIvbXib,WHi$;d_IoU+e>rɟT.6m|՗"=՗f[@;6t 'S LL10Yc3Xc L'ӽ$+~3`˙]3_XOƞRnHW*JOXW.nk_>:de`YV{S_YM~NgHg7هtN:|W{S_]9t9sVIU7>Wľi 27R•OܞҔTS}u&DSSZTGr{&;M;xS{K`er\姐߯|e[ [Nyk~-APkU%$v"|F>YKhϕ2c){\scT~zuuWLQ:0kԩ%T;֨Sn-5h篩2/gb:ULQҙT:Jg2S5wa:5_x$XuT ֊G!n=lAbcx ]%t]\K\RYYY y Ztb Vyt>K:_&IS_T|^8s4uN\p$קnCUXqn$+:iyZiysgiչ 1bh=XۿL3̧t>`\汥` 0ǯov◣^ͱ~^Kuyv;_YYYiٕt(:ׁD'}HۤC9tNߗ_]I7Je] Y WܧׂkQ}Vu[nLF\nb3i< >5FpdHvjb'/Wa_j^mRkw#P9t&Ιs\*:~46wcd݇r]nT.y>"8R}YGP}Y!Y9Ȫ;:!fh< f\U,s %lBy' U,qUv־#XR5FS~GndU~y$2ϕlGGu~?h}T !:r6gܯs{_w:Vq:>tm.:-D'ߺ-I3E9t =.گ+2;X6AelT.9?X%Q:TG,ydXeS!X߹8 >ֱ XBp,>.3x Ց\ <wL.V9쓨v V;t;Aw<")T+I1AQp}׆Ʈ I]w{`(xd׶\j:jOGrk ܞ("˝`rIfxϪ9.S5 7rvH vH 쐬>m ֜ L~L&?&ՏQ`c 01B~L!?Sȏ)c 1E~l־<ea"{̬au)m{ͳT9ҶOlj'Gr.m+j~>(u5r|>^ 6}}hKgCuQ܅\=/k67F@#As~)ŏoGVBs3ROb\r:| v#{h% ;D6RzJ=F:K@#Ҋi%\4__\+εҢ]i>syxaMҰ'lҾ/Auh*[lu2\4OE7w?R9$dHV4Ǐ@H4)WlQ_.\)ke}+x6ΡET_DTՑuLwJNiѱ(]s `StYݨ<տqTޟ5`\Ma=ֿ˻6mY;?=WjeH/ FFFgIbb,7dt+8? tӯn|?T.6 x6ϡ2_ˀRXb \d%w))2(2$w%t8gн K`S7R;D{K_bRbq`?ʑ' 6ߺAnl,*XU`gqt~K:Ifҹt'D'bIylr٤$l"Do"Dc&un|ƾ)CaM2 \r{{sT~kbOp3:dLIw2j`k OG_ꆴ~CֿMnM&n}_y$&$+{[o"{[oG[H/& rJa-3ubݘC咫Ï"CHh9tN9CrMes=E:D'fM:M^q/~ :N;6TtòGP}Æۂ5"YaC9Lϑ~630ɄL&}nXܰn`luRrߠ`y1\7k:9~O(o& v' 3tfίNo@t IJҹt H|7؍M])~z\|Py܍cqT_~#HV S 5ٺ x0u IYx6q-*X:xlu9/>CTe+j˽'Qπ_~zg G tF:#9Ftv+:cߑ5yt'_?JOIoE(߅gP0Ϧsw?sIVרy`gIuϒ,L3|fxq< }Y FRM,<Ka/\=( \6uKȾ6Ⱦ6D9m:9mzWIP GN̿m>" s!ySF>m6KQkmB*ל|/P} uֹo3-vp:!fkl fzuXcAa.k kN ־?\fcH7|R_ږ7Z}m-f뗶[_ڶ~O_6n%ηIcщ5sɢo)3t~M:εS}Iۛ} r]$k/7(-|܍|wspQ1pҩs)0Sl|qqdϑ'Y1Ek'}c myѿ5_k~m36dC Ung#̼y]go7a~l' >OvoK5~+~k6VVύW=oߺ~mڗs[禾]7m =ekn\HQ@57^u_J\em_FXr㗔] ,10_R)}+X?8Xrc`Kv|R{Gm |Z|' _⯹/~Ws9H:щߢ9v:;WXi`p?Չ:Nca+y6Wֽ\}9qsù2GsHvl!s1`z>/dUt;yǮ`vh*/po' 3X6;ukuHF[M^ $nIo(7< ;&$;dǓVkg35KenT_b/{x8ﲗew>CםlN6WdA IV1}6ӗ7ޅ˾rwm\+nTKumy ܟ::}}?h:Ùә1<Ҿ1C`KG1/<{EleS9#om1_1 H6d7^Ÿ'1I<^sȻkiL}4e_w/O\])bӊ8.[IE/bdrY.a.Ia蓘G{ۻ *jPThI% STqz>ߞs;yym֪  F|gz<"zʳ n?M}PD+χ}`~>coA[L}F k(r?\b8!pe_ ɏ (p驦_6zotq7Mx@:QA`տnI }Jj3g9+}=i;?|-6!?u}fk֐(C ԷCh$M:Hg,/T,!S~>5C7S3sYI:w:q:6t:33Tivz+&lZ+y>8怛 W;Q,plCs</gFO|gx6 aC3:3z oQf|v6o}أ/}q].99 rؿ;t!5"܆k ;Q_7;(vP |&0vmvTHݒء{".V~} 6oG[-aszt;ptw| =/X=gD%H O:u1DEtHv2cl>2cs9|tNy^5cyEk6\,;cIuw$ ~њ蝺wZbS{վ]{c :~3l߱/'+v~㩱۸=kk5Lw\[ۍ3]'t&f܃wL}N8쵌ۼrDr]OG<ګ5kN|WX~>z]tַK{-SE%wծo䮔+R\ND+Z0縙~:l.Ϣ3㰀$3>>za|57_Ɲ;qUssittV.[ʻsD:&Egx$f:)7<^{e$_N)سIFjKW.ѳ5k{JC_>ahFދMLf/%ofp LJ}'0oKzMgwUxMCČ׻o|v3[ Z|^\lm$4%<^lʭ^i`)Q_{+Å֚ z[s25XrrJIN䮔Rڂu.u#}-= I<\|?|7_ƿ՛/wz~]oKHYA:ϒߝ r r u M m ] GD' z:M& ۼ5$538^|\@ M!_߭]{JOSz5k `'$v{ 6,vwɷaqf|k&lRk>)}SP_]߉WZ&6ۼ Xzxs&R_zG=g+׸rKSz-Gaf~_'vxXR=N,;ؗ/դ3tn"%tY.|db,>2J999&ѹ6t)w)ς/:>uHڿ5X8Oy|3Y`>z/g55kk @e{I>fh)Oy3i(xI6kwT?,% pwT;{4W5n/Z^#Oݯ1m$x39dN=/~1oKeW/_|v6|v63H62H|s:w:4s:v:tottZLyr[kHy5pS BjzpWjԔ7zGu֨`0!!s*X6 y,גFů1S/^gD/3a/K/_^oȻ3"fJ,&H7Sޝyw>2S~r:^tNmtNz9UޝTywdjϿϻkݲ\Ar+I^E5 T˵H׾픏)_#5k^~3u4Sņ> 7#7mg613t5s-̐s-8]]Ƶ^_{q7G}Q $/#$?JԾڨ|sX.\OpǩW45,~O:|!R{)T,~OLܖQx+眩SsGI)gԦ`ESÅ[%Ϥz_lfwfyyuf|jfg|j}<_ϔo_f|K23%ISs\F:[)҇WHg&B:%I9sQOcFh #ԓ$O:6$TpW{~^Wz/dC0GӸ,hjG/:* Xi7Ǟ`kV'~'|zlsgۂx}+gG=_As"|t. !xEgx&=YN:NitZ<ġ _~%RG\j!`?שQGb u XUX0݃OOޯV_ǀ׶IW\c ,ur*8ɻ\S:wKLxYWYW_6[jޅ 2.ȇj޵a}n*j7\uo9iOTN{rE5P'P$wKX\T~9P99XcX:UW;w$r`V;[#tvOg?<_fD/ٱYҙ@:_&H%|mfo_fvt$s-Ӊ81tZ̮8ZKտ߁<^+2/ppkIpJݕz Luz_qPc{?iwziwPc,l>8<8}%ҷ i5@"uS\awbݙ߯7ssγ slm96w>'| s<ÏfNk蜝t'\-щuEr5Ns|\'9@t&z:M{DS7INH^PCk~\ZvԦ=. 5!z`ZZ|CasH4qI~K>IW\r{>$a3 O:%eag5|}XiM =wUM:,әj9"a`͟ۻGGG$gk|F1{G#%Gj´V =gt3͙Ŷie6sj8㼛Wf^_ݾ2om,b3{$n-37U}$ ">s2\ y}X)C_+56F@.r$O^LԜi^shhاc a?ӵ~7Fnl ۸-ƶ7qc[7.qc[M9`7筯6^3x\s|:iK^kx3iKe_2p#Gc13i/uO"X/1K?1/9~Lv ;Ǐ%1}1G]Z Z?FMK뵬YݜqzNt X}_0*9q]ց5 1\pz<%/#z `?I_JMe՗W6_}Z*lƭYXc'EZx l ;a.yOjW|]oca>7[;a>}51=^3`|/?`|>y?̛_/&~/⧺1?KcXBcH1NcȢ1l1Mc+cX'c@Ocppэaѵn 1,ōa]n z1,zPƀ7EQ^J u.+H1$yK/k_{lM0׷BAp ڟVBk7?357j+k~ {m;GI屯(}syl;XT1X;`닇jgh:|͋E^<,E[=۽sĆ/HYt~J:OOsuE'9[8p:ws:GA#y< #j^b#m/jԯFjԯ4F-󅜠ը'F=A5 QOPzj1n 'zRk<zpq6ol BF.Ws\<}:TCn|%JI z~8>YA:ϒ΋N:Nfuӹӹӹ$t"Ѣ3h@<|Mϖ|Mϖ|k`{~zD {%z-fIsUcbC[3 [g+\YSlS/ҷ=Rv\߄P7גL IGpɫUBNrOqmNZ+N9磓ZS]9o`Y.ŧW z-&Ty>J >*a"ʞT]N\Iw9q&a!]E}7R_#c从Iȥ^+ߡ M|ZGB.99~p*3I.1XHp)?BmR jsH X|O=M~OsHcz{/A=7j`3֤ǀu̱`3|+ςu}\Vls`VP-j'sׁe MOIRWmuKLNiVnɼK,.8nN=!XF֍ K%=w{ \|6_N9jrJJrH=O^])Sz]z]7?Lo 'y_FrugI$O%y&Ƀ$֟.7V `ɷk}!ߋ_k Æ߷wv~1nX=S{GOySriz&4=rZ ^>HK:/=M祧^3>eNNk-X:]lrS&],sC-7~A #o }Nc+XaE:+ O ஷR R RƜ}Ve/׷2Qxgȇ:fƕ&b2yjŁ#J}ny6X[F瑞kU!L1y|w|wF}_Q-ΐΐΨgt!d}~`}f??:+l?Frgi-;Ko:K8?y9Y}EIԗ9Y+z`U{-ݵӸŵӸŵ\˹w-8(s.ƍ>7 ~\ B=k!_ZW \|~'8'\Wz;p;s_`#IEa$V%yanހ廒$/ y wN`}r@/|ks^{sA`}1,vKMt>p^x^{^$#<ǓN9WI|[?qeGO7 F5{u{>o/r-R fi;o!x2.}ړ7Kt7Kg3 @Tzm+m .T~uYڼ*m]!f:,xL}f,@[^J~kYZ6CE.9; Y6SK^0R9{<2KK2fٯa_ü0K@2o6 SX 8 )~'\H5^yp*Ϥ6:OQ6O2'/'u9O>z-yg}5{mZǕ}5g+{x^9/eVƉW$&kIg2#E'buщX]YD:Σ{ә(81y&W]~~1Q#R/e Iކ\~ ܋ګ߇#t E> -G_ȯ>`ݻ!w~s_#_e_1t"Xms`Z~Iç8L7n`+ǂ{M|YϿI2IH:ҙF:$r6r6Hg9tV N*y_qbV&8L[aسZHreL&j/~x|63@  {gUkU‡76.o1raj_׬ˋU/5p0 ,~Y%F}*6cVmRWUm4Ь|| v6/˷쵼F5u5GDrYk2G yk^njNPF}HW陁虁4a: LguW6X>|yFgorv}nF&BplЯv6/w^W.:>-%wKj]Y \sӹӹ&sӶi':m;5}H@9tN!RnK}hmfħ=z%'d6!y)el 6*jѵsm.rm.֡6rV,5^fK̗Z`zT36C\y5Xb 0).P_S\"6XjXg/`_v,Epp"X葉H ^xYNrI7kygpj?9//=oǵ8 InHux8~g~98/=}uWkLkĵ%ט,(s/jKr-%/k]6c FmFP_ͱσcX\%ʱ(^{Is,sIb2cX뇕`6-|5ڑӬD4kFd=;օ6if rY;m=v`~v`N3f/qE_6/մf֮uڕ5ick=9ɽw"lY4z7K-Z}WKϜ E$؞ CRjh(6;WwCt ^)q^] z-faĉ&9kOs/\Ϟ4 =j ņ J AgNEI}gSƥ{Su7%}WV5ײȵI3I:P{]wK}~Ccp'׷ M}uM)Z5ָZHO!Mz*oX֮|WKn<ƞefl+g~y5*c,oLj2I:IHg8H:դ4\B:W 3tnȓI[=&IEg~ _\kchP{_㨽8Xm2+W$ؽzZ1p5e~x|{M{)H߃#\^3L#=IeVςu>\<ͯv6IG/8L5Q/љ<#e Ͽo/_os:M:Αs|ZtF1s)\M:HgtX6O/? rPo_SEr͙/:ymk_[\ ,/kk ׵ݳ͡e}A8ywZ[BkC?.oUrƬz`#z&n7/{lk?<&G<ճ'c{V+"I^G}o!mgYC.|d>IS^r{/uԞ묻u\:Rgfv#qB먯:Ӳ:םөr껎J. C:HOsVzeo ,9*XsV$jgmOඞSCw1OSy~L|f uJw/&)=Ŀ؃$IhI:Nyby t%)MYL:?`{56I~O%q$Me^NUY먯rYyk1W64>1 ,kwuqX7$D#kn0uJwZoc 8ϲ+fߤF{ʩQSO'ԹS =uwѤO%s3|t'_NԣcLt5v:nӼ߯ImEg_:zaN^!Å˚]܉GPHjEmPC1a`#?5πב\cuN' \@~˪k#Nszzqq3X`I`CEc5r>\'̅zKCd.M-$yC}PJ[Ej7T7F^A I^Em$5'K da:h)Խo.~ d}V}pdRwe$\Q{}Nڡ爅MK}bCڀܘ{G)!:ux 7'_pcɯ1_|7릺1_6+tcԍ:w":w":G}aZ| qc sc 1!y;7nna nakܘ*ܘN1]pcsCwCטe>fkL]9;X&`w׋CO2잾 k5i#|[i 7ǂ[e_y7m!j΢ӼDڤyfsI[N}_W΅M&Ae׎"ǺKtͭc rI+ڄ{ٻ}R[7Hl$훂56;] JHOtz%X?ֲ˘^k};k,֮q`KL?Y2_tאa9LC庲F:ankZ=Bpۍts#H07j}F׀eON:lD眍$NQ6RG霳s6sF:/Gh$v_4Rvz Dr{Y[Fk"j/q LkJ#Fc5ƶ5ƊZc__w5eX_뺌urK>kMc^M M=51эiK_k%rfz%uzEm^Z z qe4W =:_==Ѽ?z=Xk7dk%ݮ١XD94uk}vopcnmmu`=IW17Zi-7uHԸ17ucnܴčn7GܘucnzʍQo%esnlڻ17Dnn"ݘ%17KrcnVܬʍy-799i`3YQ7׵IOHJ %d#6f/ɏ\b/{X1/7EuoOmV~p{ꫵ ⭅3y`g9F}Bs$/ y KI.1hq~W& 5/o?QO<01j96j i&LouLzP>w !}QD XO{ i#5r9G fg hkhk6K|6}5k>]M>]Mm>]_L>]_LzY*bդxv8y6y%N.3bդ66L ɕ6ߖ8wfFy̗ԫ-elFr9 INe^mىK^Ai)"5p+%jK>uhKZR}RֈԴ-<%g̖rZeA}{Է76N>&_}.rspo~e˱vыՌfrYnz ?8B0֚,_d|0k sgì<fMlk7YSVOP߹V&_R,껕+}35?2rH.9$O5~3Lf7S>YHQ[$"oߢk܂<_dF,>B3ijUuPV(r{ʾݳd[A}量Sǥo{,_E]FP+ء \o\!mS-鿭[[;nN?(#9_G56uMH.9owS kn w+ܘ[ܘ[s+J1R|*F>zgs`+NMh+?J>J}m|cnŘ[{sksk?zs7|Z1Zcc̭V_Kݘ[11_pcnSˍMsnmnm1܆֚6ܘ۬qcn5a Xm/vgN%8H$n%yx ,+V̐z9m$DQ~:Gj5Y0jœc~&WX;o5zakb֮-]k t#ܝ>H}Qqm k/l<{H |G ⯜js~_r/=;Eޡs"hUk'8Σ˨5/ugZ=i'"p%XrEXb/P,-FW;<~5C?n`6C-{%7Np/(Iפ m/1\gjӜhLbؾ=#(랝+yO37fS;[({m}j4_| )#} Ζ89is\Emiskydroy+J֑`~u>b>^!,/鹵Z{YCwט8ڡ_5͟լy|ɱy< k7y`üǩw]"}a ^J}K}Өw*-Mr"C=5QSuhCv$\18BLuZqACܣs%Jd5Xm]+K۽=;ܣ{F:h$ [=wovpOGng/%s;81\#vlwlwwFcH4?`$rk Τ6i`t@h]sTCvXwv{7ءSC' ICXgNv؉lIrvk{NE'z=wYש|ƍss7νܘ;G1w9ڍT7ݘ;wcܹ̍!74f]6BںܥsNn]z1wrc2̍Ksn]ָ1wY܅bKs#n]6 `9]5?`Us`͇؇vU죻")'sn Iގ$ nZG&$~~/w[C퓨}*/%ԾڗQ^. ]TuZf߫kY0ꢼ3`[KSu ɯj|ﻵv2 ekͿ=/^hSy"Q3k?M6ϛ|Y5?.z3]|%䢶Nr?ɥNE=6èjMm$K>\b;ks5XɭIK ^@m$^ s{HN˽17{sŘ=,zu1йIZ{h5k5%4׃ 5B{u5w)וܞF^n8xxݘ{sc){:DZ7kp\{3ɞ'{R)y2{u`c`Yrcz^k(|Ks&rZ$iƂe}̵,VoXǃ݋Z=_ɟ˕'#$!ޗkc6oȾ ˾ oSCK鋽R~" 3hcm}G|ۤ_m6>&x1[;xye#Tp{w"y0j{5&Q;PXj3L6޻7^5ؽt_^E{ŜWJ{\y^9دݫj<}ڻk[)\޲>wsw/7zG[{ޚog)hRoEZ{{kF^MVozW4bG>z]>r]σ#H~xu{>^{>,'ލޣH]9Gyhԇ>T':9BהU`5`c:aԊz`]SKEN#E躀)Bt< 146ۡKKI| _Mn ~S%(.5Av >I}gQߥ7QFWDPh'G~C,M6}lj#K}LP;l[^:}HyI(j#'`S(sb$cI|"N{LJ{_s˗`IAwdCz$"?/3~]Oe~~~ ~x89 ~ >(qx~9&g޼o6՜ s,)r:ߌ h9tƉN~D\,\F:_!3H:D'j7=&o K͓ɵ |䧨_]|` 븾z;ظx@1@4α}@{Sw|DXk?HOsz"eMC)1:?RojHy#GjgqTǽXs'|'ު\o5}n}:x[Q |/J:Ǔ9$9y k_?~=Ku'3`YEk~AhǐR#lM'G(8O1c(m?6O?F׋z񶹛cXӿyE٤?˞g6İ(/r͍]:˾;/6' Tƿ(Dn$EG<7_Gf듈^n~]}!(qy yoH N8 ٺϋlO"HNa_/M􇁽2B5n\a8ڬ!抝`͇jm0Á.fR>|D;`ʇP>|#|G4|^`ޏHK$/$yKH{HQƯ>2vSaP6/N '۽8)/N A^$q \,q:X~PΜwS(g)!ŤcoB#n~k溶]8<ã $׳O}rGJ99> ֽg6W10ϣt>hG8Xd8o!՚+| Q[>Z j wzi~,]X8SaZ~v3hǂ.'Ewn`Lhg^ l{=_odldl{t.#T$r'fNYF:Jy^KtߚvI?B!:j8@5 \+jL gѳv5/u 8r`K`Ɂ`#'zx0=tH:_%sf|6&IWQ[tbﳣdǵa~/t7߀ % ܋GM!ze|~SF~ssG^!'T#l;_B9:n C1 u?X~"Xj[˵Ce^[͎v0/>wtlzHuKd;*;wTvwGCS?eҙD:sI6mHw,9E!8imRT_S}ro~GpKہKXϓ fsna^'bu>oX1v$zi 7n ۹1 Z>;\CQs2'{l <\Ǐ1׽<\y~/p=Z@Nwq-sԘ3ɏE^aI5>#Au~US%ߞc.3|̑AkW;BnWY?K/a!-܃9U1͝׽`6)o&]J}N[_?K%_>Ss*sx_#)m=ǫ$'\b>R?>J j1\E@_F<bqke-,kA>7{DZ)k1 a+](!U,/ߑyJ~GnSR9o>XSwwgw†fk󑾣r]S$AP{ooP{$!$Lg5iX|7Gh=\3t?GK ``<0_cvF=3?7On)uƾN(o|T=2lR3JGη6w{e _G/ޫ{{ou:w:"r ?r ?Ig4|t"KHJYNtZ]%]oBs\Er˛|ϵ): k?RkWm`}q2r3ok#i3>#5`avzB=e>\c{T/g;7{~w x}7x~;jpCs_+s_Gs_@:廝7 }H49t>O:_&<ٷim/I}'_#~ ܎n$E#$G}"FI"׍}Yg-$[FIn fgFIsc`\Uh`>,YsaQt>0Zrie̝ pw4ђKeMpg8G'Q_'hgk>Ép47:]鉖ĜV_E-48ZOFA:t>'z>z[&M h x4=GMc$wwe ލÎk811 z^q =8F 5ac14J7xƆmtwލg`}7n^;^lG~]S̾#|wmkFc )u3hk> F $8W9`k/j_xp8}?AQbp  >f?ǀ3eW׃3[.lR٤I&e#M&;p6)[lR٤,٤,٤٤CgOMʾr6);lRI&;p6)٤My &9?lR>٤ig&/:٤<٤٤gOMʿr6)?lRɁM\lrɁ۝Mtv69pɁbulbƚ6yx3oW\j(U^rQ0:OhNگ>Xu`R5_5k5`ɽ&`'`irNlnz%X Fc:V#Nе9v5c'H{?Xm`zw`BNzX6v(w0kM[1֚t~8'J-nD&z:Xr-v=z iݮQnlbbu/RGrI} {ROǞrD矓O w㟤$z`:3i$`{L$xI42ޤ#4n<17d3H7Ƀx&GL3ޅL&ӽɺGֽ`W5UM{UxNxxxЙo5[MXՃ`z.kJ 粦h(S07d=0XZp/tQ)a+A}5u:HA!QW;up''fcm=0ǯk9`z;{fĺ|}5`{vXTݣ`]>'~u!˰.l ˰..ΰ.wuGmc]> nYN7լ灛jv߀up _ͺ|0 W. oլ NXo^cm57?<"ipйGATd 1o*qodPQ# ;*(AAY"}#VY !A"']5{ꩪ>{}19kcr6&9INI6&9ژ䴴1jc$gIp 6&96&9lLrۘ䬵1jc$'$'GbR>$1>lcSlcɡ6&jژgcraCmlL٘`crECmLM194C+mL19ocr(nC6& $&&&ޜ:t3/!!$"}5K<սc>=P _˞a+zcqF:ғ>=pWrbppm{#u5+psxůu-H, =FҚ;{#i7JsX{ú0mEMFE`6X=ۨ(k(:{GXCGI xk(/a u^{mCzY`2MѴw{G#\h]pu,ѺGO>鳭t==ëzloz^ `{=FyuW'OW#:Gt FדEדOSBSjgL1513&Tg6L&Ѿ4`'0}ǾE`05z5z$_Om$!ykBc/-c8\ӯw8kBu׸/{skao>hC?69|;<;kŐ{kaw-up.Sk@߫Azwy~>ucx`:|i;r'{kّkّަkّ^OZv= eGz ȓ-۱yΎ+vG&رyߎȇvGVرh~$ŎHCvGN۱ŎU;ܪv칵sٱ>dǞʎ=}%= ݎ=i;۱fǞ;َ=w{vsscgǞgǞ[lǞ{Ɏc~n;>;~;؏vw2cfS 炣]f-?'> K /syQp4ɷ>Kg 1~~|N9`|X9 >stzX][^{ョϋϿϜg&ۉd+-QX^3vubx]1qw[?X?Z?9s`ɻ79>N6z8ƍqzĻNzen\6}g'hkK 8ڎb_8^x\l<}.6>O˺Ox\l<}.6^"XL} \l}.6!^τz&PM&D뙠X,[뙰''g7]O.]O]O1]O ]O7ٕRpupckF}?j_*KMn̅7^yyz|`=O8AoR^{q{ٟ䴷y6oMۼI{7=̛z tšrt_Pg]źQeG"-^a-;ֲo`-;zo`-;zr/XˎB)_ˎUuײcrײc !#ǚK{ㄵX~$eǼE1a-;=C当?6콓[wR{u<~ ֲcc=ٱΧvǢ؏رA;cv~_c?^ݎxm; ؏?j~'؏c?v߰c?2v?c\?c?Ǝf;ivdz؏c?~Ǝo42;;c{=1;vy=ڱhǞ7Ҏ=M;2v\g43vo.M_oḅHNr [YֈҙH:I't֗z[ve- z[3:QN`u0k;ι#VSėu.߃ cߕ#)wD:[u_S;!~.6D-k{>,@{-Wۈl01.Fg?LۘDZ;1ɱߋi':/w /u'^οDgRhywmDt5w5wbtDg/Љy9|^߉(MF]E^߉ȻN襾zD*tDGQEwTC|'TA8ht7|'P3FG\/:c8 S":^~1:į#:W4_sc^NBge20}'NSɆFw Gh?&:Ϧv9?nmNw1S'\ֈ p$ɧUⰗd+kbSWa?U[\MZ`a]*kJSy=DL}`3q \ƸOú0UuqueMgr&Q\CGqطOJv:F,=6iX(8䓟gMq6\0N#o{Gq'kI~O4<6kZ}۸`m\+pK{ Z?Dzɶ`u$dNZ?Z'5x_ե~fP=̠zk=tS=̠zA0C{ZOfP=̠zA0S! L0a&L`yfR=̤zI0aC 0LYTpE0a,YZCZ8Β}WP^g8}9F9N<'vrX9!҉~d"{7x;{?x?{}${gK "ߩ`/Wg~p ꃽg~F{ͱ` n``{9=58vLlzNc<5Îb;SkOmcMͺ?KֻteV>n?[Χ{-Iޖl|y XL`铱߁ ,bK,l`;r~mbwGuʹ>voMVͦgfg~Ob٪llzj csrk=[5CV͡gDm.X/![z~=K?GK8͑}Q p ]};KZ\мfv^G)kmaDC0aEοQ=̣zp a>|TJZTS=z(k=S=̧zC[>z  /@/;URޓOǃx'SޓO9=t1ӡ' !z`!3`oGO>s?l=L#wEO>}6|33z`!3Ϙދ;蟾3CXΌc9˙v,gڱYerf˙d4444XVc9dr5cA_r7GXζc9v,g_c9;Ǝ$;X.c9er6ڎl2e;eE~SW{gO5OI?HpN \$K#=!nǂem{,+n:XCHsm.X,?<^ rp2VkV?kրH/qz H >1Xzc$~3 Bgq_z`~gXZXX, "qf_ ř}6x]<0Ρ ?/@3 ?<.A e} {`=ߡ/az녺^7zhA uo{6NТ{ jZ?h^D"o{E֢Ydl%.t ׋h^u78/nbm[ŃVXIt{ ]Tk=k=WKKL>GXs<ز@+_&9g̅f` -Z\ˤ1IŷG\,ڋGro|/x22bY2ueRCRe$G- u\o[\Ͽ%ױ?,3/z`F̋r]^k͏}ra` ƍ7 qou_{;`u|\b>.^; ,4]p.^8;,ƾֹIG瓡g8w*X6lV~ ~6=|icSO$[m,fJlc?o6G~ңb x+|vEKk"l>k`btd Z>S=zXIRaX{ΕT+VR=zXJu`T+Vj=| z L3Ϩ>zzLgTi=`?0gTQ=|FJ!NkFoY%\%s?sjqYogu}x B;W}Tt0:ػ {NIW8 :: gUL+Eg Ns,ENjf+բjtV{MmБ*Qtf0ĉ|j/ Fmmjx9#:^|Bg,+DyUGtgYyxp:o9?;Dܝwr]+qތZBr]Hu 'dAGg"Xtu8ѵ0X1q]ۯc{=*+=mg{S; y<7l2Blϭ[֑mn'[釈09rdsY|8,{݄ytVN%7,9MwM0ΰk$w 8>ge}O=gγ~9=3fY`] u/T J>#Kt -9}ZϿ~s\s\ G/,{~~M~$ǎRߎ Ρkȷ~:ڻ:zo&XW /% 8˯zÙ}.'k% +sAB-9X9\$}{`7 .z0IW/ܻ콋BMFu Eȶپ@{¢f?}EoB/:M5:蓾i{чFg?2:':+DkbJ a=Fm0:h#t,+O/Id ȵ',^B夯bx=G`_QzGum׏W_+:zOb_Q'x⪈7>稱˹c˹cmsB{b=Iq}lGD~mc덥W\^UpkCJ|-z|C}lۋ-;-rcm\T[ VAk8\> nLMHG{o Onv6s;"E?s9s6{0;u,#&GoXF|%V7K>7}0}גm"~G?--zd{l/mآϟ!XnV6u-8Z璾vKHG߁Fzi#=״1Tu.9#Xou, >L~nN7abp$VXl'd+ >b]Gd!yLc 9™tG8WnEraa7.!ryvzҏ&]i=HFZ69&G:gqݤ)0zu,!>{M.TdbuE|X]h>`buBbBKAV!> r]xlǓm$[G,>=GOn8I.5!ަ?t"Ig:",NwD7%|ɳI.=gMN`{bGp)e.'vq'b?Z8FkY8Z)8 G=;m0οzDMFGؚw u^sW~^CzCKDگp ٯ]C׺ {N~u>`/X97%$Dr`'h%Y+pe& ,K|,J,gDm7˚X u^,JYx08$̻Y?CL6SL6SL6KLqެ5\Lmg63E院-$⌼ELj3zh =S)ڢ-:O}`zh =S)BmU g-/yM=k֖?.d:`v x!S~ֻP$z{(/`S~ֻ Eɓo_Jk[dmKXےFb}` Ρ'=Dz5Dz5%tXI) _IWxs= }%}W:ψοf9A/yްܩSS!s$ 0׺jҟH:Z,V=/jmx9ދ3V`8XyL u\ 5I#D c~8J"өNZ\2WB}Ws%w0,&보YZW|JOXi}보Yڙ|&Cȧ__O%'ڔ3HJG~< {X]ːXͻkz4N~{}ů+O;%nш.[*xWl=Fd{Ilg.Kl@k{>k{qU+%\pɵW&X9N> U"/q V~e;{K/_c'{D{~~|mkbmwkMbs Γ>)>eՏf\܏E}W?#[g:E>ϳs4@|b^-$WkUk>5>ɳ ȯ<ڣEubr.NOd'٤tV91/u){b)X'h ]{̯6h{E&n"&*צ/I`ks%>ydlV31] AL|Rv7#[}dwM~|,ŷʐ˜My!a"e=M O',җ9sGJҗyT,=9 甄d+yOY&ޅLг|ʗIw9AғpIgXĶ6QzWR8BDI8$j?k||uy_$I 0\zp53_W7&/K9|FN|bݹL!?O>a_u~/&}^'\(s6 )쁬\$H_rsYb>ɓyZ:I\'鳩u= g$9/'=9. }o~~_=M~}&ne#&[Yp2g.پD<9(W6l JlqF+[olm0\l3zx%ɣH_cxҗy,=9Qpj$SyҞ|%Z"&Yd%X{W+6`W0gFW1H~ Ŀ1D Fuf/7 ξ!n4>o>ot%}s΍W'9|.%kȧ_\hޑ}N'91)@0ލ~~ߍUg.?PͻM|0^ O8 !V>CL|7s:w#%ۡd+ n#7#+}亞Ǔ MX{`p.jއ{+UTWd+U'?%[z!kHXh~Έi= [=Ui Lzݯﻵ?[k!&Hܾ1x}J|."d󴈉}mdk*X{4:bĪ_::/'J#oK#Ǚ:iR|qo5|gב}:gA>ϳ7|Q|n}Vb}Ve}Vj`}VzF|^L*0Asvh鲶&}MrK JoLMHGs&-ӳG:=.y>((]ωZ+K{^[߈?#ȧ<ӈFȭD>w#䳀|^$9VqT*T:OHޒuߕ '}L2:Q2yLZ`z%oɤ[3Z`K߀u,߃#VwΊ3S1pKP<䥊N4y<8+d*M^gKcs&\J>?'ɧCU"ȭ|%y< $>PbPBdC.K < LH=җ |78l>~Ȣس9,݇wz8ؿؿؿk怵XW"V~6% |ϳ0% %`4xEEyqv!+G>3dpC>Wy*یU{T P?' %z4luZ s`"`KVu{}X~[a℩m'M^zk)ςM^6y:|F2qv+y|"gm#oU'Gg!|޴>)>vŤ%wh]AZw篁k\>%?!"/^4&8lX׾`+t ]k)8AjreUrr!_X%)䨓jO./ח|>>N[m' y]`ׅC䇞.HۓkWm2n'|ѿ,s6oKwC%/%.x(N$d%Wrp<]C'?RR{ umadXb{ ?D(M~,,}2ΣNЏRثT{ίsͭ. zQ9?9^m%毗j/|WK_vxW3 _sw|j?;{Ln`;nu Cz0㽏V }z+0uU^[ڪkV}UE׶--Z&k6okˢkCv풽o-;˵aE P{md-pΠk[BEMזL׶MGFv}d}oA.s'y 8:'`җ><N׺^/H'Y1,{skԂ\ը{G5˽.?z,킘5Z5zZ5#w':\H>WhL>OXO/>5~}/a1;/!ߒL3cv2o'lM:HG)?'-@;d~hKߙ!wv\ ֹNro4x(Do#}[\}.CtV!"c~uE;λv>םt'}>۩:(X2ad{m;$lѱ,Ss/!rI^ .:du]=".& .?.2`...'` 0qqq7q7q7q7q7q7qq%X cK-dw'ܽMz{{48kKkOKkӟl# {GUpIZ7ZOg Y2V-x e~G|-KLi'dґz9{^}'!)2OS:ot<$Br-)3~[kv.o%6g_Qt^7G eo~ϲ~K6 |\l1#_ɶ֑_B.:K޸y)@.3e x{/'}Y/RFI_饌k 'k`~ا505:8hm):ǃ#븰߷˯qtF_15PxsnQQNy3W؋Y`8uJ^ϵ3|f]D:Gy[{YW/uEx1r)87퓽A &\z{ }y$'}8HHG{;;L\׼#~`9k Gb, zndߺ/5q;1bV}pM~3uocnݏv n!4o[dٞ b_gc[> .~7"ho%}دNvc_)أGwQS]YSG= r Z6lwaz@{ק`7б`x`7bU#{Nz M ϗz|7qv.yA7|N'j|&hpB>wϣ|ȯ[ObR߹,:O7KHteV#\3lʗ`_m0ΡރAzsgj=| {2Ȗz9-ι/8A9:s׭_ɯq@.0S?@|K&/_eRmz n'Ys,e3|J>[ [ V_֪Vd%w)$5:%FpW?ࡤ!~ >CX!5ϐgHc$ r]Jx:ɵ^@%x=z~p<X?B ʷ5p>9,kYa0ݟ9LgZϹ`ۣ`c:S`G7_S?!5y ?I^fI^K^sɋSg7D)|fϽ3|Oyo9rCQ l}6 >g}6[ Y ;Oov2>4\~C.KGr7y$'}IHH}#/="- X֯@p$ɧ\j>ĿYKhf]w6f},Lqv=O>_%,|w#Gn3tm9'ߒϟqY$>qiVl|z1ivS ZsH$IԩܓLe 41}>sX{l|0ָf?D>w{&n?D=<&>x1 }ll_ۻĶ&x<~@vG-W.\20˵W/X5!Gns L>gϥsƧ_ܾK]<%ӯIބ弖JWO]ܛle^~ 蹲'-^$c9|.#ȯB~Iu'r]7$5:ux'2H_~j:Xyx9g(߂8gO  ݇|ztIz$[wR{le7_5>n]E4ψ6K)8eUpKZLL^ge}hpg.7B>;#|r/H>gs5$>'O/&-P??A.K= ',o'}9\8_ luzL_q})YRsZGv8N [c``c':`fdq>/~ɋfku[ 1yib8J^Gm٪٪G>',p59|&fm-ƧV[+Oo;V}n$}~]15jk ޝϧwu XWr',z u{}'贎2U_֬S?N %/!$/ޚUdNpKM^Z!nk^2m>[>[9B|bzĚz||%ZU|b:b:B\\r\u%%}]O&HJ`}_5pZ2iiY*Ҫ ڞڞzN KݦUKKFosOk\x?e&/m= 6oih8mllӝ| /Om#mFw\ \G>cg8b&I \rv/x9ɥϧ%zҗ76.p6=Wj=ZwփڞMCV9k>Vc k|68yp j*Z&/ms0}7 nۦfgn?|| oϵ7'ܶos\K>m3n|z1iQ~\r \@riMI~=X@S } q\6ߚeJk>I5E$:ޣm_-F6u/#&pOkbL~qs~qs=@-ɶ+ۋb]?}lǐ;b[ dl|}״<8ß̒,:π~}(X"ׅ:ǑB} .9X>OI{WCYprd`0܃JlKHNBzwq.D=<\p[H Fn_cyhj]x{|? )."_nosidw?OvI3o7?ojF\5ґg =[y&w{"^ڿ'}IkkIrǦ#0ד>#ᜮe^uoiͿ֞6 uZ- ~BG{q*e(G$_BrEDQDAgS=YDpx}u|&}{޾X{\,=үv|̗RE],OmtOO{]+|:Єt&?ϳGGA>̩rOv{Ȼaד<Lg u־^ud1X׋Ny#i߁}$K&$"]`=/|KG#kkYE9]:K?OH~ʬurOֳ`}`={y\|QoR{ {3u ȩA~9u;"Vsbnjȑ#Uc8.$.A5s Lrvgѹ\#`}n1Ϡ""f/h͠^н)+.?t(X܎ Vӱ)yGovĪc_ws(`nǡd;l'LŞ,&dl{ KD>Ouo| :o%y-M,Xm@|ZKm%VL#vg1vv=LgVqp">n߭mhkZچo n7rY$ ^B夯IG~m#:Fz:uKNӟ6XOQ $V8L&{KYD g1v7tٮ$ d+ߩ򝊈D;0ٞ[CTsz'P`!}I4z2֣]^s?`Gᡅ~>9?obյ3Īk7&V]Xan~+G]5$XN[G]%ۏv%o#nWpo,]7Vu=z = MrkmO7!}]ƃ[|XG.~]I"뼞ֹXwO(aA~qyF~{/_ғ{2t:)`pxd0=?t,3k]75nףs$XnU!)?v&ꃽ37 v*ȣۭ٭3E>aSC =ԀmN>Us#gQ?n7yڋI7mJ{gC=y!8Fo'y6G H_E`?Y?Y?ӗ{Sѡ>kH[GzZOO:O \j讀>/5yIDz~-ůw!M}vc޽r: g=M޻7d޽;vo'y{{ٛ|||#S'طt$jM>ɧ|'.߉Ťs-Nm'S_'|"f=x# %zPZ_oqF_vYkr`31 zΗ&a laoanأdۅl{%Z">nsd;l&[y'1tPo,a3+q: ܘϓ-IޖϧI7OO333E~X[&X{ڷ`i?Qa:7,I}NXB|%Vg_M0v77UEkDekD kDm +N=mJ6\l=~Jl1'zVNȵw\kx7KI_k{t9_\L^w/ӻ#DXA`iq0OX'B|v=1Kb1[bxj 'JJ1d#<>!d{loXw-!=4XzU!G'!sSx=ɵ\'y2kmcMIGײB0}^vfWhov%Dρu.u u70zx:G[Q'Lz#Gv!~&Ubuj! )X+{2c]!G@Q)x8ɵ/'|"km_"yU0GWh=Bѕ|ѿֹ\9JN3[ױ=J>'=|G|.X=}'XaK=ٜlvپ X|Ql=پNSV~k1tɨjF-ɥn3ni>Xۧ7C) 8o,OWѣ˺Lr$&}G:-5l}6zM{d\n9,9Fz_> y~Lzi*~\b%ϧaS|>5l?$d+Oo0!>S6lV~1t=/ ZY$׺ /!rҗ%x=GtݧFi;Xfܧƞ#~ħQMz6F|Lz0 cw{vXw'ۧd+=tXJ6bf h0ZρIu x0ɇ;CI4hzLi}t^P27KN3<[:.g(g^UL0vW kDֶ߭m/?~q{~q{5'0@@ ^ hT:#HI_cI?TUpk 5*kUyDtΎK3&ezdz,e§c`ezt#^ 7X85<<z/Xw솎%}~59nHo޻Bz/ػ D^ݕȣ+|J>[޵4j-HX[ZϾ9)q{oz1=` 5w68:?K>@|I?X2>%VXDm,f.Zgb-lOm ʳG+˵ 9p8ɵ7|kmo&}]7'3bzeu+:s9>;_`G?w8 ;N;@{_.ر傝`c Xk;<}>ؑ3|c͵~۷rUN&}!L~܋ go6xS?`ȣWCݾR9B>;qYL>>U>OC,Ivȵ'\?8Rկs|'.I_0{TwWJZ{RJ l}긼:en[rm}V*k(kdA1u nkoe pe pe 2U~ t~ߛ`u4y79LL3~s#L">iE{53p$ gOc_>OAT!x=uB~+Ǔ X޿1ӯcq{N\zNa>ig%ngonYhl]A6^l b N$l=D{0XV8\\5Dk NY{Rr_I:Q~!GU)G9#[p_Y# ~;^рX ۗMtX 0$zcwXa?3پLc$ &dl[y{>c}Hf5ȥV3%mf 8/{;CH(D={:8ޣ9 yY,s3Xry/׀~;p69: .šhb52N&Vʓ״ ۦdAl{ȶ%b}b Y!G>e-ά.%pNp+hJmgH.7{U=upUgfe.g6˜Xr 灣:w 忷 J%V8Sg֕XXa }d{l#ƶʌ-amհZAѠcp= fdk 7o'y6km?%<~lQWI$>Ifs``Au,!> 2A&+2A %VXG-Xalבm,fvp|=(l) 82R!G!HrPt"}n夿tzT֣jU(XNpu=կcq7B|: nbb5 'j@p7/Xa$VXG8}l-֣dl6Yl N1XV@u=zܖZÃa$'}!ࡤ!,x>Q`СG3tx9t%Y3tS;E'OR6l %Ng.> ]v.>iC|swv4_j31X{#am\|^ /j3J4ۋa7>'|@_}`z~6xaS<ÏfXx*\L:sH6ҹt,:_j!t~K:tZ |t']qD'~w{S?xt6y=g0 XcX\1엀w}?\0>)noؽib+ԝ$dבv!u HE=@"\'K|Y=kk:_/|p;73lR"UE6淃*5co^Lk~ݳa7<[ MVýln{ A0'"^wxKY$+7,2|B. я]zf$6?É'x:ON}nrC7AK5Ư50C`Mk=zX!`="zw1p=={x>ɶ!xßkm>#=!ң5MO:0'Ɇ_nG F GzIOYX{%/BÁ50+K> aκ8/x u94X{_5Wz֋Lt XkvH: Lw~s/dK${ǹΕHh/z:X|:j%T.wR`mK}NϥaNϥvz/y<X\y6t+38yD/$?Ryh~T` 74g>`//*WMg('=>Js%?CBk'pMD,拄vz5ȟ&Aj I a!!4 <AxFHAMLCg$ uϚ_&aT =sC!<jrCs/՜3!܆a?Bsf爎I)i`.}^L❰G[=[%ܕ*b+w(s1nb!|EL&l ɾI"[\ɶ,-1D|zy<_csğF<^:]]r#J, ,U`iSu݋IuH[l5z޳K<[ {7#PGN}I6dEȑ"u(M#م$JdW,2rY>z'8Fta̧Wt zG~3w%ʁw+RЙX2f+ WOC#s3#dd>eb[׳nFl?:Q8QNvTbuȢuv#IVދ (y/e|Y Řh"0+(klc$G1W|ԁQGaga$:h=8 ^̨EOQk[}[=|Hl hb+ԣQIdFo>f%dGv߀ h7^F_rVπ*D׸%įuse2GH˂]|)z6O˳I`K3_Fܳ D/V<[aft 5bl]Iy$[(O,gHvɖ< hynղ:GD׸8įus$ h|m)|d98|dG2{0fMF|Z=C C&], ѳURg<[%yIbnzP#zl '"jz`ͳzHػ#=0nԒI+AdOWdqƜrcwc/uc;yڽ,eD Mįz%ftۑ`;lG{G X`y`#.{1c>{>|jsjpw#nƮ"$[Ln0cʻ:֑$+Æfܲ .tK(O/(p ̰G4vjay7X@b]{1 }(*hVn0n`$;H ʻIwa|/$DwaC,۽$npTYq;8蝉_{?xgHf gs t/&9w{wf_}䝙 Ug+$ {7l3~G?,z_D=CNvENvNv"aM":GK@3(5' ^|{餹+8 uGM*$Os19{1G>K<O^*,[a)_.$9>OlcfCH6$ǁE =L"D=ٖ,m]vk o.&z kl_-oln"Y=N=HQdY Lߛ%Y\I`ͽO}X x?lu217y~`<l]x0ީFc^.˰ 2l&&+Ig|t@:'%:1GO8@:%ίII=Dd9^bէ/!灏8y'x/6NZ#JD \6Z_ pl>jO*>`ׁuoZ>fbwB'>,w`s˝h{_&ڞD[^2qL\)~AnM:=s N#(u>2#ͤ;әrәrDJimqV_>m p$į˜XgUk- X8Ip Λ)@,] +tteM~:߻^}('{}?'{},:k>8H zzr5?>BeO6a`R~0Ɣ&%qwvRdA/&S2C^L.Bb`=ONn{6xƪI΋mĪIޭmϭmEnmrkt[ۤ&=6i[ۤnm&M6i }थ2ZfZ3RZ;&Z'hm?~wk|[em9'_zr/ZZsOA׹l G|k}į ~1`=_k }envg!~,ܠSYAs׷:do#$U|6h~tu>doldo w7jzf{ Xsitԏf`Ğ$`-3^N^ //'܋v~‹pk_zq8+/'>k/'݋7ď[?h ~qkƭan Sn S5L0[Ô8YCYC>P))n Sf655Ak5/k@9吷)ȹ>W%*Z]oD/"~ˈ_zUa#CS<`:_7Mr*Uq0|D&9_mm|D&:_7:/uV"Y|10Ŕjsz>W^ |Ƌ߼Hw/6Rb#sGϋsHʋԙ^ &u05>k}&^:@UK|YEg}Mu}VϚ}(YSga?NKL%UtAtE+.G/=dŕ/Sq8d視( ],E٩XH'`?f+"#_ g!Lpj&e/59 rr!'W\)*e+/t~L:?''IsZiq[щxv99fsN紾sD,MtZL$#jEg%oTDtmDO#~m*?x4 L\|}wm}-wE7`+K^Er{Ž݋:{[q cEWn>دG \Lv0ﰃVI_~K1tZ+A0pW˼_poG_澊z'?0Bw]-sV<(p#ٓN/ǀe8}g~|t{bzg{?!~޹޹.ߗtN%zу\GSD_5rHv"&٠G?QZ׊ΓǐӶy%D/% +чߩ5?}n[]j_b2̒4Á?neC.] , ^7aE72̳2Hضضy[> ^Ht=SwClQ#l=:"J/jZghv3#Lja+I6dccz}<:rD63a,p?.q<Op ɓS%T.}Lw9 ˀ%+kםSםz0v}=LtyCޥ]2̏w=$r]IOsWy.9weVD*yt/K*swS=ݚK/C)`!{eW+_ޠnYg%e3Km,6[_y?~}7C¾zH.{HPG"fl1zQ 4:{_z4NOO= cOyR%QDLt2+U_Nz<[p?ᯞRszw=GZ[_.!z)]k+f̞bwW~{q^aD kŞe^==Z[ڊX7{IŶIzm+* z!ыg =^O4?F[OxϫP P+g}VμHjLtv3ّdo!"{. Qggo!Wxff_ؙ5k9sdǂ'GxF=QxrGI_K])")r9<3;sx.x2䳖z<13sǃ13h=C+<7goF$Ϊ{I ,я]W'9{=A<'R7g9 $ۜv H<ۜv΃HM.%&=B:Mwd{뙝,,,g =poUW{Kl[fED׳\F:Ob }{I=. 6/x` *}Rkl$'N[f>U]uء* }€Y3Cf_K`ޙ'}?F~Cf]}9Kޝy79w3+κdl/=XiCzӉkf.΅\YCG~k}VYc< =>ykg?w:8`[3KۚY.O ]YV zU=|G.Iz Vix9>A<3W#}E>gS?G|m+{hXW #$+l%lFG:hꁣA_gsS䍪L`?Zznn.$#y+pHU$~{׻)~}_r=Ǫ+Лݯq9pћ/y =)ģX{J*`k^@B]'j%DWW_Xy4Ԏ*$&0>=Ѝ?υ?k\ Y$ҩvC~@S5X8.]3kf19Q0r#%>{1~\~u?}N6"'~M 'c~G5wz:q~Mz7;¹0rwsaUG#.wGIᑻ=`?wlk5);jlng 眕3Qs8]T!mxO8H}B^ S_=KUX2Ҿ`znWΗ}I_}n,>7 LMs~ܤ_&s~NO$CM^`}n"%NB&iό=7y ^Ht_S.&z K ذֲ[;z6D'`gޟb2Unq_vng' >g~m5fbVD/ z!L] 6}n@I5 1 U}Z`Qe5NޓAn7 rI?A?;82 ٗk<:rӉ\mfGǞ “|+x]$-t}s3xl,? y $1cf}DOϚ'sGɣQzn>7A~xT穿Y+; !IM&sscTz0i/cC1s=&ZXzjdQ5f:KmXjkuX_}'FR}30=7t1Fri-?Tc97smR/sKL3&YK՘"zgk ,au/` ?' 3oΆu68(1VyD/ z!ыx KZ[1>.6F*#>6> Dz>7A>@c;ܟ1DڊyvVbFs hm$bbz ؏\0~5WmuvvH0woVJ]Av3[~Wid;9W,9c윛<:rD6sn_K͚#߃@6s{f]IyB/fN_/ks r#_̜X<i(3g$x b̑/3g2G b̙K%_u9YUgQ/H pGygmI>?0 '@Dw" GdocV$9 5K1Κk%DKoPZ9H{6Yg,6Hc im>Hs,f'|Nמw'y< ɥƜDfl6js5 H}7a#5ڊ0?ґx"'@$Z0z!3kk-'!r#' yۮ-"/:3R k ˈ"~˅_[Xmp3Ɋk%h/ ?&1Ac K'НUY%h,}KM1pOKw轩zo*A^O0oԠwp$lMF|d;/62mÌ1xZ〟|73c:]o/)t';I^GU3\M:F:$%8$'fġ |ޯY!q5>k~GYoq5g͏u5_ Ύ/v(l>( Jt[̉z=_8G/QK.FyD,93(SFi\ָ55g$)k/?:RGG3ѵo^FwszFM0qzaD/$_YR EY>aJouDޞ&'_Jf |mL:&?: u:\t.ZtZkDt.\Їt>N:GΉOɂIR_O{?#3ѯD7n߃x׵XC$I'Ix=XzV۵K?V{!0݋Yv<`;"?, *6P~{7 7owd$Ȣv/"tlf(QW,y#Zԩ$0֢.$5˳pSx^w]#GmZԾ1Rk^;S@b2{G[|_lm/.{{dʽ=n2*Jϊl3pEol5~ ǁ?d[H}q 蒯jDU _z눿xCF ?kox Ԡ.}y s;yZx)jyZ({7 `fad<߁}By#Iv:.$YdY(eYv:r?_ALA{Z̭ceޯOESL<%SJ< `˵{lv>|{;qk{w ~Qk{qK#fiNF̌\{/>jj^~s%m<öw蒗l/=N{ ֎'M$z&k9*8_N!CjuCIV0X+= =d= +~i_jD: ۸d% 2^|a׹5Y~KD\pGGL ݈_z-8F =@XZ_{H{ &=$D`L{IZk]xX`=Iz8,g 0zE]h bc/J.br49{&1#/Z aWG]Y)H뤳t~H:?%(b,wDf ӹ8\|ӹFs|qew(Mw]Em]jbmp c_Hp2kMN%~)]v>/@|Nq;$Osq;%DS]N)!)]):_C?Us_]ܦFM3 0z8vJ/ς$^-Zu?_XdYϑtt~A:#:cOXs::`'33(yW&(yM=ϊ[15ID 8p.k/Hs-0F*WJդJ~ }7>TzfjJL3o`=k{)'9Lugyw08So|gOq\,~ xLo3D:#GIqyJtO(:'t.it.\p:tu:A{=&K#3>4Z]g߁;#Zw%~Pwpo|0ӨF=4%si!6M[][`outg2=.y{p]8ߺ`9uȽs`>Y2 >=),w mA_9]Ŀ/{̒W<_fɫt~D:E:#kD|mt.\zӹfsiws;81KQk}uWjٯ8DAty3}g`yXk['~Z[;6D#z8#ށ1?Kk cZx0+x#1ܟlW.+o}+]_br^L"^L"ʁ N%敻=v_+' N'ŵYēMtQZ/5&`Kn4|w}1 )b~Ag{]/v1@Q"{Tql֙g|V{̡BX ODk7T=D$z1υsQx0+Xʏ$&DUKL/&֋싁뼘̾ދ웽D[$&3gg?FI6X5R󟁮}9_D?F>M }W [;مǁuC\-wW Bo56N%Y_H ֟֜۟/0/ XDw$/]].8˼VXUHO;؋#/޵}K<#o/FZP;UEo^zwo%|Ϧ~J-ߟ<_fio NvNjt\}ӹZ~{6k~9t!I)817WMVs_zSDV[;k;Z/Qּyw~j,QļZAÂcgwXPraAi h 'HY,{lX[]"1oً^K\l:7K}WyM`_=꿃n HτjLѬ9k.q:D:knu:t:ovffbyt'Ig: NaFwɚu껃9 }I!ѕnbzcK_uS"Yzk%.>p6rR{X]D3KS].p4R[^J,[s[-K~RzeO0ֹoYF,[; Bn˨,Ӝ0|V{-KscD zg,=w8kYr7hZ͒sg,ocf B}~ac$!nk~O//sNj9İɑ MN'Y9>+'}VN}Y䳊g6gg@u>>#o4{em/,{BÀK4x?ˈ_c{p"=..3\p`= т%꓀1|н?`'Y<سk`8϶k;lV~#{7k7wƐl>fn0c֦|&Y[ Z[{Y߹]k.fAg]`'1//&}ijxʈ'D<1/U? XkY{cG=@nD\yyX{<`oN#jp [QmXXg1=+)nW 5n}= ܛDzԔRwQkVEko`X^ ~xfڣ>'| X:[e/;=qG&ܓ=~,>ǜ-{:[IlY;C^gmΖ_X,U>pUӿӿӿ*_'A`3]*Hs?3DluuJ_}!*ּZ=[wj}G>]u|p[\եnͫ5rk^}ȭyQܚׄ5ּ[5k+5WZg#nk4D9zNo=Z`iS(X.#:o"f^W`ko6ZWw}7 uX]t Vd֞q:uW8u׉l౿em¬D7뺂Gv 7u=:N{=zk\7 AD5`X+ߟxb'xGE%KnX[%D3pC GKT]ZK\vNWfu::;ӽ`_'gf`}?`GJIO3Xuu$)G_/IFOG<^;zq6^lY/{gi ܋^}7 :%I)/>j="s]{p$V;Lb6z =||S=ʥzK(7K(Q.գ\Gm=ܾGmz,1ـsգ T6P=@hգ T6P=@h#գT6R=Hgj#zL]6؛,lQcD?NDs4dB&YbLL]P6i6iBڤ߅DtO)ǟ牝fwDМo֥Flߍn`Ըu+mѦѶ< m/HzaֽHHdl>Yi~}llA2x̺Gދ['6wf7z@̋!z,ѓ,mx8ēE<ēCXhfjN7]hijiQ)G8 D&wH6$*\{|/{o."%Uģ~l*f|Wk̛tݏm.6zq9ˁ560mvvF"nw}Im.6zqEܮuvꥷ{齂l`I̞SݚmrkޞMnۏ5o?ּ#ڭyG?n;ݚw5,ya=p[n;}[*pHT4,z(y*X&*:nD?\pҭygo1n;ݚw5,uk޹ϭygȭyֈ-rА?)jDgZ?%zѓIzO_}2D&!ذ='ѷ^Ŭ=w F/}Ў^k}," < (}-I^>Ǭ,}Q, $Ad7;^ ,W}Yx Ab֗NW7<~ǃaֿ OEO]_5a^wsSG=@tKnlLOqO<ēD<gK4وIj`UUDs׸XjAc_f#~RO_(azFpdp qBp uK.jlUN$[@1cD/Txvzn< ,1X܃ޟ1D%z<ѓzi{8Xr]cp &sF^1 8DW@3j:b}FVg9a1?#3za;?#u3U''I6NNlqp6ll"O!_)fgH6/&בä_WcXϯ>Nt=EmO`u'`=z~ti<L=XݽKs#jS5lRD6)"M&Ed"I>w{ԟӽܮh]1nͻ4 3p[[B]~y3ּ+ּK]>z'59kMs7I[5v֘Ěw6XnWĚwkޭuXn=Xn]]i=>={?C͇Klּ'ͭyO[|=En{Jݚ5rks|ڭT1=@ZVn\_,mU,1Ј臈~zƟ[ؤX;`?Ln&x͕cQMչ fVc6F$;dD^6$;NOjaYxLj_{ ɽ4Hx/{ͥQD{㏁5 Xk?g\} ^̆uϻ6~OlbZņ:z~C?,f Y ?9ٍm+E8p{xY>B*<\Dt}p֚oi*9| >'þn ^Ƒ瞏6NBle1jV[<[afVr|}d(s=c6֐dd[r,oD3pYįW<'.v>z|wG,E9MKmj zǀl >?y>t;iV>ri𯞭6lMVIv.&5"YMkI)}dl.GtMD#~EMğB<5] |"=yEC"<6],gJf^<}t/fEG_*/G%_ 84]IK.jR7A<2_4a|IgR%cyX^> Krn3؄y%ɽMw# ^LAZGyM׉>}[Aluڳn~l_0'J'FE&YEH?Ɖl^6dk^X |w^:F/ybB1vwEKif,T}zNN)=)g:L3RzSJt^9yyy9(kXc/=>+XGolPKkfBMͅC43 uNk6,>g_Iq?sKksKӹE'blI0[q:tu:G:cHgGܾQ.n_MWfj[[6g5%kOwWqOr0rږٲvSK<4{8[l.(.ߧ5zӹ2sNV U~avq:O:Αs92[Xl{V܎]m2p?k!z,kLڷLN%~ɦ).i X"4R%ޚq}'N߳{^܈}qr|yMkt`>Zkf=0uBܾgy.p |P8/n,P _x _>Q?)z^ktw:v:ttXs~?щ-A9t'Hb):Knm[8s23$~Ms?x4O.֘D N1:K5oh gMkCt/&gFb>bo;ػɗc&g'fD6F|&I` -Γ{6^n?w%17ѣ_sFX#6k탏:>zC-ZkKӴXS݋ٶYh[zn'WlxJ?nͶ =L7,m'VNv{.lhK/d K?|{O]"MN~Ż;8=;l$k<7_ׅ ,nzX4 } X[ gMMS;&fcxbdعHl>]}?>mv_پtηHgZ7||V@lvlw051^Bb@~2;./{t΂NgAY c _7-.ٟt%ɤ3tfN˳imRHP'?OtO; \E:܂,[o?>Nzw#8.ḥw=WNT Y ֻ_}0i&=Z $XsI`?,M./ ^ ;*_{VW/S Z)tttU:HgK:Hg&M<&;WKjyt~%_D F#;0g[V|]|]qûv~|mt皀|v;zu}~{K{)_ {7;+aquq^[*iT4E (BL!--mBlM)E.AH;+ jߦ~>:sy9yy>3ԈI/a-eʦvE.ʢ&O(a_N63γ W]Ce-}{Yyrs}}9з~ε3e\ 3_e]\)j/Fa!PVпvj !pڙwkaCޭ݂"Id)a e_|X*;EhDYg4,2 ˺7g$ kY:kB,[n%IĽ{  c_axvf_\u0ӬfÿX-zJDOe}md"tR}Be fu?pfl ? ci7>q/C>(p/t4͑|;g_W0g_W0%H,%ԃT|#zrEϏmaL`_3ؿ'Iigq֔vKkƽsJ:떬3~ÀZx,<,Jձ c)F[#V3RDO=88 ڡʰ:LDŽ^ t w/CfŸ#_nwwbU?Wr+h`gkd=  @\=dc02'0PY%zygI[I=1Ug)=?38 v><\Siζ3;8m|Z^>(Zg5>uSuq5Xkɱ_K%c'_[m5uI=R}ͺ.U`[H76׀g53qa3_ }:YBÆ̗iWD !L?D9ȮDuEl\?͞AmB&`~Yo1==`y<F|Aw-oO|b쿑GfDm.̓G~#լa7C[ͺV m";Dd,Y#);w"N)E>Pe;l} ͥ=nu$~bo[lxȚOA~zˁm] )"{~kn՜^5~;6YZ ^/+Y_ >zֻQs0 <~sϬ?ЗnC_tn_+ɻaw;D /s&:?'G_&}\az\"t[W Z-:]88;yG;yG;@Vs|`mV1$kn|T}-цG`ٍm8 sf6a쳽vٛ)[| e/̾Ud"4ew~&us={_Ye[_yB>:B_--P~~+Q7~g~ uwUb ;|~o5|-ǶQ";NdہmA^Y>&z*DgM$~=$&7HLn l1xÆGrɥ/-6_뀱~6j1/獳oUc;`.v"?vKof9R.k`5X09o͹֜ko͹֜{oyD~)9[QsFo"5I~}[K}9>ζsX>91IoY]{Yv:!0c> `Uv#`cٍN[v3`ynq,Hv0&?7 ckc$FaL~<qnǼ >X-<yv[ s--ٯD6[d(;Un=e?9?Y'N=tuc#ٍ<=Tz羖pg᷽YϚ0$lUlۣalo6$.d3mXvmg!\+cr"~ 9ls| bO#0&]?O/G'øC~ |LO;'cAO /g;=| ?KtND73:6WѹWt:?mu~sO)M>m cZ趖^18) $'pOx Cy0 _t2屷? 6ްOjO~5O> mDڍwW0S]܃O"SD?"n"fs)M :' }stO#<[mO,wTbҷƤoY~ km0VCrrH.2B}?n;R6'R6?~ 'OΗDD9EtNNK?I%sѹQt_s2NgU!AO$^ E趖z/g d/ 2yV"&xȳx^̳><58K,h} t}I 8ۂ~0`A łEQ}Zd_DYG/G̦,`orȗW\#t_ GV|VmOά|ϷFTS|7C_.s.[}_"c|9[(ܵ lnS!IC CeG|KU%p>=W߄^}^ `!/z o:%:9:Q/-|:뀟 ?9Wt.u"~+B& W&n=5|]&t[% DMOp[ox(PP'`ٛFZ*js ^8OIhE,ۢv0`c"{$}(gQ_.'(G e\xzi:pN si _?'XQd-"۟Q),pœn3/: r}s-\/iKKfߑs-pK/[b1pp]}+wi7[ XJ$Md;澓s30된[mwc]20j w d5a?ٜ k$ؽ8~A$~sa\Q]RBOswzu' u@`yףT(w=Jm]ȹܳrc^Dm.w`B_/܇6\ On mK7܃"YW>RW>ң^vY^vY[/,JY5., Jm\!Jۺ~[F)k#oc+'%wy x[̽\zr˹7:`^vZBhwmcE/VҏB3W}$S6r,(=~痁nDW1UVޫ-<r"ϱκHGɕX_.Z=lדx>0zEW.{#uѲpU|DvȮٯ(k8{uub]9]T|,s"s1\gXͿt˫_q-`~o:(#\6Τ\E[U>ٴ>mu",? s+Zyxw``EEd!޽b(e1G3? x-W*z[lo~s ?suNu$~W6'zmv`[ȇ~]ܜB m]l_`l1n,6KY͕`n`ʦw+^YɘtyA`âf`Õa\pgw!| t-J@ Dk`/׹׹2\\y)u_Xٙ:K/:W$:·D9^Pʱ BsOd=8tO['dݍA;B`ǂHٕ"fSb__Dv]*0Xw3a :#Bg=E]}Aao> <@ͧ~3_~{/\GY_b\y?wty1rWN ί6G}'>2<+e>^_ϮOqAп= }+|3~~ >DD<ѹRt~%:Y#X#rDϢs\ݚ:{ u:><{t N_ǞzZ~ #Uv'~P%{VY<dl0KE1U0s6`=3W?<&gagC~yڍϘ{Ϙ{zWd,>j>}+E{-Y a5C\~M:LB&tWY?N “)<1)֙9O2j-#|tE<lwI";Ud9 -vg Ė"[)5^vC՞Y~j=V˥?o=U۞ㅇy)68Ej1V_l 9N$~׼ YC]B?`$? :}p700k3^qB TO:0x-f=^{Sl9ρDY?6BilςwT=\=HuK`ۿ;W[+8AVoQ[77t$n3057 |cMgDψ`'Ӏ}^dHC5ns|=XܸqXy y5SCNӖ'-䁏53C(X3 <]z:w³6m538]QO̓5|| ߻it̀}Йsr3v.*+<+sQ{ogoz{;k쫀vrv;oAn5\ x%"k<="[ew4;Fnf ̜{0s~ kgǰvLX;,`HYwH_ 7~ot?-vr1Y;<lj-0@I[K& wX[D0`ˍwN4Ozi ; jB;Wswm̼{q$?/*t˟Wx) l/rdљ18Y*:`*V`!KMQ[I{ȱk#Ǯ=ؽOH<+nڛ[b>A]f/CE#kGj!=X;6Թ_ϵf`-0ckvy-䁏 y`k ¶Z9msdY?9 r#= B諅.t'a4z[1X^]l#{WsQ>v),;۞ls'`vB{M[UU\`׮֢(e1r캆F\|gA\w>/F\"?]`"{)(~|}qsBZұރu:ރuy?uXGg;.7|]n(X7< OH!㽟{A ~{.OY5>tj3g~!BpXH /W < y5]$;WsQzG 'j˃cg;7N/`V3,: y2䁏B(HC#j? O*yJԥo{M[İysljŃD5C\y zg.C_s(*~F?B4*`ajC7s Gb5aۧvO~?ly3>lgkqXZ,6_Շ#G 2y> 2EO)=D0D7.\SY HGj߃3Ӄ߃,~O~Dbg۬ 5e߰[+7=SKVW>5Q˫E}}1/ { }й_8f{`ַy1xZKy1y^yՙfY\;n;!Nq`ysF>1g[_ xQd B- c/Qb^K#5mKa=a(pȦ;l}q`K\$D%>=.0o~z[3 ̜pl=)'zS\OGo~=\;pg?S.)y0'KxJ%<&]W}%r "'!;?03/f/zWyvcFMg`B {j+ +W y,?X;Zs40?^ %DsiǾOfN˿xN"kyR`Gp5pBC_'4L\#W6oMh8ۿ(oT_'1444\ lssvDΰV)tCS}x2?l~lxm5gICfO$4\1;Ϳki5}>@胅.~od~ L;Hh,?5FYAI|/q{)|cty]"{nO? =7u; u; u{zOn g}ȃ r:< |L1g,q}zε~y_ O<rz ϽA-3<{.j O=X rgygO!i<5׋yF's0M-Vs@P\"t\*W :8B7\] ψ{ ЄƶZl^ưAP c5^lso5f3p[M,Wc=6cc&.^EX#sµ2A QvCnc X_;j^g3vunt?u-:ψ?η"N$Q34I%,t:xЧ ?c _"<[3|<4g gZ<cp"13-yM\ױmVا6<#[n$67ml"{ert"{Y%0e^rs~c'[=Y-@Дk5CSW=D8ø-hX-f|3G ܷca~|~\߹}' &u[ |5/Vѿss#^g^c3l33rwu&w:nDâwLm W:X~^<<:Oo͸ Ya/@̞e͒[c|`@f Л4cwh7.js >N:o9ᷩ-O>p@nmyAEoe[P8>}/IdޣaߋK.=E s/.)s_.@oҬJ +5~k9|BsL*&М~,L?\ ;E`汸3/ 309x_[hι@-%j~ _Dl\g߁`+#@RЯԯρ??/7ENy,huNWgS'FAkbYp(:~BM -ۂ@gYxͿwDmoZkb/Ivvv?`f]p?0z%( `&r}9+;iϰOts i+Ydq:;Q5m /[e Quo塬K-nD23 OtO#D-= Z-^j/{/lN p"r `R`ġ~hKYYZX?>T^þӂ{%(Eg|g|[?x9#-ƞf)p`˙Qh`Ԩ]无qsy`WkwY. V'+xUDg":|:QW:ZyE΢+΢΢;f]Ng>-f1[8]oz~:B+?q   6q}{bj¢QKPgLׁ O> mEi+EkDvȖ"/m,R6=eŭ)}8|o~.&t2oOz*k>Y-<]ӄ7{L v|dgGVI/olT.B*t{=$t7 >ܨ!(3oIGöinuAA=y_BÆA_isU^O;^OU.$E]Hd3D6[d(Q~~^U+X 훫 je* *,.kxr~ꄵ$[[zZY\+9ke `W' (t[ɳV򬡕_[ EW\ 5[Zør0o ?wKQmA tK`?#'o lB*z=ED3z[ަwDlѳL|!z6RD`V1~=iaC`vkQg*zlMY6)l1^I8kj`fQWp}mMvّgۆc oKg3HabD:r)t+!τ^nv,]x-X'<žv6?7\˽37[[+pBV_&׋EQ;us;`P^BO.|9H+j1/s9_re `]lk' `C^"tC^/<<lk0pLdm6`:Ir`[Ow{ $9Dv`!GP\\Q)B*4ӿEi"{d}3.~^#zG5F]Q۳߉O,R_T=[.^繽3W"/?Q7)gӀwRHT奠(dz7 y!b2Dxll!R5x\F O ƂJ+2< y/lRxz3 Fy[O/b)s O<+XxD] l;`E]AZ(BMqE:& =EPgv'E9;NTbԜ匨(w6:#Т}+Î #'$ބuhG>L} 0CbChCӻi7O1`.=ew;"GlG6+E&Cٶ})w"x.W^VO> z*J~0EÁY'=|Pd-6$\(ͅwÅ ";^d'5Å\E.|}ֻ |e v_E 7a+nSjA <%s\ۃKƀ/=h R`E+-/wd' :{ר7=6n}E= |x?+-D{Ȯ",ݹ*/')T('b>t;xЭzLJ_;`kwܵT]D-_lH[Ѻ{uX3_[(CRݺ1nufMnu9ɏ5-7n=1b,qnuܬ(kpO%"=w}:#R"wxW`/={&3PyCt E:̧N7S(:C^3ν ^^w 3g~wtrB/x, 6.k/k#ُi~WW1_}Џks~]1wMc:ʏ+P0~i~]u]uW1w]ܭsD?ncc&ĻnrP*ޏs ?nBc׏^~ cf5;3k2>D~cԏ{[1w}s~1wܽ{sw9ao'`(p?~l=z1)^~=1cs~=1_ԏZprIės+ -`/P_˼jkK^%Bzum(.B)Bq lW`ߙIbDr쾗HOR{9ըق}Hs 'I[x{Ko 5?#6#.g qc/ 2#/Ge}A:r/ "Ϧ O y,iϷgWKooK'Bg=V{Gɕ璫sJ(AOwP7p-vh=>nQ:F=0ՍVs~":ۍuK'ۺx.٭5p.}S繩Xlg[Y_^.<>G"%1| 1b@kKØ<9W12Nw[ '5RrM{3upF'3<)ΧΧ?@K#t }36JO)^2 8Mv?1vKZIeqFmx(U=$B+BgMUr})jv uɁ?W`<ؽ<7%`)~= -w|A^=xsE =C488t=w%3@8 <^n0c4_ )Ex%D|)z;,†wș1S!z$fOZ7}Qz.0}Q:{=}Г+yEqB/B7?5#j4848)R꾍b5b5z_d?٥"btlpy 3<<.ł]|8I@gWg ޶v{w6E~e]^O#/'_cI=cD%//| ؞C!жyD*۳J`{\ڷ D/۷A";XCEvȎI";YSDv. ]/ "[ b"[zth} .Bg}R`~#EO,z~KxFlj~[~_~,8GϞV*&3UZS[ca{9=/#g1/coKҗ1- Nc;*~wc;Տn1m6c[-9a3aX؞b{1$t'< ŏyy@@ <0Ώy`@1|ch_-nj?{1[ ?{uc?ͿԍF-9xAwcQc7CP[c- N{~y w NzwzQ 6n, O4\eg78CT/XA?-Cb[`2\2}*t, yA1b 9A2h2Gw{D̷eYpK$F=C6߽QBl1v| |xgZ[=!Ϲ3aoz[ f/klk|`+d -3Crv3_lm9DF܅bϥ6CN2M=qٕ"WdPteW+О^Py64T 5^l~X gCCP-^,φʳlan,ra-?/cxxxxXawK< x&0.`>$I< xfa 0aX<lp/#H<<"m>(ol1`+yzrӓn{ğGY=ι7v5IfpMR8ӎN;ZHHg@w oZ%8 QGٛD(`l eoFZ@y<uHp!qM~97GP7}OّIxrób_c ,+'kKY֖؛#-˶%kKGԖ؃B֖؛#-rEmY6sgm Lv9𜹞sf#łK9l)[Qؗ-ك^vxgmVzc8xy"pW?ὼrΚpؗOY> jFS .^j5|U11-c!cX cX#cNƐ'cIưCob F+`P[pѶ~ G/c8z[pt'N8{ptl8磣/ /҈o^ t[=W =]{O+~+Q =&`^Q#=X-GA-gRqJR ̺Oq)ǥHb6Ab6A"}\J=Ǎ`_Sgp?#9yN4Bgv?#9шTѓ&z|{r?#Xw?,ωFșr&8m[qڶ|<'zx Q1Qnv:%R55R Ep#q~54^Z~ ӟx'?FxX?l=b CSp?cd 1] |g2o8187S ' rTO~;^ ŀL&xZOW,[F{=\GEKhy`G0gʀ=r/hG0Z#uT#$j-`fV@V.NTcwOpa%: :JسNR'SwELѹHtQtC&6qhߚ+~, E<*S轄?xx_?-O'O[< >lQL뇨%8v}}0z^oG}Eaȅ0vhQNd{ :}uEv^d?`v8̥]$7G!h\#tN ?!n?ck0tl 0*8dT ,eg^3k)0}]x.",`C'#<#;$z=c Qg1";^d+Z0Fj1RW=" ϲ鋊fN.&_Z @\v/W'ccRVN50gk"*\ 2 ҮAsd 0#5[ jpwjp州o?ߪ#[X~k[uX l ٶAf2V+'w tI%C,rR`UeD6J>;oʝgYW\z+p}.eYu^5#+z~+fMRq=0rMTm`hf /`e`0Q^T斺(yIBRQg !:$!y-/ZrC[~ݿܩX} sxS~nW{8zqX?͋q8 d2/$Ob-?@~ٯ8b?\ϳoƭA}4 5b 8'\j$8)dGZ:xOm'ε`IZC">5y5`YSrkkt*ܿcocl4蘸 b4/`y7 /%:@.㏚0w[m0l>F6%mdS_/ny '_<3s`UVA~~m=@TK? t`}9"Uck:nȿw3wfsBրNY'I j C6&Aylam6PSnPkkm66^im6F6y6͘4'q0r"p5u h:VA- VA5R[bA}xP!Ԙ_^ ^Jmi x2p'"t-x*q1yHs`σ' 8 ,\Ky=/Gd[YL6OKf#fv7ۨ٨٨hhټ޳8qͳiƤ?Fzr6oH#%,o &o!_9i)V>-^k殏ZK5ֵS!paRk? ֜9X _>ya·` X|2M|2m;ɥ>7߼L:W Xe|2]G3<{̣r\\wz۟m? yt$χl?^e0}&aݛ8.|ዶ浚 |oDG~>lG#G; 3?33I`9#s"m?gm?g~mx <+}+k] Mytޣޣn|כI1>L^o2JpIo3g>Ϥff>\nϢoRfz{Y~/}E`<כy^!ϳ{ϳ'>Ϧs׳ƛM5lէrO>Ϧfz{'lg>ϡ>Yn<כy9h~ w09P~0˨R~Ka.凹R~m<\zv77h;>ϋ}ogz>g}c>8GSy~dZ 8x)o3m/"RmmW>/1A>/8w 軃҇`y klPT?,ȱ}^HBRpLld!=Y(}kyα}^xm 煹$D}^(y H}^y}Y$} ˼C?}^Tm8yq(#lG>/dxl;t}1u_"}Cȼk}^c$yIɓm>/Ye$yI%նϏyBm}~L,"/,kh^+Ī1]S$(~ǒ<$G$Li$$r!o'y68Ƀ$?IZ+<}<$O"y*ǒ|%V\Tt6z{mN~Qܟه'ͳ/;>\m_p[lr?ǽ+`?;PD!`Ukfoodb |3>l /8W>M6{+vͼ\ ~l~n 0Zכ`M_S1 Gf`,d؜% 6{y> 6^̉`˼_}*{s7ЇB[> ]g}Q>OB> -> =m}XY> K> c}vQ]GaZ͵> [f}Qz룰޵> (k룰룰Ga筏Y> oG[xG$aG㬏o> b}>(|QsGwZ> ?f}^`}~(QG㬏>j<7Z5GgY5~3Go>jQO>j\(>2}(m[5(QD3룈G="ZE>(_GYE,>x("(bQG[EZETXEX5qDX5>j>jh}$IQGM>j&,>jQg|h xQw>jQQSGM.Z5 >je}ԴQ$룦íGMZ5g}tQuGM7[5c}tQϭ`}Դi룦|aGGG^G#h##ߝ\$G0_+\޼'HKr{Ɓ.ʻ|/ :"2?DKy볯 /ng 0&4 Rm"Xjż;YoZ1=8tt:2:cX>〺 ŁcE'`wEm"vE"M%zHm̊fE1Yq"Qj{Ҙ++_bۮu+iLV&Q[zѭL4&+P۩$Fm3-Jz!BmYJ6Hrz~ڶ]Ec*Ҷ]EvU<1YEVUm1Y.%9=_Ҙʦ9$?@mQ[U5Զmۧ}GK䍧d88wt}t}د6?ޔK[>]ͺ|ږR3V.C&yN_sb-sxkYr_ g [SI˛$$}o[Uttm}L u)f]{Jצm`cv>[ ~li@'`L{Sj>j?$op_2VwQv1}Jڢ?-mQS۝V` ]Sa,.<䒟O"dҗ|x6KHkߩxZ=G`pm y΍5W`;/I`f(>" Yl`>|,/6$L6Ǒ[#dsD7[$61ߛ-&ϓ ds'lyiĉLK1ivߏև/Zyt7|JZkZp ǒ `:ﴚjTu| 2X6x;ދ4wưsm6m+ܻۼ;Dm7xm1>nmx>BmCKŒ+ov>H:\I_jҗ54? ,~w|:>뷾{=Kg7Yg}ֳ>Ye^rųGISk<'uQ~+a~Xb/KM<c$6ߘnO2|30?7a07_׊ϋ6[DX-X-X-X-Jn "llN6ds,/l1i䯹"ď#?7wr~N/InϏӷ{_ծyK/?/=kg kߒpo`<;8u5[]N] ƭ`3D Z;8'mqJsWk'ډlkDJ^xL?#_t-\|싟?D$2؛?_MNDgMYJ::Qo0ɰ>]53ؘ̟8| -`p}‹ z/ Q ɶ iV% vͤ˩6Q-=Nmw_5~Epmb @m'Q[QxXhc"G|;鋿5k u >JuM>E}x{D^1`Y'yI*ヱziٱzI^ ^njCAZcԇuݴ>}XeVeZZڽVOY;grvO6'ss#{ `Unr|۟u!??m֥KY7g۟umMYq~3Xײ[k?k?h^ RNRhoeeͷſwm^Nyy?/Oyyˋl^o ^^NYCymtĿ:7Z=1$~@:#ώ/+ʳbHDtg|)HGI?t|NL:FN0Z.OPDޏ:Tȗ8^]!#5)#5>Om_ۥ-j1`{6o曀3oc-v#eYw 5#eO"֙SI>u=xUzjWu ,:__87`"{q#+1}e(9{-[;Dx-;x{w[vBٲGmQ[ 㶔o0>nq~j;Kڢ.m9kk{ʘM<N"y2>+ |~zE)\^|һ.5YOKz^C_wys9kL`O|5}fqx-Kkco qh nw"-z{ چL :˵kmXa_ n9p5gn@cmq7Zn/1!N7-ΏN{Őj_y2 |./‹aĤ*Tb8f*^UV~Zk^-tZIr-c,RֳtZZѵ>ka:]ˌmܬkuY #Iq{KKP'KT4j+cA0=}]&bu1͂vA#0~=Nm~ > <lDkk O 0ސyQ,x5۪ ~ËV<.z~l l~k |u^NF끞/u_m=l^G6'{t9_lƂM׭gzlG6%'nkC3&%eX%A.y7v|/ſW.*% 9I:դSC:F Wn?uHz#kFݨ)Ӎ:7Ό+Tt|&,t0nOnjOcK|@נ퐧 'k̿֘/x/"tVaXAߔu7% x3({Ky -ɇ1vEk[V2X! <.̗W փ9[tjs٢1:X/g{P'o~ydKMͼE|g-`5$ڸ{-[HGqx7z{E[|羰Gke+qJy8`5V=ujS½o3E#l|'z'z[`X׎`ɱ+3X)Xא|-7\ߦoy3cokuZ:(5 |r;&~ 6gcǐCYq|Ye*%WI>gj[k۶id۶i&mo:O"n'6OCё<\'ԭqm^*6si=__n<_nWd3lL6Y6|P66֦6֦;l؛W{6͘c~9rck ]A%'+HtjIX%?\~ ~ !xe "'ĞnH.1X 6KlvHmĞwa``8X{:&` r鎠0֎%t-7wZւl 5eg͠w w꽷Z`Md g;e `)&Bl]v].svQKj 2d bo]AjKn7e51tkgx#[ `əA1ww\C-TX,1SX\Ars!ṃBB۞HK,Dl쑚#1S8ٓJrBna`EG?8S88quX@ε !`!,ꃎpv=r#cLk'Nx(C:Xw&:CzGԢk96VضK=}ooqdG{`Yǃ73Zjjmb[;{eo: Jm=^zϻWvOx^:a/^;'P\O⡰+X bxg!bu1o e")D쓹P۷2慈}2׃e- B>ɽ}A$V#]usf/S<xy{XjtΗ k>y!<xXxx LP<|XaX7:5kM=$?IZ8c졂[}'y$cI/Xie02ٳ?͞}2uMݕw٧虜Rϩ i{t%-lbeJtNxo3 |:?|}H~vcbgE7tP}j<7ISXOtisis]yΞj<7Z΍NK#:Eq${}3mS=}Fg(tL+:Fљ :#E&Y Yt6o8ѹKtw|=:7>3/7Z~k=c9\p{:m7zt :?İ#z1_jZb4GsCYw EY-$_E p7KX,ym^wX`]1>=.6Z{e(Ğ MrK{`:ۖC wC9ITj!Xp {眣dzcǷjضm3KR?a?=KO#``z_ޗe~ }1pG#z_/Hcw`:jj|89RNZ;S<|LO`|0S<|Px)>xc5Rw`_&7yFg:şɫ%֩蟐7MnouꞧE~۩{Sl~* 1:6kXpWYccM`M15`!E l~s(_`'b܅&AW>,}y9>'o矩l6}n}n-}^>}nmsѶmo}n{s۩m>}m_>o>>>LO|r#~'ʻm}9 (FrH8'}YڀRQk}EQVNQ OhO$Ɗڂ%ƊځmimERcł\ӧm~vK?:u^,c غRp] u{ƢHZznXue֞?__M|mtӵ>k}IʥkUҵ~׊gDT׊`^+vVlVxV]k\ kA}޵GbXou\j ɥ+ !ZKr|YGQoO·T'CE_ҘOk$% k<~+־ v|zn*swz:w݆q!c } {K{o<1>n Ob ;?ZkNb1Ra(h48sSIFF'Ei`E#j0=<| ;,1`]>Jm+mmeׂYSu`7v>Hv47 ,C?'- %|+:nP.t09gS7;ø͵&礉M10;Aa#_F6גdBlbӴ=F6d1)67:l1gk2 ^dq:b$y ߋjI_Ɲ#  mh{;BgƎh x}zvz><(Ό3cG:3vTjȢnNN F:v4qaGwxh;8oG8K+q%/2ln&͏Ȧ!|v8ݎfl^6;Z$'n'C3&7Ayi)xu/"IGXE5d_e,o -OѠs``:9|!+Z+k~F|~Ivs\3`ςuξֵyp-/ZBr?5 OM{~t; f0ºi48ӋN 6{i2x?I/g< E#(ɏ<O§1؋^L~ЋE]d{C?K%~ #FǴ]M6 fD}8NvjkkeY 2W3nQR<\^WW+$2{O؜kEMuY{ËIĘy1.AtIVV{.~V\ .쵺2^{.7ҵk/:ew-3]Z}ȕ7:H.9{%Nz&M:9#T,Tג?G8o$拱F`XZWo pT[I$O&懭`К )68Kx;·|CgX3`v::0׎GX;q]3 ֹ{$$"K~(;XcvtXXVF%7} :V LgKs}ҹo/ŭrmԖ}K`4}K;Ok~k~X*'H>r~'`[H$0K KH.uN1"<vy>)6cchy&frNy&f6.l y"֐.?P2j[Cm/KՎ@3N΢ ϸqryƍCM^"f!l^6#7^~;~qìhk3>ڌڌF6XS7^~>uǑ8|Vlbllq^ýXNhldǑ|<55 _D:KIg9" 9`y>S|pXAL1Ou< 9{ ,sķ,[{ {{}.A Ŧƿy<>Imd1$G]p?&;Z?v{ֹH雸雸eQ$kn1꫟$P/'y$%PG$v%|d=I߇Z,o"ď1!Xܷj??k~3Wj_:e_VQ.'mI(Xƶ1XVKrYK.A}+YI$?%r%Ā%f :< g% "yMtZ'qU Oơy>/UQ'Aϓu9?o,AϙӷyE,Ͷg^Ibȣyt~;ow :_ց|O D{ ^D>ȧw2_ 9`zO D>(гv+zy:]t<9l `vMv`={"<5o?ȷ4ۇ8Cxj<x@^ J<"gelK:c a0gyI:QuWX\pɓIFr΁uq<$Br-q`k.X0SF}v`Z iG4/z5t7ڶ]۶]ض]v3t̳P]E[ly Oku::&zv Ǻ]f:uagtn |tEG_rU_r.DKD^uʹDLCOy]y:5:g9V\t௮O{` Y}_s $Dr]u]@^xON.ItdΖ z]^$s9Hֈ``%'\b8K2Kuz'\EI_>AN(gE̳H_$sy">O,,BP{b]GuJ]K$n,q^ֱXpX39{%ׁgP[[g%쥄h0%lԱmK^nkM1/MvJRT֯[~>gVe%w<:w̵$/!y5kH^KV^C-]q5,u ꙲D'y,r31גls,swU:"y ɥ%$O#8'O$og1ļ 7׺&1 l|k0C˗`m jn?wIKe+$0U ~Pk{Kk{hwsA[Ǒ[dQB `q&>/w~/7A~rZ ̈́LD6%WnjMC6o%GBRlbʳi$)C}VRG\s/I_O>S NZՀ{={ʴ1P1;X?V*:PE46jώy0[-L~Nv~x,ugz`F`'Ot݄U_巡rP jӞ{ ={ -(M!=F[d9l'r qsnfLzkA.-mDroI%GI_jҦ/QLOO:'6~RbXb%Xb߄'F%qRr'%qr5a a!G ue߇=dr_Q ґ^|ю/2KہcHK򀽯_dq?~3x|*u{JuJü61ځtJ;GZĩ{\NS/zb݇⭧E̸=,.bogfٿ+Gms ٟK k&{:İs?E#>u{ =?'y =4sqf{(sMb%Kg|9u>g n'l!stt>b/Xc5 1񝒜\Xcr 8 $O&`YwJ1Ni| {SIGw)z>sϜҼ4pΤ3i7)},fs`gI>H:SY`ïH.t=XwX}=yuXW0p ռ4 cgZ! g􌽚W3j]Xu`zRM\Kq`izr޹w.iyJǃ5o&osָ^t.Ons 8ukthp39rQv9:ur{%@>өKQ^nv$Omo2c'r`/jYN)>K~1ߩFLfBёߩF|w{n/j3wCtvB>¾E+ %yM|WC#`^0}ӚM).X]6X;z<ڄ17Mw?X1lҫ7ܻ۫+ܻ۫n&6m}^[藶]ٶmoj+>0n08ҏ!\Ap5kH_Ir|gB'`H9s3wg3WՏ_gS[PvF,g.3AkƱvjѵ?WyRk&cS:n໏I|,wrN>iO|l~s0-!ſC+,#M&Mhގٻ;==Blb[~ٌIo g|ȵ*/%BukV| kzfo!]7K Z׺(-k/d (c{}ǥjv ;j[Amڶ}K[}xmͽ \ȵ $xI$LZ  ٤)Xkc#5X>+ܻ2VwRv!gA< }QV~+cʮꣲP%>˰>OrI$O&}"?t$a՜>:ᣳY|,2#q|,^IWs\CI.s,1 踹}RP_a_t=\Y磾s>@vd# >r:k!;dg v 1 ɽ:Cq2 Ddk_H}>+ AmgSۥVj2/HS6ؚ ;oR/k@mQׅ%`i$AE$׹V^K,o!#qsxH~en h>tB5MVa+9=uK؏'zM ܋\n&m:S[9vȱ+ewȍn3Ent̚XtV\a!gIccrMM yEtA\ I\TOsMzq>љcsE8xyqtnr9VFtr/еdzg|Fok(1PQl9rP+ArE XDO!TI#tґR ,/X!`Wt^, {KVb{IWVY%=}J*G^Srr9ָrԢwi/P^V5˽7 recr`zgzޙ^w-:Oq+}gw;Scߙw4ڀ/`kg5xN5+8πn=_kTzԀu9 N$j+(;}eY-Xa eshmy5%__r,|.XA`S)$O%Xk+Ζ?U>H2ș'ݤRpݚ0Ĥpk3r+~]S 3rۯc~m6m8j+H^2:}c~9`cOo/:)3&NJ֑~@nj7֗~< Mess+n%zNCA>3/3Eo>yS\;mbB(:K/ѵȱcx./\֋c$us18Aҗ\|7pu<5w)X:%?j}%8촿=;o U`#O3Zj<1Y ߀3 k'os^Rۉv2՜XZۇ d9Fv$ߖֵroض clۆmC]+_k`pYDvV7) 8| 1 \X}33hSE:K*I΁ͻǽ2Sf`1Gl~ܩ9Wv/sꞥ\y% w6s>Iԇԇ>>}o?9X79Ir{@r| 5t؞[75QFƽ z=3u.8+BPKQ1XXAd޻Nż7*XfOyX~_xqso䐝/N>٩;ٳSϓ+< qrlρ9=_WK~hU Vſ *:tLG0'2U2浐\Ū7W5_U WZW6J%ג͛]b]5l$Ksds=~ Խ-tSd#yl*yVlbl:4|U *A.QOr%*ZHLC*Zǒ䍊H䍊V Vj :b1սm,uoE4Xc-8R[ ?BHE;}R}}P*:RUāHEgw`Tt*o#o |:`[{10;f"MG6'Kds#%6'Fl~J6%dWyAlM3&/|E/տ{I.uNEo"}-|[RoT$km 44Mbm 4јgj;jl;Md8 Y *TrucS`犫&N 8)m^^t'zMAqo>S&*m3-!u}ھDm7JX3*e=\[\3Q~EjNyo1#Xc,l̀ދ-xc57VwwOj*oHm{Q[Y1>PY1>A:j;N{^+)ȵ? \X_27+CIa[QC#yL][sܵ@e3@e `h0^a٩N|>08\LRV61aSܻ;m;<ԶҶkqwXw0j+1pyGle~Qr$W 锐\leG:z㏲Q /Q/Q2O+3*֭Lg<+{5`qï轻c<9uF? nԽ+c{92Gÿ$;dI ;ҼIuL$e*\^q$O2*H2HvkɲkH˺\9,{a``ԜiMz/npU7ƁyOϕ޸NJw7M+ݴ9v%]Km}"M7MjMmSo-|5̩юxIrY*ǀcI }+'~2^rX;w;ȕuz淿u0i'z/+0>=_Ո.1X  0_wwPjwjAmH[mjImr& c莐3i^F?> rO3V%$ל&y ^Nju/V?ZcgL Z`c=`fo-ٛGK cͣ1{ha<G?u1zSucR7M|4|!;}zdF'#wGvc>929llN6b)X=wdg{c8* 7PW>(w2ͽ:Xv8NnS;Tj;[ڢ^5kkeܿ=ľԙ $Hr]O1G\lIIg&5%V}]>mkqsO۩%jvTKZG{ ,K`ժz`UIN&_3]`E[{˻( uv;8h k]{oG{ {%V^EmP۽Vm}`wO{cMn箱5sTۇXzKc5&km ?V`*ɱkmbQNPJ?>mǶkvHm;轔^*W} L:z:V5nWޟ&2ς;tρ%+y쎎mۑ+qEp2|vfǶcێmt3o[oZϿָ}K}>t"v}e)`)d)SO }{ ,s NOuo{5ާ$לC`#lۀU-@RS/$TŃ5gbKmq۶swN$ĉ:zT5kټ_Xt5hON]=3GsFAmGJ}d>cۦ;mzS6vc~H5Rzgwe:_J:Ǭ)n?̚'ASwn<] ]nA3tpӽYfbMv otS7fO'`8g ky6M~?n"*T!g5ŝ7\ {λI%H(H^ݝ|WNm:Xrr]$Ƃe>Va/{z/nT8ja2d? ,Z+Eyo!_IүlyO~΋I.4 }9UKI9h.ž~׃}d?( 5 {8Wao~!N9rc=,=F{7ܻ;_2V3bj~Zb/3j:Im?zmͽM\[q$4.ɤq}k\:%}"|Ͼ8w(.Kub]8 ,>+9gދ;3xcuu ϽX]Bj7VW'xc{w!cImS5VrǽZrWѹGmgR%crq[+H15(䵤C~|Չ׵u!TSOuB|/\^ 9X|ZZ1z/a|Շr1>se2Vgdv\]#cum; vLm;&Vր;HZpGjDmR[91t|s/c\ךgH1z8~76CttAOkM<5]i+\FU,ᮺ֬#{q,|4䜕2V&笒29)+9wwܻ;&~Mm kИkИ_evlm;6Jb=ֺ{늏BMU)UI)ZR/'}]kփג~u#H8ϖݵeiFTK.ro0 >  6(TS(i\B.Q)61Z5s~g{>~9:=XR^f׽ }^|>8˳U$%U< s7KVA$d_%wDȦGGIK^dӁ >BO$j#It~.ֺ8S'x҈'x_Xx Xwu~XiZK{ }D}}r#zFyDϱ3H_9`×q$J$+1`9FB]?RJz;=M5&~gM%X\p~`/V~y X6g}ܘs,M9rV~`YGYGC죚3knRmhI%=Wꋏs\Qֽ>c?ׁOFD ,TP$z 3MNwKbw~2`ݟڷcG_н xyt<{_N$+%Mwى{Nߴyl"s)m/V0tQ#y OԢÀ H~+ 'Y,I'utg-]jڂX`uq WI@b"}r\! % ,y8NR?.i p8#Mˁ5J?,ءm.}+N%)% 8:N6 mdCɶ!p!ّD%Y9wzP 3.)x8xt՘AzdVCVilWhW.1s+jPӲo^C`z\iS>i]⻂5nO_wckwcnNkЍyyssnO17{ٕJ K+ pcn؍E7aD"f7{ܘ[Ը1ܒmI=]7ڟfZF2e7qDwcn2ύE7V7Vݘ[qcn*܍[)xX}­4V[{?'z#7&z(Èy'`,4S/>y%# "w> |Ǿ^o/^~Gvd{OMIS;^}}A[Jt 3IZS!~KEJ}]k3zzX*'ۚulM:ֳj`Ղ`z5ؚlM?=?XrRض53 ̨az .bTW%z-Pe kvxLWĿ{$Iyt^&r _^r _^ENgzNg{:tZ~JE=F[xp%WܘM_B?p(Xi!rWoXm"I+ 9#]X|Vs5b-v0-ö |Xx?kmn+kD9Z/!ӜN.֍]g;_ZK( lm'}ͱf.D '41cz T!A_<_{?RX{? mہKlg=}q^ #&MFLҵNӵkLתqS]]O#VcZMw]O[w>ܵDѵFҵZ *֎#ϠZgPo[t+ j>܀ _'ǁeo-lܒd%;;;,|XbpR,՜,l sogXau <XI;`]V}Φ}^~T~{LxXp| L|=Ş/ӧ/e:79FNgdc32Tt6~Zt6nN:ξs8H:gN3=&I}ׯ3{.{taW}D?H_>AGL|un{SO`0ޅvcn/5Ia?$.J``sjOͻ@]#/ D 8=}+W_wz>Mz#=Iѓ <<}|uo߱5}ya[w\ Nך| p $OӀ΄#^|R[13u׷gcx/lbV/liV\l|տv%~$;\dG,X$;dIvF, {еWw *_nI Oh]T>-ֵ XM.0 8xzxk~~:нtxہ&kM `|nsA۞c Y/Cq;йwG:Ktۑν;ҹwG:H緝ܻvsNt݉ν;&NOտG=F!$~͇b5WNՇ;QDO5WLg˝l3-w&ttܙΖ;atܙΖ;rg:[Lg]4󀵟:Lg]l -ckqt:[Bg]l -w.tܕΖr7ڻ֜p ΖJg]l+-wtܕΖr7:[FgܘYJ7SNkvRغYJ7:KFg),@g)/Y n/ĺ1B 瀳_ ت^|SyKq{ކ]I=貮N~:{&5^}(^[>ŮKm?b~לlFd q&ʀ~c}DDA؏LCA_MDDA&JB7QszsC@} #䇢&98/JroARx+jwXKX.a`ɢQ.NG8{]w]3"zG7n=$Ɗk5(X&Ⰷ4ح E-OGƋQ˕n_B|x%jkM_Q[g𯉒okJ:<%tybDybD:nr:w:thtqeHjm2/Z.T5D}=8nHEa!/90COՈxOAS]Ls3mOzjFqqsq6"mDgDgDЍ3B.r+ ވۈK.n#t _̀uk/nG(j#C2$V&ă5=vH1yt^!NĆPiYttWs#N@2V7m?kECC1ܔ͈_jh/``GEC)6zsѽ^E1wY~z^}GW>ֵ6X4\}oOڛ^h qEeM΂͟ ]?//MzE;p!jA<_fnϿt~H:΋ 8@C ,w:q:t9 n6RV@}p.e>Aį5l+į5@"Y$5\@P G||('Hk~K{>to}Խcpˁuͮ~iP;AQ|f(`ˠ o pY_g%_fC M:? H/) 7|m97;~3>3-8D>nm8]:_@_բ!5WonI6D'z#EtNXLt?Ci:!Un#Do~Iz>$=DOמq~#\7S9|/p:w{3h,MzrHvk0|s>rwu^K V>`Cїj l6? n{<~ׅ)?Y`p-e o)öfpw9tƑYsg3X-_ |t"N ֘ ,":C:C8Cbă"[;ġàkl%}yGπ/O7k?r9p={uC {5Nk\gI:3Og}/JG'w5}܁]%D'=D z&ѳ삯P!3֟{Ր/LW o5d Q$}4Č"!f̐I;cG&-Ğ"ު{&Ei8Z]D<?_! fo:gXZ?/F z3@b`͇q$Jne:r.&=3Pv%Y~X?D u SALo&ze8%5CF\]bxh/Ɔ6Gbl(^ y^ cCgx11C%P ILҿ\/(A왡;'u@?"%n_%BK*\ W#tgtkAFeA< ғCzrI{ceG}M iW@K7K L<ל |y~5KlgKoь8ߢ-u&Kηߢ-9~fv.CAj◀e> py-1Zc`ݍuw@oF&^|,#r?2 t{?oQbSyD~3t^#s:G*:':t999#%:OtZ#kN{x$%wg=u|8xXBpjmdL1'\u.Vk,b&6.VcXw'cbcb'=6՞5sl%ؚ9Vgsmx[k/u1>ym\Cq/fF>!͇}>jůb+k81vc#݂}c4&gH3ʷaC3F%h2#}xsKPS$z%,_8S'x҉'x$/k~@7^rT1J ^,~,A15Wħ%O-A"䍒^7J_Dž$%^E}@[C[ڡjI,A= =Ih``K>nDoC.D^`w0d=y!N"vg]wscߜ -;O'HUca?Q0XrN`o, %CHVm5 ԏL~d|<#%ΏHҳK9d'qNv'IS}&9$z/`0I zI;졓.9 sDHDW!'Oee.ƈ{=]bxֽpѵ/$y?F^g<댧{kO_`O:^g<뜬q;Yf`O`0.Dlrd}>dY_6l߾32zo =7E[`?sS^۔t7)DtBSrdOlZNKzNvjC';L #DBzv {Nǀ9 tѵ8fI6K{h44a |bO앳$Jg]b{D*ExvRuCtWóUbo>#؛-yp[Ww@.D'zѣMKR 8DgwN$z 5rl۳^N~W{~5V@̘bƌGzVg'z^=+6!&XgS|+%楆)짥Q1D<8ҾēDzt u18v$ʫsGWKkt(p3% u؛V&f=y//vv\Gྞ=Ќ{ׇdG+D68HIE-{I'Kp<0;͡ys+ ,5XTY35FF@bƝ}ްߍxت/xgl[%u㍓>%)=c?MI6dcDa0Oep9/_:t pkM<1D5yp" >\}o>+=`"`KQΕ5[ 9<4JDoC0MV?"v3S /9_^/lzuG G=f Q82)$=qz(zPqI֣ԁe!=㗡'!]ğC< Dz&\;(y }bP>`<6$>"t1H 0'Y`.\J?XX{d]N|:OgVv:5a`P׵XU8'7! 7ք[,bE7>X^_a^ s,\Qܾ@rEDL˼ʐhLNyXZ{=?Z s,?૤Sj6}9$$,1Y)9L)>K2gI:?gXJ.$}d9)OM 8ٔfN6Em{cR9%dw Xsȱ <\(dƳΙQ>عu|It5.֜g<{ٗI'(k`WYH,=`oE>']$;`u}(b"z&y=Hs~3EL"z&yQ.ELbz&y1=I^Xct7n̋ܘZXbbnr+nl~7TԆn~JgtJg$Mq$ln'}${$`|C`k]k]%qp%>?t.|1,K9%]G":;,Is]qhFqd%llToKc[mHoKݘ&1/Muc^=W6Ƽ|sDƼfnܘ1/Kwc^Fρ,ܲr2-knA nlˮ1^Viuܘniniqniܘ1љR97|74K/ ݘ]؍yyS7sc^ƍyyL7Wܘ_uc^N  +4N^y+fk ,*C-B⿬́{Lp`;G_$%_%-eeK}b%'z#8{7+e{+>DO"z*3E=D^=qn h_c⚆7ŵ|/p'`^}2^R 0{I = =$;do}[ aYB=>wo}L^tzq{GOטG/1^ =O3 %&}DrRcc_Nc`נLל2]sG9$`ҩwKm}*NvU3' j/'k/Zt2Ivғ+ǁ); ,^`V8m_'w6ϯVX_{u%o^I<:G۫?F0goVӳ7_ֳ۫jzaks'{j}n]515a[ٍsM皃nktAFU{E>LR+ ,_3 ÈN7 /dH-T4c3=]fBk^;. ]#O \髽g1a8rH6NW'W<3a.%L}ٓE0}Ե9j#E' o:Xf‡1vG=ļ ^mu|dy ̈́aYS參.pѕ D?GI2 _I`lLug3ZS!&brmɵ'孁e IAM#Yɟuk#G#=WIOӳNLsR wq=N߮uaD粰~Q/Ne]u:~7z]Z]uyX1ZcuW:s}ƌk?7{_~W[L| qp _'x-1|x ]k&]k]k ]%tt-yqn&ʻEs33WtZܵ&]kҟݵ&5Ic&wm'=MTyeO,&m_\Q>8xt-ֵ|Z|D_>F$2:Ϋ35buZ(M J5%S)̃f= ҷ5;8D`g%=DyOOԏfRWĉgbR?H/&"6JLEHg,z%"oy~q!oy~? o,tsDdݕN5X+M7iG_ (I@b#;q Lm]kgIk$PĿD:&$t(:WIN?:r:'?tN~Tt?d㒟նikGtUyģ14h^y8XZG!~2}tf3ݻLn6kj#p ne3ݻLn68Wp0Nlݢ%`1lil3-tEA y !o::cߢX[}ͭ>X[kscmns­a[Ř껢VCvkHKD/E?!]U9EF2Y@cLud튞hr4r_Z<ڵ6x[_9ۮuCX}{dH?yd}d}to?uu]wJw)!SNi)5w]k)xyf1%ʿ#k.Q~8AңI ғI_ 0}wzwzQsY`>/5}&k$K_ޡSZ&f ~g{ǔX㞿̂Ox>υM[9bfkO˘N"z:ۉ9DGD%5ՏKw>u^ïVpcZ- wPݵjQ;&zz?0G;y3`-wh8ҁį>EJ)DO%zӉAtͱwc?D#9Kwm2vZ{_m-7߀nzYST鳰WI&d+;&>xlLJ0{IӉ=$4O?I{;LB ?n: F3 /<͐Z|39$<g{Xw&A׊f"h<<$D{'(viAKﵗY].Gv>K+cߥ5]o첱P;4ħ`co:o]$$kX§}/7| ĿIg?sڭN紻iQщ55AsZ sZًt&pĉ&qhm2MPvmտ/=_0]W^HO >zNUc<1GW;xUc`}L=TJޫk8|"qz^"e5k>544o{q8aơ|hwſ6mJ_f!e]&e:v:Kf!|m?tNotN@:{SqbKZL1ϾEZ5o}-I|8ӉG YׯiMb}>y_8߭qyeڛn}gĆg>Ć=[afb+ӏEd.}kNv;E}댿zv.3B as^FtP'zk;GkvӺMz7ݺыu^l D뎾Q^n<P;/;# g3z˳ "sggH;cXHIv;f,Ό7EΌH0~A+`3CrE\.&~]wO(%'W4#z◼W(◺.W ;{y?pu"9Gz*}NT|.F]tI:cH䢊_W<,C#؋g&0pm,% |DԽLq 4u,\oI_&Az&9gxHҳGz仲0^L&~!t3~$%/I%{ԫ.5L/ID/$~9787$Tg{CoxxCc䴊g5o9I.#9-α=*;o|_%z!K.~s~r~soαKg{ܘ1>,9R^wIZ|~P_w &̿?'3C\=nOy16j%P;͌"=H ғLzVK3E꥙Hˤ'$=y5̣Ly ff]yx~;ǎ's7~9F UY-:5v]NJ>>vGֵO/ߘx$*S\eS͎qq9Z`MeTeS]-u]@`]>>Cul&r̚jvboVg{z>gY=l/ ͬ$;dg %5lf-$$dنoyv.ޖ)}zHZO◚"8SGz`u:9-X`I>[cS \̬o`Q⣫V>c<[#pgwzbXໜH6dD"F0 gOd\fOLsx2Zk- D!~i*pZ $Y2`]k[z -iW_uoqoۺVk͙&|tY]wKmYJ<>z'98)0̙ȹٜd`9yGl =b{Vy$1ɞ"YNc\Y9ߒl ^ws=&̕\r@< Atg};ks8S;;ֻr6[qX`پk`䖹t.fns'灏z9jpb0w3w*8dJ$YEkaKIVm= >B'zwG]DO ~EM!TѺ 0ER]n.Hu=={>%\Ϸ ;V}.{ɽ6̓{mלdl_& Yy#Hv. "hJOe^ >*]8Z?Tk.$(њ`?Gi]'uQůsWF5oU@b}N_[}Tl['Wgydl 6Y&"|dېlW64Ak\@lހ%U #uc]K^r_>u+,n`Y}%V6%zR Q . 7ՠ/v~ǞYO<;n&xd$* Jۚ`wV|U\sK=Pr^_ueߩl ܈C? ~;zz_sV%W5[3[={#=IOvvV;t߯9 NaXn2p`9A ~l!-ħc++<R־:/brzuLGzӞv _xz_3 BzI9= n=oY/&4:ۂ{D?jx乑<7ӬKU98RkUCl|G``>_>@h֜6Xz 9CzH4ˣst9t#=9Duaύ=Fs@jK{n|@ϜQRz:1+]98]]מ> 5ނGk`b^Lw3?/G\%1Cb 5W$Ps.Iz# N,zIO9ӓ|ӓ|nz}CěI wH]dwܜxKakN=7 BdT. 9v)+'ɝ:6f{V|޳rgeMzO$KldOI$[BםlI%E{OV5n!9YD?Lm"wӹ߇?Wuֵ{#1/23'YJ'˳U,%E78nRl:n!WE65= d? c$+t`C"tjrQ|6 t'] S_ğI<T{GZX&i5#>`)_t.fm[ g>9>,- s7 ;.BIv NY D6x.& of|e|tt{'C1Fį} 8Gs{~DG{~I`]˧u͞־0—:+GV5OgE>j힭0w.zd$v"}mѳ"pQ&١$;^d{.Yeф|5躏fèmjم[jl܀,r:Ϋs:WJHQ#X|Z&9|Ā,z"|#{%S[ɞE`fѷ$[BםbS`X,.nd7!٧E",nqA8å5ˁECGUu  \b[[{>Z<DlekRFr+b+Gw-Eg${Vd->'؏'ٟHɦDQJ|gT䙪:R Jlԙb+GH6d7I1;Iv?!3"('[;s7/KjJt᪆aD@U8Gi?i?Xe-WXl߀ŧU#\̒ax>Z۳)U =[-yxZ"af< E#H6d&} ad.ɦ64K&sY= 䟪fDnsO8O4n@ G'i?Oh?D'u-?k950r=YR<,>g>M=[-1VKs7Ks7KlkB,cdaƒ4/؏.Yei >j䟪9Dfį!GĿ6|&{!ѽ\3:,L; X8Xc{&pgRcĤ!i1 |1+7i9'+',|*Iݮʹb9ibm.f~4:ˍӹ!sND贲=I09t&T)>bk=&ݐCr@׺k?_%'k}rϫ8ӈxBG۸-/-Osv`)^$ۀeU/;5!] >vxX yp:uTc(u4эh !K*q7$gOjxu9~[_\췕u !{J$Go(}j ܻZ@tݧG ׋3IV}c?Sˀ5-j~|wK޶߳:Bhgu"|qBoguBogu"Սu:q8Wpu9C=?5NN" g{Rco[}.׵߶:'`4gW幾 \lX{>3+} yx^E4+|hE'}dYA+lcm4+ldD_Z6+"=eBz"; -F!pw!~ݣ?x$Ϋʀ5K'5K'3\,<\,1\u XJ`9ӫ"?s1+VG+x~\ [=?gq֞m.;iI[d埰YQ-W8ٕ8ٕw;ٕn5lhVʻv.+nꛀk|SuT]Jzj?Րꛁ:|tJNI,ONeb^\ѰuG+Wl?~ZV[V/g[$Nk`sL$[#Y;_j?V w&zKlW#D_!~ǪOU8j~?:-`Yބ\zZk9 ANvZ-i h 94  7Ͽ K`vP|~/Ào>oP8xNO"/fN_D:3ItN'Hwt88NkUw~]rD'@uSt5p&KR80]_P]_h 4~?sy3Tw 3TwLÙX73R?W?s|8Kp =t]} y&酫[g}ŝY>}ȋU= 6 a輸?"~On*~?UIҹt!gH<0$ĀYO:I ~im7g;eWw!: )ћ@_É_r]u'`YR?uVc3,Yz>89{Y=D|F|pr94w9˾\8]Ɉs.>I _<P𩜯 ,疫gçaW.疫ׂ.疫_sNѬouf^yt$ߐΟHC1`V?fuӹNN5:kZPg<&kZ}A:~u\CRUyuՃ56Clg5K T#>>89">ry^cy>@9<ÇG_j- /~z>RruXXM@oLOLxMͮYMGw.krs=Ïf!;j5s󟤳ttfy bdy bdu:3әәtfpщ1$ SS5D gדb9įm0}bK:10 X `/]3 t&v.P@9B\7X8 X$`z>pEHOH ~2l$~?z=x]? h2$WIgӹ&smNZ"bo-"FNǜεIgI:?V#omv שm.^܅į"h!9^LHgVꢎm)peڧ,ܾ й6kw{k߇} ?39-gr.Z'ٟHɮgr`NɁ}̺Nv$+2 ::~˫:J ~]܈!įuzfJM^+J}։ҁ׋6{ͺ-0wn+f$+HY'HYwd%ٟIVΑ`CNΑjRsv1kį.:뺎ko>|o}|=_^r/pP9~ \`ۜgajhcVǒ,]LkD>Cd+גN!Y`C^j;wAט<>L<׳ >,|M]o~+|5~96Xk+йUϻ2o~ϳU]>V*1V|\lu>G=IV L.c2$M"T=ēs\z>]cpѵ? Iğ%&_>%]"s%]'5k>#sY@b2?}>3<=S:**3=[a&Flpn1}̆lKHD6 'k粡 > 1D׽58Ԅը/?xtXAG&~3HO{k-; .DW'P; A ˁ/¶;3yv̆b db m͆H'NvFe粱o#RItkn!H◽p"KTs+p57|>_+qXsp;u͆w B$X{Դ5wjHgtJ.1ҳ ,㯹X/wfc0pm,m\ƘKD[ŧOkl]uq_l\,N%=I.ғCzd?FO_cs|OzIϯ}.okISͦ[Gޗͦƒ8$Zm2}G%;j}%z=YCM䁚ǀB<\{p1..k?,99b2=ww9HNy XXˠO\]{~gIWIvaU! QCj"G3!NU:jRNŤIUs߳}}3k"Hɭs =Ev惾>Ws>7}}ʹ}nz4\rm nfPx.+rϵ[ĺ]'nv;"&z~|ȣ_C\5cr47!'n4 8q%z&٢g7jWn4Qr׉}53&zIpMt1)ԏZwLLx]hݍww7&Uxoz7n @o1M~G-  x7z g_Ypp; <W%̈NR#uAg]W]ml]4MܘGӶaA?[.WaPhaC7_yEvm>Dv zPb.?~ tB~݁' T^t푏YN!O[LسGOj>>>pV}mI;> sw<@[ ~Pd{"e}&eGEd%cEv:eQ2#sd&k3nVps " 7")!Y_myl|whwC R*ҹCDyH6I$gVsxYʓ<9KcWp{r<\CiE'.wTM2?uti6pm-g7zu8M ՁغX Gl] lh u 6ga^65~łY.\Z|B觅 "ɟ_)ɷuXʷo?=V| lk}eQusvs3anp+3Dv!eO/,/Ev:Z)QQ[裏~zڏvu u$nsqj>BMH m5s8Մۀ1&t+=D=}M{0HdG"aC7Lu;趿;B*~3'F9ݹ9w֟zq-\ѿ rXHXH}ZgI 9sѧL7 ;` h3yah E'V.*j_&^vv_ЋMlxKtv颳/u?䌠zhI_pϗ0w7K*D6e~}$MWd{l_e~ $?IÅn]xй~ /!u]x$*<<(q98+>Ea «Y6N%5Ƥq44$hOhW>B`nf<)G Q#'#?IDž G'~V>;6{MakvBSл?{  [Yv ~9=K_Np- f}"[ɞɞ4>[x ۀmmasf)¦O?Y" }~]ߏEzNxg=tXtNEg@7R'O7\yRtE:'WtN3GM3Go5c| 8C趖;᷵|pO[^|R⓲ N.|ϋ F0Mn zrgؤChOm2&&nbns?P &M[Ǒk|rf_1XnHOB}pgw~[={ | ʈ|qʞOyowoOwS>Hwo?S"` rܵQZ^cAi}?{0 q󋛼c;`8'z~ݕϖo ܔjwaJma)3OVlV 8?g0/_sqSg>c?)tW =.֏Ln!r,?^?T`gg }y\8 8G軅p.p>l>nvpBN{ 8v~O;x"<13M iB]-_ ۺiD"me1 g*\#_D_W)oup=p 7o俤GEbyx+mVKe.zb?c.Bgg\匜-Z5QMOG0 ? }>t`+ry/ X{enTѳX=E/M?zNOe =-߄},>߄}ܬ/EvYGY|b.G F $tqEwwz7O'n_٧(E*W*`^>'eEf.E~>ia\}v?k[AQ} v? z=BÏwYt#EgI1?EX}&:D&ѹOtN/fďߘC,? ' 'jBO~@݁xbV 0Ϛҁ=l7p&{><&]C~~Іw~@ !B*t۳<6Y7;/ѿ_<;yv]vF7.zo"{ȶE2n#DY}ہ_ e\fvBǠ[=?x,g ?뱢qjѱo~|:u/uՖu)lѧiē-#ǖݳRy4Cؚl h:ZNyF\+:~Y-~7ٙa,͞<>]?~Tl7O} ϵcgl}DFzS#3rA|I+"=sEϽOԃecO cr3ݜgՐ˾F~mg--j݄N 凥?Tx,|,ﱖGCYVe+-8GDzFzDz-} ls\:E65Wur3圗3QG9r/Q%c cܲ1oNߍV|QGۀ{k7g2bra^^\ 8IlE\-aL^;9θB}2)̭{qg./rs}Qĕ[?3i'z:C7 г55s nn_y=)cD?w˽~ps>¶sNm |ZgF~ b"*Og=>JL|h9W`ۿ[L[cwg=5]4m?h𹏟7TdlPڼ-E?oO"[Jl0K9k3ѡ%*#t+iq ws}o%l} dk KKKb.1V|1po*#D뮸60sB%YO zNHO%uS/?zX%J]7?ӂbޫߙ?Ӂm#?B_{ӿEGs+:S>ԉz~*:'DgAsA%D/VdA~,xй6g}s(n lnw]п z_wKB.x1xѿ cE \-:PgV`<,:t~D:6ub"FDMp;XenT*n@荅]iN{wc3V9#{eǬv>0c`Ր+o:c~`Ϋj0so5s֪!ΉΉα3VQ{z?>7/"mxItNxx0_xD3[t}Ǽ:EgisaH‹# Qggs+F=\ ulnBOKx,U"Ägc'*bWU(fX\\ t %A\Fr`ۺ[lnK`pb`ۗN[+s{Gs{GsY׬٥"Vd^Z̺8j *Ez΋Gz΋gyc 0F:t"Drz`E2lѓ'zNGzZD]T 0m^*\r)0Yz*Yr9p3JgUe\VqX,ґߪf 696b*E<,~zx俀׍WM l-l[Gض1¶hzxfL܋?cccokj,D6]d &GbO=kEvckd2ӂXJQ@̗6 ӁN l 5%/u*L[`ЙgJ6`{4 lM.8-t;lJJēdSJby vH~qB@8AW=-)=9 B譅NkJjs=`uz ҭc-C>L#ι:" =K_-ZڟO^ؕ{s򅾇vE0At[^Xcfv N~_d?٩";>3ws=ٝ gX;ݩb}>)t,a[ڭ~]aֱ֑nͫkTͱ9ֱcu9בg"uH:6Kw%so-YZ-S7&y,~!c]ƭgr~k+Fxq->5߱k 1j% ??TTfKꂾ)˖qKX_a% Em'S_6KS0s˂Gqf)EzR㗥_ \"nsqKJ J,~i`>^VFPo -'p m5:г,Dd?٥"Pv>:'GEWb--g6wھ>^B-t3;3ǖ>l~8+2/]n>L|t50sfi`3>NM6GΗ͒e(m̺` TۀS^SBg)Ejsl9JBgmSZ́_I*ҖÄgp)}u҂ʼn["5#6`}b:w *e+q=!}ux~8e'YAm"χY9'>lb8)*pЙ gn,C쥞~Ae3wufyrYz "W0WXߺžzED_*k7p_&#EyY`3i9)\:y`Ôg^W3+ו2+^gY*zwڠ vJעp=)|kzVɳz2z2z6ׁm^NP˔1D1&}Xbom[ e%iA?qw:7`Yگ>{A}bu]=4gԨA-;?&caaaaaᐌGC1ǀ\c@4Ê 1a5Vư}4DcXD4FcX ǀmE.LV]$g`Y~%8$RaU^-3n. ?`e-D륲+%Qx}[wX`}Q_rԷr- v䖫ʞAc]_FV>-6܊-ZAź^qbi^ma)%algU c8q]sVS`_H˺%[Ğ˺5[˺-.W~k?>eoUΔߚ+B~k^#[oRUݛ ~$N UWCBgZ6 x3T1Vp&ʆ3):m_}LV~֯oL~keVV^BjVpVʻZ֓[/o k(p ۮugq̥e =WG 5 "")SSxj O*B`۞8x02̥!@i\Es[U \d|8G!n˝Roz=sA DYs-,h1)C٢'G=_-͏^^Ky/HK';Zвg-tK{΅ni|=`q) h 7Hs 7X'xзoխ%]DG. `ߧxtчUW:чUW'<Ͳ"zsn<ܪ[u;x w y{=<5ܪ2!ϟ31d?3y0Uτ<)ܪiBCnxy23 <]~s!jxKm2<ÀǀUL!H< <~v4!+ !WܪULʭL?&^#~,&O>y g81dP;U'ȭ=Đe'#Wߘ/}纒 ⹉N9zlD~3g$߸CA\xЇ ?뽠p T)`9gY,G*J<ϟ̾ X#mH5Y5Hy>F#mI 6?bms+Vnur?_W>'ח>N_|nǯ[|Zyr_wQ||JtowD'_]}?9Mt~!:W͢#}|'n16&t*B+7~ַAC6"F:qnqn1_5h,nYyGfʹ߭*=wVF`sp へ٭I8\s pпkAU`u0 #_n GܚE|OtOt[[nnͧs[D~y:Q 7bMgfV; }A[ Ÿ#<ܳ;sײg&{mܳ-;[l{}?ל\ڔ4o _Іka0ۼ pІkwVس#DY]ǭ]ǭ}MdbZ;1sY;AWйBg<<\#}h 8S' Y=>mr^qWnOny6J{N7:_0ɰ:vv&/D*љ#:NQ<ai7:!vuߠ}Pl|S~~vp}mH' \p?a?XMF(0lzWxX$.ֽ Y$ L%̽;` w ?Z.g v汄[m:Ƚ]D6]d-&o`u#Yt b=S>Ix|^neZnι6ݴm8`9p7%^$/HouvRcq65w1.Jw$th3|d#krVQt$3s Ϳcv4%~8OB?#tϷX'ˍ&zj4N#`b_w2?sڂ.۴bxg *nt#7W{ny6ن"Jd,MhD;hÛ#y-7\_<gd/&~u3 ::F [md˷b`p->):*}Plu10O爬L(;INWr k9y"{%'ߛ.;k9S`JNWr򽒓G}A쾀3ρ =.t67Mco *jM3Gqib#:`o c)iI&OI?G:7WtnE:7_(ҹunM7Ύ|ItI6ٜbo! "t { O_[>Y lyr9g/*<K+}YQ'}l9s%0c>aUb` 0yzз^&a=݄snӰ_f7y2|_R]y~Gۼ~ "/{دzͅΜΜڑΜΜ߹[A_F*rWaYxx;E.Ib!)ƒm[l{B4]K {$| ,w;y](N:[W :[*jKyAaTbrx];˶9NM wk3gN+xk_l=yHϖ ҳ4u8T_l]z =uWm~[' ?DŽ$3 끬_X33#|}k=A_=h5j3{C4;Ecxk4mO;cwYA __=K~bl nw[Z{Жہ9rS}Qmyt-b !nۢ#9Yt+DzDز:So(:'Dgaskrsk:яo0m{P"O "t:1S1X sEPz;1K<Tb5`u1`[km.n+nz bNL miJۋ0wV]d?YW|q[3EvȮY6t[l<|#&Qo>#t֢U'\gx g jy"w90%^ ޶ O|sHӱ0G҅9 C.Y2O0w%Gbs2=lwsÌICf ^Ŧm>6މV >w[=65vm6Cc֑~ItvωA,B mfbm):'ys$:<ཡNomCЏ?3)PZF~@zol,#ùQ<B_o8v{۽? swo;oOE>G})i".(; Pe!nyp;sN л?;{ ?v{zb{_X~[`{97C)G|yΠC9QywQhZ4G-w lsl}/PLbG><ʾ;m_ ¸|+{>=Do}:wg>3q]s͢nIv@ OWD[s#:R'B&;!t琉#Ak޵Jߕ1Tǁܵvs׮݀S'>;11#nsq;v>]B_~6 y$$஡vdw&"&}[BYUd;",e[~.;C  {tbl~׉}w >%|"џ< vMd5g`/Hlyu`ξq/اw裝ca> ྴv4v~)_ Vfعk Awaߍ-߾FtvՂk7Xy3ծ;3B[ vsw:"OdS{! ȎY1bs5;b]Um [ |L?f3 GF[09gc\ܮMϿ製V'aVE#C[ swϡ:WdwHv"ۜwv,"{vYn7\v?y Aqsz*$Bo,s>n#icT`{=n}.|Ձ}dg[ aSq3!O>hV|sw v"Ȟ,m |:ݓ SMRss|4t/O %b鐿 S"n5G"u3+%V.|rl60=m.nO[g^=>_ͧ|Z@[|b+yCd)cD q{`g.oDvG(͏s'e\va?Zkg o =KN]6Xl9j=pZllox3εTxg qt>?s&EaM.Jض$^_{Ynn/k~Ud;lwCY{,r޾"Y9n/\ڙsҕs]'5:oR}B?- ֣R߃@U"u#_u;{Z`I۳4 ѓ)zfIMm-zI3=tWtHj ܕt0ǟuERް*-c [R=47#Ha=|}-ɿ~ܾ*}.ҳAg_ ѓF=}SsyR zQ}Aoa!v n߻;=,nmgt謫&tImG }[~hF\\s^\'.ɘOȘ 1?i}8a`I~IS\IןKko5bp gYj˘,nsC1'ig57B\mgp;yJ=n? n{ӏko Ā:v߃Ho>_ [^;0w- >I'my*=e\#I#'I/˳ȧy4b){OY ׀m۾Recxm\[x `Vяӆnz>%ðG Zq@yP@~?6a7wgr.ρL8ӈ $tۧwz7O'F?۫I{eD%z3^K-~Л%Ft@< 6\܁ո"'83`UO 8|h7x Od*Y}܁ODs]&P6x]([1g璴 tc$n-t[an'o> w#ߧ>zzX䣧$i'&} "i-TǼ6m.ϰ2xyhbϊV]UhzV~&,IM*}>/Em"6FYw>?L*z5\M+ʁSiOso#J:l>k9w/. p]"\/_GAwĿ MdskDQ`WJC^uNnc4$#\.#\เgj2l+Փ;C|Ilv c}SaŚ=p??>ǣ<8>/NO= D*ѳYT}|T}<~)|nZcz#}o>e-P}gvn߷<\09? ݾO28Wyo}/x*RžF}m] Z8x$9b3Rdi93znN}ry>/|c>o9|,=SLs\y[ў7_QxV_~'^Pѷ~!j8cr,03ƶ`\)zg9D=yԃ=âHϡJC)C(k ě;ĺ~w ύDV*Ā;tOmu<\Jm\\_^*B`+ سQb/H\ 9ɱ/z8xXq/X=89)nsq^/V1s-UiY0wwV;~%DϪ`wϪ^~'D8w~`C{v] u *y!_Ƴ |~_@?+ѣ3',wY@ge~\cMB-Am"@OݿںFE-G1'`;@_-y/g-{{^70~ww?ݏï_FDŽ~O?NJ٢s\':wC8Ot!)CJ󇺑Po6ᚳ'irUtӧɕ 3' 0s]5~mH_пGOVާ?GstGF&S#sM~>G ;_;w*wp/7I?fÄiSo%ӗe,e[7:m ugA0}{ /o w&t0 =)7oXx.c/Xekہ7#kØ?p#'_7ދ!FЛo,Xw<]>G|Zt,:N Ā@ 13ѹTtD'{%ďgm9r { =NBo,U;4XCܡ}b0c8~`K/\~ы`v^ >ɝݎgGyuGyuG;"_d,`wM!cE0掲s9:yY{'?O]~Bm-?^ "WypUi݁F^w^M|*{[K/EV})=mO|{%ܟ+-q&?pgsVl_al~>*_>:VO~,\G#kBߡ9֔n(:{Dkԉ@DsuHtNsErD~l<cB:m?4 sWx ۺc m}bem_{m/{x3j׀GHᱽ`<{-+yk.H1-`cq;M^ei7`M`WB/_$E)"ypd3_ _\ -kZ`I882jo.]l}`'gm.n؇'|χO%|S NՈdO"S?z;u>$=E`Cw\N;oAp $0ީq;56y{iհ>7:E6P=9lX'$a: )N•NB{s;IUd;lw{EǁyI{ʉ W+' >x3W ĞC>=H{+Wbo<}C!s`Q9l [B w!}K/"W ^r]3qyiAĊ08>]T&ILgwi5U'ߵ$=%"="=WR3 >㑞DO;Yt '@d"8$C7 y%9@˃؛s+_\S*Nz\+*ǁ[ I#nl5M9gxS޴89bg=o b96!{=pBo t;[,D82s=3}σIw5դæg*n_m nkQHBT#BBHP$!!|w׻::\<\?sޏ@?sFfkƆkf|kl'3gu9a։gnp̭{9$;q~9|-p-`NSW_gc?G18q q%iP4h4(zt2ԓ"zzEq*Txs n/\-3u謕Y,t -Y/k8pUWՒc%V[#r .E4si+O?֐T{wvv0/6<&6l#|Fq (v~"{4 d]:լˁ M(B?Y͏~~ߵߵߵf`.:~-k}V` k }1յ\{u\WN`a:juu^8\u+u^ܛO`KW3/% cYS ~Aqd/jo׾nX᥌|uGt#ZGt߇Pz y\t^#:o|Z(MbZ-&z#>JxW c2k"$bz% bf`[5#ckqG|\olY/VYE7D:6h+YME=UdϠ,z3)/k^ ,k lXSZ=ixY33B\!Ix*γ3>~y`({wƳy`x> 5 `Ϻ nz4 b>`9 jM}:̤|1 bedzxIox/M?ED6wIM'yvԩ$T#Eu*&$=|rӮxssqs3lv0kYv)0kkQ!={fc&}ry>lc_ls:ͼfOn5Q/!/ݼOnI[,C-FA[HEOEOzO3joo<PÅ^~+;rjepr+c.p}I;cY1ձlV>;~M9G9dKd,y']Υrx扜rx扜rB΍˙`9z\"|r\"lrg,wͼr+.ե;ν}1~Q䆁'dˀndyGi4=aL!~&۳;W3.Mr l_\Kfk0sZ߽]샸}]_G%(scQ b.Ⱦ$\~G[Y>%rޢs!:GN>p|n 1r+:٢s\):R'z#&/pۍy/{kqg"&g! @9bY,uG<ﰽX荄f%_!<ߗ{ p?x!`f('u[K}D^0gQd6K"ykwDȞ#g|޳}\E"o [`CϾů%!9i-^'t ,-z^e5>ᷚ|,uםe_wu-9*b;^jC;?AS߹Ra\ݗm[lKM;!S>L>5]>}q '4+YP ~磰7 +ogÏ}Yp(:N>p|^1 ƊΛEt9Wt>,:3<6);$l't:-B$vfxwmvCR"\`CW~-3C⨭Ә,J.ksGh#x1?sܧGS\;0ger_fΐsF[shS6c'zlcޟ8|Ƚ36? #Zkk lk u<{m_\m Id_Gkhc,5r`` Y=@`1>xZF3rv[~x\rPă+܈1Ex' }95kvx fmf/OsKix#A6wV XeBzRe,?tie,l1l=ZjGt?/4yFnwi>&+E \'[\Z' *<Ӆ NxYu=Xf{k[ļ1Om?_ĺ31*ڗL_'ˋG%1B+qB=>Q蓄na6C_dxm}`rX9̀i݋{-v^hU"Nd9s:P_ЏyWX|yvI|c0f%g1.('\yXRyXfs&`㈫%֏z>boi,R?K# \Bo/t㈫]N]lۙ z6w*t{7c rt^![^!=~)c8R'8/\ƚ~~-fe=9x932;G5,s&E'm~rlzeܳy2ϣ1ߥwgv{NN!V_DZV4t[3=.bB}/:5bȎ(; xJu,ϟb/{#Յ:f`Wo @ᷜ6*\Ckcϛlun`<E89,uBgKzu맯H`p,n(xpBI b>`{fCi=̞}`~7pM{Ӈi̛oYg\c5##r~򈜟g<}TdyW'%b~[uDq#ӭr+~'AnqV{M~`bؿx+WgWS/C<~[>l=8q%~M*%<%<-.=.=nq5=DJdqw?&Zܕ8xO$QOKY[\)k7r+EN<ؿוv'Fov#\)k7ʕnă+e~]_OKvY'ko. f\)s1J< J |1y_"k{jtp|@Cz ɫ&:scb @:}p2?],<_0o>mߞ$F~{ZC{-?zЭW X+n9s7g]~\vGJ7k聛H6G 79=d3Ie˴ٓDȞ.3XWf(11?-Bgo^~֑3 gÁ@>fgʂߟgg s~~0sc~.=KyZѳ\z; نAɠYֻ0k\~ן_ ̜03,c6wkǃQ\e|>]C,4q۶3o 7\ѳE|"z=zcAOtӼ,i^4J=dv{Eas׼0VU5=no]/|z5qξ(XB)5e˅0'7{V zV zV GWZWzꆉ|ru9 :[oB)*ȷu\Zg^?g?fɌS'I{Rm퀙;G?vvs`;B{9D`Եd׮XKہ3>nrձI4GeuQ!N\s~? q⚿,zݢ绠aԃzp iQ8.iqo!] LZ7so3~w- Ј_0k8Gx\eyjy۶ўf+n{/p ?{|̳7 a\ ,q$>g9ssc[= A>'-.Z\E(fZ ܇>Z[/GcXkoaK"([=e-sl#lKF9lZ7ZZ6gb>\#Z^6߽N7 &<;7 (\pO''ͧ-3Q˞_)zreW[}\>0c֋yA7`{ { u{bԯٌOm/`ouB/Ⱦ7^`i]GX<0kϿ؞ ^\!z6:s:{ :{N_gwFkX'kY'kYgk lkެT`;^틿R/|1X֓ \x\ l{N"kc`˷~u Q5|>GYۿ3`~yyH`抂R}B/7 f/>3B/z{_6{Yٿ=FYeA!v?#j95ѿ8oQ-o#ky3#t+|5ѵ|<~~kfEkJăZ1ZnxV \ˏo2<yy c<<%Y ,9Gy@?<ˏO)yz1[}u~y5t";G=Zt+Θ/@r /o-ü]e^>3_p|`(`KR+s> ا7mX ܗHX+HX+,3\\|~ 37"91BgN.\-Ϟ|ٳ<gP/_^/W,]Kճx ]wP۳K^ԣ'z{c}U\zyu=m-nQ/fg7[Fojx1cw_#fĘ9_U>UύVUW`?V="ÏXs#:E'c1Z1VdY#:UsLg[6iv, \.tۧWwzWg cvë֓ ^sE*`ZB~{[k\u [7}lDvk]k^Z* Dn}\k^ޫ2VdoY> |ԯCrfW-byu?zzuҽ,Jk[i~͠sLf/̵X ,5l6{ ,M\w;Fd= V0/lzya>|ԠFyaZ)6mb?ξ+3aph_?;C1l|9e#jYű,jV9b6ٸQW11{~`;*ALiEިX k& wZcT1\ 8%: :ƃζ%AgۦAg[~7mA=>pmOE[~ԯ)<[lzZ&m} !I?z/yjS1M/MM6!&7^X`t;>71 q|!׳ t;>7!?XKfGא'_rGA˘/>6o"V,]6|{|lFl~7ֵoÏ]GC%z.=혫uoy`%Q#nцA} kwD]/D !?v8:MY.vh+',6t;/~-ҳa93mBA1.~_b6|Sxl}f;6[?m lm/9d3!l7C6{!{e:=7rWԛƯ-n;|yӞ9Gy?7cwO?=c)uxdٱUĠs7?#mCrO(0 y0{cU:N}~|i9ۆVX`&Pd5 {B {BkdZNm),yxY Å^%ׅEcy0 #_w/p p Ӓ6 ܊v[j_ kw3"^d uw3`#?Y9XK!9薇+ 5$MB,ׅ~~Sc௭Vy`Ӏ-sVu\[;![,䐭֟ l3+,wlkl'za#c" aEN:c.=G< >=)o翂sf1>%V7;~tyV ?ΓEg\*:Wugňיgň-ѹKt~tvitvI]Sc"&]CΙpX^> x' ?cp0t)<5C,w~=a ωe]8؃]Z\A]ٰhȆ] B`[؛'^]?~ѹHt>NN\IέS:\XۤaZ=B|5~1 Nc:ɳɳY<_̙pWG6:n]GG]i+̀]"{հoV>k>,u"w`Cו"կe!96k^,tہW }𛞩z;~vy&aZm\\-!޷[ =yI~>t_Н  zN zNTd,zCDvY>g__ kݱvXvnL3/ _W rpp w<<<;Dԇޟ\lʠC?[/ V3/%τetK:3x=c_D>2Vo{YG䳎ytӳBt==EYԃGA|,z*zƈjyz 7QL׮' 6w=g ςC/<?* } L[#V?>'z&d (`lG[ N녾I΍|u̞jhv}ewVki=<5=Xqi=z\vr/'^ /ɘ]O2'ٌ91>&{u c }N&+* zzu=+F\^|qz =E[8t^^HG5;^ # Ka3?lgg=}>~}oF`iEV1>s,lyf`{>lg|.g2{$92s9\d>3ϫ?3LsY粖m-Z0`^-==n=ac5e0p#Dj&`v`G-wx$Z>>J^ 5L)?e^X2À3B/z'ӿ)f_>)QwDLE+%S5Oxۧ8~>%N/ק߻4A^r}x\f*wG1>_Xr}|5bx8f>NB=I@>Cȃ^υ9<<{=D=&KXaWW7.XO; ׇ| 0\ w 1B^~z//Kz/R/+Kz/S'W#~95ckq}C p([@{"A:n?n>&V3dپGپ|q}#n"KdHYF_K߳g2:s/ I\'ϼ E/C-X௯__ᯯ,SgըY_~Y_ٻ]_ٳ Y_q5+WU\C\|+کAè5_ w{̽c17]=c4} /Gח]t~__:5N~-~]~=E`Y%:׏AmGHavk{ xfc>V' $`[{%aųa5x|~8uY>|wC|'؇${ !{/mF/_A?ߧ}\O AA[FYԩ#Y'>B S.:{f; s^H] _?0s}=Xo'/k{ۿ- lW#|͵5lr>r7v9p LɄk*`[8`moF g7CaL goV'gKe$t4;t.'f[Ww*7y]Df+:g7C 3rgg4:ht5:̹# Y#OI`c[XVKh`[:nj_5n^  z /(b9-Ȏ٫DFf'P4bAgM)ttkB'o6 r>Po0t{`tG`t`A7el-nا<נ'[Vaִqξ6aw6w ;}Ss" e/ή>9">/Qv?둬_oT謧S7 |z6~ iv>g3Ә;7ۙ>Fcκ\-tEx ݣGߞl o,OQf| &'K<ۜ1B ]!|aQ0%'D1Z98nqݐ3EgTtGtNwR'!S}is|Tt>':7whȻNo!XYӧSnz0L𳁗 Bz!x;?Y:j֟6 漜F^6}Ί34ȆC>#|vdlVS/D|e EYxC.׈"{ekgD~-Ceα\q!薇/#tɰOB/V/*Ӆ{ ݫ~2yM#5*|yg=F:3ckqC>Go>}B[}|Qdan3X + Úl;V,dXY a|ٯe=CN#7l}m=s4>XҘ!#9<=7lG?̳4;ߘ lK@4*ckq0_o|4 u uzmnmxAd7 /z'=ۋɔE=䁭SDvȞ'Pv"Yk@|; ea?BxF (-̙7Y|4a5x~S`~kYX-_;^`XwcO{~O;}?/߿Anbn*Ud?}"ܹ1`/˳zw.ܹy`ij;+~h7 ޏnw+R-N '`{vK=W`.30{`m~f5 ms{ž?x.fa\[d+- ݝoakEN_dPb)eW/"Qdߥ*mZEQ܃E#\Z#ϼT(mQ pϕ\Xϕ )0kGё?E.>QXoQc+κSj{΋WƊJZVNJWby.sEiĿwu F_}Wo3/n[_niku[E~GWc`ΰú4 sE7'EY~sAvNFd;)}ws {7 E.*n#>JY#N~ĢbXZ}ڌ0擢Sy.Tt=?zo3^ONf?SxNJqs X3`Q_`^Q`ɢI眚19}|">>~3;rZ`? cΝ|N=9{Dgn"(虛s(&v$}:ptmvȃ8bm.7 )#/E4 '^, X:MF<4~ %F<4?V=D[ckkt'{!pRBo$t\tC{C`? pdc57^Rt10{k|gK7rY,}D~?=cvsDL1/sG9`އʘ\<1S͍ީq>!z^=[DNѳz0[z z5 z楂y=ZQzyAy'q-Dw7DM"a^o9<^4g<6ɢ+@/#pm/*0K\!9ɱGX7ث !'Z<'WD13V+#'c%'"anޓyO"~JYOEYO-?9Av~ e'K)?{tg z3B/~oGYdg޿$`Yߋ^u5Z`#<> `hˀ'Vl"[an"{ 8!eˁ"ȾMY-k38[w }ЙfLj ? OFxʅ8L϶g!>Ͷfy|m{m0gkEvȆst`GK->ަ=@c}f;EvY^gsK`=>}v[ cE{m| |V,{'*\gNGα{`ڿh?h92ȌCl'`{Fn,- zr{\_-?ceS&1S"=6/FF\{.=F.1rOKYo8.t{o 庍^\:p{c~| 2'O<{rV`_d~ɫY_]`_d~I%aw;S31,*o`OoU{f' @ om̃{] +>YB/tO(QB-B 8_ 띌,js }c[VNJ}b 3}g *Yw4 H<~ Dt/N/ڈy-.A^r O{|[ăt Ͻ<;ňb†^F-F.,NUxNJa=*F.d=*~r]=8/w: k 6!W2?R?z9R>}ά̙I{^93iv@4;/J܍$vUa]I{vJ3*XW֎":%/JJ_dP~,ik|օ5./\gqTETpm)%6Ŝ=)WJGM:טur )b)で k,ƜZ.#.!6=KpVPH9*\u9Yu%m]i`b`߆ҍm n$B/q\)B(~S1ƌ_O56cu-P+w}|j,qUJN׾E @G&.5-*d< m#](;DC\tE爚Oyg'u-,E#%܈y-:<7b<Ӂ![xS_|@O7l3Ag(x9&o>¿Ox>Kc ) 1ԝc`:N-01vܽhB-}X<+E`ٴ6b]&ݴfD@]dR#)Q]Zdl"~Gu[=s cYBi%ˀ넾VV[||"٧Q`&n|'&V\Xz&rϨ3jb㡯nbǑ+șdMgx{:>g-y`Ž2fgrnI? ~-bӏ;kWoX{ӿ+_[D's_й$t.IPgp>u"Kʂ%KNE`\|vd>_x+:kY)zcG }й7KW"3FxjgeQ:q^ ege=tLiw`jIÁ7O~^U}`)2ңwJ0Nic=",żP&MeO5=Ԯ3ESfʞj*{3HS9fʞj*{쩦SѶ)c(}[<\)|8f轏[%t4`ڹ}q~ZGo|m9/,F~Yà{;4 wͬ9l{I"k޸Á/=rLΝ2#'{3 "k{q <.\Cf/zVIi>0=mX9m^ޠ9\ZӜ`M b )`{}xs;+Cٜq{s{79sYs;x+y xX|xz`Vn{^o9n vn!Z=VC{xȎjD6ѳ+ii6oig#7 -閕"KߕG-mZr3rF֣~ l36nq2beAg9CZ`˷]-uկ.gp[Mx @bq=pc \V+>\)B(t[}'e~|9S Tزcs߲ޏn3鲥Ntnݢ;D[=ub/,!\t.?2\"\1\wU?n9U6Ynj156k+tۧDYsDt)Di}Ed*U-*A#(; 8qqUVǡ)pnf8V8f9@e9TVThfZXfV戊*u޼7l޵~Iz>b5xv.o0=;]z[ L"W|ܫtҽ{^Ӱ{ŧa69z񰻁kԫ0? {!wq@} V;w?0ZPszjP@|dk]#4R=Oz`c#`דs_}x%}D/!˘˘^~ /4A=om4O_NGz_a&4svKн6Ɩ{4-AhaՀ5nC_O̓&UO}.PFc8POX `{-md'YcXm`:0Zِʆ`Y+ ZX/X:ڿ >_]F6|Q7\hT@b6}8:V%,~8fkC=\^0֯݁ͰwXL/V/zŨa[4k,wPby7u,~d? $Z} BHtbx1xzi{XM&r4`-&K|M FxGPl! GK~݋%hϏK5!7}}Ԓoy1//1$t>O:IۤCy щ}Hs5,"HgDMO|^!د59M3D׸>{ xpO< O=3}\O'İSw-56O'-+հ<\◵>,͹?v &7y=Ќb{onOļ7|-6ٴgSy|쿚j=WnlM'17&t7Φg齕JSRؔ[i mkʧUkx 6 >ɪfݞfti!_K6Xm¿IV=YۃUԘC{/ 7.tA58<},`у A=s`Kr:s!:Hc[`]׾Nf:> w{a)N&z ^a]+c߷xPYZמ. 6 RF(A]j~f;)R{w'gH6dA5Kǀ砯pMEm4KK̄7IK ,1p!>9D"qk#2~|7K|36 ~ p;56׮n/9}ɽ]r-N67Ɠl.n&gn/{߬`rOG_yA<܎cКjCt[VZHoBK ch.%~EtfDgItf$}PR`kcD=Uwg}ϫZjr'ٝ${d&&xVF%txgE]_΁gdz gͲ r,g[>en..1Mыup86gis ,p7}.YP[W/ᧁe@ !mAս'⪭bEd..l76# 'ֱM_`ʣv4v4v:߽:zG j#yݮͱ>5ܠU7Uګ' Xjlƅ,56pѵN<3Gaɏlsl:⡽{]*5Ͳ{e#ߗu]vP/svG1=Y6d#)$"a޲<:r,Ӊ\0G=Lx6[[m.㪿{w.@!⻈q/p*#"~ۈ`}@!:丸 (!Ԣu!;{{GU]lwwNgGz>1cOG"sl |ugL :ʘ#/ $pY8\^Ͱ_^X~Kby<{0z1μYĀiA:s8|t/:NJN,9t#+HF)[@,k~!" toD[_>GT֔VUBR#$m"kόxxGxxTb8=ԱK DtFn.Թ0FDwl"igŽɞ WxhnVxhnV='@Wf| O!#kqD/_h'o)|ԉuX;ik]S慽Ŭ?B~a; +N>)b+]Ozʫ *^ s7yl^m'G,v^"lkJ}E A^Se}PD_DF . BZ=XXH{ 1#5/xLr0{tmz "/5s1y#z>CO1Hl=3XlxJb&Ob&o &ٓ$+7c}L9'6']#o^eeM>'zcg""c?&kP O<'xG[Quo֭ }'s~ ,4Xkl$}qS}\k\`< $KV%=`1:_$ZĻ.!ok wNOt Bwrh_4Xcx0҅t{,]d#:u9ttUkD$ծt+_:ٿ']Cu&̡мҼ>ye˼&Bu͞=!vgGO4!aO;Sg#zKDDsbh=zVO䒬ݞgOa'Yy7WF i|gn.Yy7zVލwgYy7zVލwR !vI,g}CoC ,1S1/:S26{{Ǟ?5Ӊ>苈O"U*|}u0Y ϟlG۳( ,.x"W|u+pR7+?#y$d׋ 6mϿCD/mV6;xhF]E7GcgJ9zwt=g=sǃznVO5oIc%}uˀ5WKYȝ/5Wr.}5_;蓉y=XS9M^DD8?qxuiv|y4%ʷtVFm\4}ulpmЭQV3Y%wϐf8FsHV#ͪEW~NjӀE'ު5y \ ̪O_[}< M!kij ,>5]3I$$I&yX< ,55kq~X#Yͅtw+:i ϗzSgsN'=sHO 6|VYzf,*;{&zNz6755@eeu^'e^sgDKt^w@)%ًDd55֓ZO'֓yN<~}~44ss|nsn]礆}s{c\>y=>yw{>C03_y)ƞ1%Ls`brc{^&gg?{?c{Ry`7jy|7n, c`12%   /9A3d3If =s<#q/n A=kh-`w%7:8 { ! 5N``:gL̃y?w vw`DŽ#?dp=E dH!\ 9d,7!2,ܘ9ې7!~ȍyH7InC'1<ίsdő&9WC3Lvb9DG:Ig :g6Y3wG/Ow"׏}qzO!T/#4'gxH3t:Jױa?.ʏ=c0L.k?9fRPbl}|bSOSy= s7k+Пdqk$+!>fmC܈dI 'Qk,6w|/OtM?zΗ>KDonOu/  ~^X{'xY;@ yYu-F yYbԐuA yBL^{& XXc0_zEea[C^Ѻp|tPo~jſߵKv菊[">מ?y~ړӹ6s]s]ӹ|DKp:׵"]Hg9t*:Gy:MֽvS ?_?&z_9W+;Wu_WU:|UŲZ4XYzPb}|npV'UlxqVYW&¾f d nq5D4pbXPēlcm!g;r֖tu>}vf<M<M6ytA:/9oq:K"zCĀY_\totoE:'Eg!SNk}n!cA?N'?8į}xlNAY? zL,gtM|SݬFGH=/Ҭ 8 NvCPdnd\6)']π=&Nrc:o5Φ=jh}~2Zj!>ԋ OO?b0Yrsv0h6oÏfw3tn#I _щyD'}_N[΍5΍NNF8lo[lL,]|_ SLjKk=GGשt?FdØ.HX h5a^̓:qW >䛍8dzn6~M+HvZ{D6x/ɞ ٿHȢ-,RXAjH*cDV.!> ,od%೎ yy T%{-37vgIooн7 5xg ⑞Ŀ8uLϛ(pqݗ~CϗMv}7}no9pV7zǾ XYM}ύSnou|K;5JF:i]F15nom#'"=bȻŶ Mޒ8\Ft?ֈOx2t UkJӆ 3h/A{ ]7 ߀9_g{+O v">3;fQ_oXBgL>norc~[{Xަ;oӝ HVuG3ړ8U_>:s8#ac#z3k7XX1GsB-|Pn |W~] :`𕯛ä {$;dǑ|NEژE?P(ˌh w߰cfa1S YƙyэndlmEX VmΆ/t'),ߦtnug_ @ߔFϰ1p _yϰI._I._%F:&#Hh)wnfܹElMHg[ҹtn$ĕ$a6$aytyDup!ы_נH Ds\}:Wy_֔^Fiu.f3\w?ps4ͳ{{,afn6?LS$+a}fc6&$;d; ,as|w"~']"')$"1 W;Bc'0VI] +{H~cLtُGۓxd,N%~b`z`WcuF\՞ =X.`}n"lc1,ye=(EY7CVC0,`y`!#/gewʧx_QBUvc6.6N8'R]kg(7q8zn\ϸ4E4|U {qT7>Սnֺck_ ,cB?bm140LTdel||=7M8K_ Y1<>ˍgt7sx </1^l3 L= '4Nfk|Bi$;de_k?,03 >ξ>À> \~BH6d5OP{Lt4Eģuf0CDw8־vGM;Dk WM&j"pboޑ&Hm v/{'M{D:׀io>_xN_GNNvR Ɋ#z&sO{Y$}O*psstt&xdco92(d]N0%MdèO&x"{૎O"Z#\8HzQ37ΏFEӼ>y}$XT`ͯ yDx/uMv kGZ?>Mϸ}ssXlj /1>Tc?C?>>Bt}6Eb) 5gJ zAmEw6}2`{E_jc oa^lCzT)Tu["얻HbN/[C-[u!͖$1-z<̖N}x-Sxx-SǚXc}7[x-+1G?*5003S=ĩZӰFLu}T־O$e54 Tz# SGL#Qjg>Su}FOZwZNKtړ! k4WiNʹl!YWX+8O4c _|sD{E^t:?I}7O|"DTpwu^2+ A>\9 uCD=u֠AqFa-.Z6]֚(e5MoF:GQtֺۣ?`ꅦӾcŮ;e.vݙ^*׀m.l9䋲1ugl9|(7W+_;^ D3ERFG=$ &,֬6~@]-"஢"+EE)."MQ=Cx6p-#߯V |g+l;,#ɞ&Nv"=Dvp'^d,d\?pS iWmӈ.x 3_kr2p6:x&k `;rgj._3Տ_Z;BgI5d̢YzV2KϣPCf;!1Juc5̍a0я \@׳hnnoTç->8I|R;t-n٠_lܾ;hپt ?I9X00Ā)tv:Ngqs)E1[T&ŏTC]| ſ=LRϣ{Ou/3]<|gϵ^~?"+5NA)~yuxbYOOn;)q$${d坋ϭ $KNvmNvGMEﺣb.;jn[k1,e/ Q=XZN<[~L/|ox`'FO\9DGt/>_,"zѥ\ ̎`w=h yGw=c#gSxd%ُHv' ۚ{_.&u$]dQ,v.;Ŀǹko9ѵ_wМ*?~`{g7G} `B`]k^<Թ}抏jg3ϳNl1r[ y }$v"Y9c}N9c}$;d_'Y} װsٙu: tyDX.$zK ^,g;kO`:1rXs!pFHV} 8Gf`"`K1pl5.1;<\ Z 6^#/^+_v>mU ,{C씽!lv^v:wUu:wu:wtjt{A%#%F:&IS5$~MvIT^w蚳|_Vv/5gwk\uX{5_/x8 L:}G$#OZC~sAUledzٵ.S_lO[)◳`F1G|q9ɖ켪Nvڤڤ 087du8$S@z<5t۠VX}p÷'L =b@K`m5c`g_(ofﴠƕٛߨAx>Xx>O>p=/ lK=ͯwF}si캄~`|Olf_ 7}]wc7:a,a 49o444h gWpc7n ,#o G{u@: 8@t@#]_Cg`.]HVb2L1}EL~b;9 t֞Iyщ= N۝aN灠y <(:G{:My(0Sl|1:_cc8pO[#izz;?н9Gά#o\BIAUQ~^Tң~ ,yxX}]Cƀ9,i/G?#uYI$f?'{ˁGQ\ӋIĘ9Kb2 1_u_c:(YBܚ%ĭ9Vz;`ʙA9s=K &",3D?KO.h?8/иp-{k 1}'0߽@}DwK.y%DR Lu7΅tqfS5klOǾ/PrӾ/Pѳ8QPbb \8u;KYZ_}?*OP9TC{CN硠yy|tg{N;"CI(>to#̡/<&r$n%f9k.9ʂJ8 h 0պEt.%z48S}B`\!ׇ|)peV9|g+wIr'1lpmK)$*a?-aGBе/f֜G^Je!ģg/tqeźG .`3wgb^u.;G'f>[V3s{gJͳ[iحx 9^)-qzJ!?DPo->MםѪNhȖGxv^G늿_]{D/|į |KG}zX_K.D.c^$`-ÈFtYbnE c m^|}#%Gv-󷣯xvWXs"Hv:"Ex.f#{=J`M\"k_ ָ%.kSLp> _r9&>◻151$+~L~_J~_J~_~VG;Ki-^JkRYcZcsR7=.{KnQrXu$&XjK \cG$_,ojgbc+۱D cĿIg9tJ:%D'bdщX=t.&kI6y@tN;69vHwcw.]1 ]81=5"~{}`cgC#9.r \ ҹY15setn,di>,dLS`:7[Jz2H-2!`a"c REn//ϿDZgx7n#y=.&/s\M_x'ُt#H|5岗 1T@_r˥e2wnkF5|MYgVE\gᰡ|l |׷,˳r?γ'c> ٙ$.Ye+D}cYn#C$[&'D7Yty t=b^>Bt͋tSD?MŌ9/k< \ɮ LwVНο+1coysVL&ٙ$+N1okgkB=Yqг׼NO^@dKy< /b^DMOb<=eϏ'Zۏ3#OO<<^_'zӞxt@:Gqs*-:=>WsH:wΟIx:MN[ꉮ5AWb7躖} ֽ0p%^EzI'NTb@G[+5^[ˠ _O?[Ǟx>oy~mw&?ߖ-s?7#DI"d0~?kl{G7C̬ZbfԺB`M${ɮdWX7ֹl1w"V}c֜V$zTEģu<׽س2##k`ܼ]|/星是sp>=S˧gjs \ x(1{|]OBhnVGtD[ =j,* `)l޽]#郎woHVqmPs͜{'ශB?D䲽Cx&a$7^^#OIԜdl!wd xlOd뉼3'89i׻߄dz=œx lhN5VxNU,S'XJY[ūQ%ncеRbBtc^'z%fb'|Şqf絩.]ٵW+^`X+蒳o-&>Kp-[jsIX;'{tM/>G?5(g͹J\zqgМ ls5sqNϹ$+w`gsN<\ JIVm/9y ?}tYbQUvuRbYBZ/-)z/!@o&$1b`:u4P}ut_z]!ɖ NŢVׇ>D\u:st\9:+}}9$Oy>;es l'5NE'bD'b=NQًt>G:&_s^~kHgb)H"p'p =އױ#Ⱦ,{ [X@w 4G W1ߜφz=?xm)lm=>9Sx%?IVOĜ619 ՝H'{A| k; O~c;I/y=z;^z[_s}`7Ŏ%=BZ_ޠkx`$`Al !~˗ xrA ; e\t t!Gt^y1t:/ޙF754g0貯N#z:cސIY#竱/o|A_o(p ~~ynv#A[}S<] d&vгk.N DIv!ɮYO/asq "ٟIV7`7sQ7z蚳wolBt]O7ߘDdW~ ܓ&*xUtV6Z${d:B] v-\^ZytPc.Ղx~gKa/Ƴǁyr7^\z l. XAuҙE:٤S-}!\O:w#<+:timrMytY =Cj,O ~u,z3?x'ްP BzWH ] \1PwBPo.GV+=^ʳG`՞.w /˻,ڟMHuwasY=M,AH6Wd̓sNDtpO!~Yy7Zw!Y^`o{t&.s}Nv3֮߬ˇu^?~^^T˿._wxrNW:˗+A/_:;+J#J2|t'CI| >2W;WO:?%sIҹVt߻imr়.]s7l{ 8s_|[Ky#`'l3ms-zp Xq}PoJ=^9|Գ`cݮ.v5ƳkƊ}Ǒ$ۚd巤asJϒ$~ӓsMy?5g/ gӈN_k9`灳IV~o)pBٷhOuXkU`z^Dً9{Q_uXr9)yUFT9<_/:9O|z/W;g/߮s:t^t^s:t^{Xtbݹ(:ךΤ/J:_%N{2=&{^lܝ.kkyD'~u_B_Nz'{N&՝dװ.syl\x 3,O ~ٸ(<KMO|篭SYiM?Xjr\p-'-nK$Y]qA`]qwFHPccpb ܈'3#|>*.˗GQtt!WE'֝D'ruFy#Q!ۄ͍6Nkmok6.$q %DGFex3~`v;|=|]A`{7uت'v$>n$v7| }CdW&7M }CK'H/7AOs*ܔIkζ&qs>5g IVX XiOe5*8lq{'[BZ Xsq`UŠÞkܲ~_lު~q7ܦ<__`g/]2e9tN%_S~ >7#/t$GHYA+ȷM*T';蚧}Ky4]q};*; 8 p1AzX?0=_A!YT`ۧ.= s YT+ݽp_*{x~* }{y~0% ҙE:ίHB)x𑿂G kH.3tw:+sX_QZT|S ]|"p}k5 ?I./}H6UK 1C; \H${x~X`cu.c{V>CP/;JR`8%eyAA?|qq氡2Nϝj8j5D68TdnVdœlcj4;j->n蚳ˀ]bQDCO&~yO'~<`=K4}NXϸU>A/ӳMbڵX[,'qk3E:'Sθ}`!mnWkTٽ/^(>~7K}y]M4_jrW[Fz(?ууSSS8==@_d~_)~gV0V('Bh\=HZ+J"$ ]{A<ј?# 9bu=CSJz ݫsX4{m'уDGt {Wpޅ+wʚn ܛƼ{u9թkSDWX{oۧ$~oT_BLzK|~l vIL..w6'&_}-)!=?IܗC\}9ĕ'v'7{v˩"ր!r!Oo'!} []__xvgzGH?"O~pkm/.*{'kOzZ 8flD:{΁s$=~/{m9t& H*){.{kgy }c0ts.ke"h,5wAɃS̀5|yXsp 5s^lٰ&z`#φ5nٰEEfS@=HY]<@ds#WI=4aCMyOΥ政aۀ.qgnI,z =$g\UKP;p@pzN!#=!uVOnNNC/l-;@ۊ/?ۉ/'e@/jwrV#_+J|޸VYY|t"𗿖n#5tF:ǒΩs6;H𵿖A6P]koХ' Z]?Br*!?B<3"3G>8X #Lp P`֢_u߁ ><־8ճ[ڞ0w:b|0'[nmJ^->mH>Gr6ז;v.GޔAN"rp6ѧK>h=9g>X:*׀u==sBbOjKb+ysזwj0wIOd.:Y upu"l{Hnڹy&M]3'ѵ <胈_z d L~{\?=ulӀ5?~S_OFS硠_/3Q!Vc`bqzuBߒr 7,rN! $>ɖ#]r@׺5pk=S_}pn.ᣟr~3U'˙CpZ;_͵_P }r<lfk])سr%~?'6X0r۶3RBHa+W-N6IHaOžN6)d$9#sO3Ry\ 7#Kޞ5gs{XL{#:B{#ZKu ] kj`:ӘWş4Y4i Dgj&pjg#ҿ#|F=ǟ$ߓ}IHd[ʷ`CK6K[G: П5W% É'M?xt]|G?koXƃۀsZY\yԹ[&><lѳUΰOg}7{-x-$;d?Y"}qOI{]ID6Yd\䣽+Z&◽[/ʎ:_?7=~oz _hֵ`y/G{ǁ靅_h_ k~uW_:GUz pW=7/W]GNEAӽWׁym* 3VW9_CJRJRߪ A:#/7I9j<ŗ$_DWיJdUWsW^sy(ӟ\O{J~%?Ik4_cwdbޟ&_LK1DCkdyǰ?貎? |WԷ^#Nē@4|9ֱ[2*}1-3`7LKVa"x2 V?b+[>tW:ҕdi)w`rO_ lhZoT ~|8_v'4{ND $L 4&4aNXc/vB母'N躀{Bs2 ָ%Ondtn ys ~uj-``I]SN:~q:gXVx`/P=:_x5OMi=x>)X}9i i.pz i/|ڠArK5KmC4/ _:S=TOգa4 ;"4̀Շ/x5՜2VvU|H^fs_Oꁏ"~ j4nDW[FԪ>ضLdxc_CӪgH>-iՊt;n?}EL6BW"/ZMD4&yaX;Z]`V{lT{k=JJZMa\BXW+/q BH^* {׸N y0#Ӝә9k k A_sP.~hZ5?\+wv]YC9͗rā8d]Kӹo:ᓿ:Mrc<7yaV ?+~rAs(IC.ߤ`M|q4鷺:quǻ:ӛRTgg3EJuPcTB9gJNk Y(=o[\LXp)#y?i!2a%5zOo/^8t>sF|;9Xr`ʑz=CogtO ='3%o7>gh8SJmkڀC燵kgv"ZcBPѤ߸O|h"+ʛ\F ~ֵc`ko1_OLX8iYۻgA@EϚBϚ'*ȳo[ϧgHz=szַ,;GgZΑmSrN(c/Qa*W(Vv2g9!$Sd4NbuV:`0ʚ6 ,9+~6'|ҕ96DYWs՜\1l&Xg:s=WӾ5"Kzr\Gׯ`́u`zN? ֘9Xcrs:^jk1Gk)=!TX9wwwh;- ;8CT=WyA`NjL0mj s򱋔]Թ'X%ĖYb+lu<`y.>Ei.ʸ,%VWTr$#r8Oğ`?/Q/Q/IoKoSyK^埗WmyK^*6H, ~xռ,131ppg?9ܜө3K_34v~]櫗6_lk4/'mD0/d<׉9nvL)uY"=`۾Xv/?7mePG%.[sV~m$뺣\: |uܱ]\JNĨpkWjX`$]cXh3?h2`:B'\\Iĥ+tW/Kbi@`Pp(p6l>9v6m_X~f㾯}(s<m,80^|g2mwuf:3B]1 6r cm2:3'T(S $cں:ȟʧT.9m;`L;If/ɔ>ј.X֯e-9U:gJW^Xw,la:Ľt*ݥJw)Y֬?V^>Dڗ$T1u7<߀}};Wx\=s;Wx[ ; :F%``YsW{4FN N2=I&K}Nߧ{%[eNg̅iAQfe\{EWn=d5c~UA_-"o(^l+^q*n1XmWKub.vw@Fߏ?vWm=VpE~Q. |ٕ_/\ʫ9%>G<6$J22.Opt/]90|zy%FEFoF/]4/Bu˙R\Ev=7?|TtX9`]+T 5(2,q>!p0r:^ ]y5#t\e\"kxUD ּNTvM{4ؤ-Mi_,}LIj^ ==^vؤzzzSWOurBIt5>4cW} SN54ǀu݌z6G"!cu3#s$טM咳EX[kHzv `ݧu(XsNi оyX+ؽ ڙtHWׯ`͑ުwM1zR=ͽު>vޭB]@H ѹ8DrL׆!T!ciCJ#s1B4nc\vyjT.s$Xy8HTB2.=Tޝʳ\Z$rM e:+?tîywlpe'>pߓ/{f,WfVLMb- XLf-*v9=ff/Xm2eMfȤLȜ2&32E_sd6e0MfSBSębat'ݿDw=kQ~DFOP^"of*W<I{I^3?H2꫇:;(;u# cw"v.}1#`O}wl[v!w̅V<ϛشv0O/v>'v\[_蹺&B.C;9;8c07=bL}Gwp 2Pn.!c(biq8/ʸc(:_:KOίcR'BTEWgʮΞw:{6pu:OzuZL7GJr .;SywyB2#/uKw#.+`Q;%9R틬QѯĠ u {N}. dnz\AHw+nwDnOYѵ}9'1D|>f/pwj ˜A1$/198%Oq ]nnzq7DC2j)GM#u<$Gԡu}DzQ'KtFߋUy yQU4qhe\_c`{y $?ֽ{vLbLqT\\CuFuS\~]}융w]2_FS¼0}SQVPRޠ6RPSRʥ }~6 sƵ!kCVM׆ Y1 Y6dpmڐ˵!kaۘc5Xei,>s|0\$/CeM_jn U>*9@̯A`{F k3qc8IBPCnˏ?Kj\d4}3{=4|l"3{='5Oovmg's9inXk:m@bۨ|6jxkCqT^A"]z?ՀOݫSV?qmKp/ý``Y;g 1Y0y.pϟ[0slqCxl;πz ln#x*`1boeH_ C^ 1M_b. m}qmַk[Am}Ǻwm[Hm[Im[OmJm+-m;~vWje׶~õ_׶~qmpmҵ_'i)FXJ~AyT~usI&dbH&d4>=xPbHկr>S 8*R ҷ`'Vf%o! ߀w*߁5 j \Ƽk1i6*7lհ) vuJKWvW`a\;jvɻŨYQ?%w^;Lrh9,۵-е9ʋ];$Fc}|F10b`}g=Tv ûv6 lXbjE=FНzpL!#rI7t??^gtXh#>F\p}#=Hh"]?Rl'#,amKւ5~޳ɕ˹JjJ)~K``={YBu:{F/zyFpm?Q**0*;jU'O)?QiMh'Fk<}+`'Fg.5 }XGK;yxth}q>=Z!>DK_" =1\{bB 5~mƞ4fUM~*ל_2ܵ`S=gscdž:һXi=Ï6 <-*L;\hYDtk0r~].~ \<:bMz`{f~s[\Ǥ 9?}'ؿ{h3RnwNѦ,:#XbKt'pcG*+X.04}W̑n`YsKH-ѽ8#яe.D_p>'눍n:^ߩ!VKmu">ӵ!&7} x8L]|/~af?*cjHnϝ3g7,/L?B#?8\9ی =gzyJY!Y=+;BU ) Gge7un㞕ݝ$=k=k2=k<x,kyoӢ\%fFPy\N#$`:CH3:CHй00#2/G_A [ }&ێc֎@Ab[۾?VAy-N;n 8( ۈt[nGMw]Ǯ=WrY'R ^ s剕|*H6H||L3DϓHye݌}\4Dae ^~uj_̓8\/sv5D{B͓ }7OEw{ׅ}̓|DӤ{>U>%klh5:9(W\ODa8z>8ɟ"`ga/t>.*z1XKϣ_&}1O}cT7\VO }扭Ƃ狭VX럚AIw &^7H]7U<%W+Q$3$ͦr]I*bu {$;샒k~$Ƌޏ$<^)Y)>ɴKƚ,kdvMOֻ1Xӓu߇5=9׵!ޡ';y{dmesu5=Y!)ka\j3 cW_w سb|鋍!90b}ڗo;9ۃjS1}Oʮu|?bn{̏k2j`?G30w؊Bu:QIR'TBysչԉu>NkJ 5cw ^*qo? y$9ɏ`I5' |Ѽcڈ:iDiL;=B/`Q[?|#?߈hDwўik΀wLCnc/gSc֘cjL15y`KunWrs~^P} ,}ϝW?>9Vω .}rh䈥99'?e *| %Z MNzU@ZAZCz%$=3zwYor\=kp=yAl*{jǘ(ܜ7bTޙ%-8e,1? 8t%iּv]<~`1`zs??@t\}[TӼn`k'+ W׌ nшex-1؍X?b_gRggIsdUWڮΑAW;8ѯgdsYcx@1{ %n`Ľ#IHf? $#y] Hl ֘D⌍EMq~8D;` `}k|&싛H YKt !pC+sSbnmFMXSY(ҔjJs5ƚҔߔβYVSbncTLt߯)k*kP M%׊Y9A-c׃D_6/q}yPHw=$}<~.>J?Ġ_Ur2Ic\:yH+?X+&} uzH3wl=陶maX3ڟvܵaOdߦ 7&]e,bf5k0 q~68L2^1=k}yx j>L>Q$ƕ?Fz#.šuʌ(ƞ`MOxīȻFN:hIzܞ/Dqf2YmIw5Nb4#߄&_?rG~׉5ˌ2o|;Į$&30decȣ b#d~9A,5#Ԍ<m+ Ќ˗طׯgT_kFUe0fT5GUbCyT.1<p)#yH0HN[40O՜QVQ[2GbccCWŌj#?|Wy7 (HھQ#V;#I7t}ʨDwE}t$Ec:#_/=; \ػT.kMB*/"yϱwWz8{7>y2#u@sYb X^l}pp qPbF}2FW|[*>NVѾw# %fێt]̋'Ds!>MIwg/s}Grxps*WgRyg8 !y1$/kVl8ύWs6\ x59VJ\]klG 6m)v;K-ww3sS鎑ߜnji@)[r]sr]gY|䏓#b{|O ucJ؞`cx=W,akLǠŌɇ}:c4fjUleb+w3Fw3-t#]y_11cNU;+aC3V۾8o\Up!ůדJ[^UN9 s{tt{椫ct'XҷV&1cqoYby6 (?g &.A?FX"c`Ko'Mu~Bu~MuF(c2S]*:'tsLߞ](9|u^ |H^{$]e'Zkֵ>Zsv9Ck'][o؜7DZZY\RjjƮO@]>}(r6zg9C͵c^OJ$=c}uR?;Okdܧ܎I Qsq4˸#L@u:?:::::׻:':'uuNtuNN:|_F+뎁\cƷM!Ƈ$FcVXb]2'm(ֵXwg0źRk%'?m5֝kc9qPc&wZ&ɸLͿqٜyT@`;Cci2Fu]K]רRr2r2Q:OR:gqԉX7_ό΢\{E~*&yIȹh%0sˠ{nt-#M/5&_KQ+73Vg bv6÷ی! f{诙1t HY]+!3։.Iw7'C1 _/_^s!ΐ38T. j*_O2:|0r qIW=XoL0^<7^d.=5+yf;{vtVNq]yȍɼCN\օ }Ӽ6Ϭ nf0ϋ?3 ηf|/3lf=%|Lu:gRN}')123KשRc+Gs3_̟a\.(< .$/J\h_ɷ$c^ZN`V>@{z^r@0hO2ӻσ귃kGx<TYcY,\f52+Y]q,[;YCe\5Ju.::Qr cdf6|U2\%U23θY`z/I%3d{c3{XڰjC9kÜʮ sj6 um#mJq s\smkÜ׆9Ԇ$51mc/0g]P>lcKş<:rߟր]?kPQg}ߞ{X6G+}ߞsiƜӵaPjDjlj2jjjj^j~jm?wIm8Nm80z׆y! 6̋rmwküG\ɹqG+ve^{o0 kN&x+mR>׵i/5f'X֬]`vu@^,-/Y{÷;k9<|`3oHv{uXֵ}`yYe;;;/̑zEwQ06t}eWvy.X>aBн.־|1Lt];?LǠ7W1<7 ]y'dv?[$xy^ߟ ni *?PpkCAе ѵkCAkCAw׆l׆ԆI҆Rdi5P S6RvRޥ6|Fm/gj|7yg Q;F6?GծM\}83H^so9$`]0XƯq_~];w].|}.w;!NH7M5n`>v;yMa;I&󺛜{yݭPBm;4Nk_s7ܝɴ"za϶ #(qORvs*?H-e$d[uk|끏5" Xօ`v`wG/ft\,,/Vrc?rcnYWle)!{ N[xھy9|g:\H]+u$yɥ㻁uܻuܟkL>@uji AkhOZC{|XbB<{8ݞۓtuHr;}T'{O">9>9Ы;3ɧzt\5X'Jvݘl܍) &>6lۅ5W&߮šXlxRI)|M|YYӳgg]pZT=kQV5>< 5yY/Я&AY<Y1bٰ2R|󈾛#n&t.֬ş.֬şQ=Cr64nocwΣru*/$y _M2rnLk}GcH&;Fot. 9X4~;8.}1K>k1ZַlѶ [-omDbnHA͒OIW >f}̒}tKI"n/׭'](68Շ3<շgow6f{,m:7hY Z}W;KߝʚXX}cp=WaW0޿30ڒOj tWEU-2=Ea/ Vuѣ෼u?Y3eܱ&u:S#gιT2khr{bs#չ|_Iw{?rTkˮ\7K7;~߂u A:^Gʨ twy<}< |88=~ ,7Kk`L ܗbL}i(_4wYW~Tg.9\Hu>GuʽMY*6fs%)6ʽMk_Qyp :x3o!ya΁΂0iϕM{l?w?;?ֻl=f9.pmȦ4[ǫ` 7O8|Rp38c[Poǘp?˜ }(?'q_6wY6ReTLu:7wI[TTOTT6/,6Y~ݵP岎'3\XB5pO*"yYj|.$6sO8xN V%'px syAY8Kr6\-Kp9mrS,1EQ;t|cDoۤf?u+g; C\bxB=p 'Pp7' =S)z0 Aı`W `9Hc^~0}17>o↰O=VPV|[8Ml?Ln_ҕ;u);u)FSIw!>'W.R()r*<$!|ٕ I'?HN  $>',s0~i//'c=8^l8S[ՊIVT[a^QCl{ŭNw=OMDk􊦾.cV3 PCY#y15kzӳӳgͣgggFϒo'f|[ ?1kޢg}Fuu=kMYkkg<ֶk7^=-wW*H N!4iN2$A2?Y=2wz>6DdžY1|leO}sOWsO˚(Xܔtn6| Ė`isd9q*Xt矦TeWP͑st5ε|LD?TcbwCKHwCe=P`m,X^`e}LDL&kb"|oX{0z:ޫ$^$^0z/0Ls.]b%0}g=tKx#Xy`isbUpC}ᒣ&b=\}:XηeOI|?`;ofG4w%|%]:A9#4y7`>{#5_:6 6Ls#uL>02d ~͇5G>-#]:G% ?m'b$(9V^l8,JlVk B3dnدqs X}))}IdR/qEƨ{Wkө\j}p6h, ,~x7XC{\u7Y2gj{6Ojq \,2kN~A2zfr`ͽσ5OaE.,28ڠq֟%>5ZT,LR-C3Z_u5:r2ct!X#p#} V|Vc>jjj\ƈ} jn`vMwO6%ڿm|f<ۏ} V=!0kIw A#0k߂mbwې' c2Xsþ \+X?Q_Y/uʬ=^E7_ڬ= V_'y^Q.:##X$">Ծa#&ڈw^~ }7: 79 b!Tt16CɤFs`CAbˆg8OHB˺Tu3%pcoN2$A2$#U`u`f8}8=8ɑ{q:}:OSӤ^#$S&$s9 Lwӝtmڡ/X2^/x<ׯ-5^ Og<}i6Xh˵_v/MpصgBsמ :Q'gSyRI&hE5Ac/r %T.MB5A:  `q``(c.Xɤ`'ƀ&c~OD/0H2&һ:π. \t'Usj;Iӄz6I^fR#6iX|5i.?&] 5 .Wvm\39393Y윴>~,6O¾{`.5W>3G8gb3I^leo<#gIVf=braa bo(a =Ga-⼵qwV3yc>bP|pmtO|{q{vM]ʇJc7|7eO|zyga6;SV|"2w uDf'lm~ݤqyt5>DI^q)p >j|N0EpS.%|rS`YK߃Oh<Wpo`/SVj13,Q6zcX`@Wm,A޲q?FٸV]TT!<%u:qun\j:7qun wunk5YlJs{ٿ'\49^%WW%N&c/'?y~^ 7&$F2IF!!C#`O$bE X#t]'l 2/RI$#"0˼HwSNsBϩjp!2U!־ٮ_SN55k*}P>*\b<+9 |}AifS4/Y #؄.o%7*޴嶍675f|Sxh6&H-ҕsEL#W$}<&9(MNrO3϶l{ ׶Qb3b%<ܧE6Om/6}Zļ=JDeѵ}"cT*},D#ǩ\b]bY*@yٕjNf`ScfS|Myv5>k|^ 1M~ زlO} 1xo홰bV{|[m$:,:BϐnY EL,n&ݤb?}_e,%$c1{=oraf.)#$sd4va1[9S͡v`t3XiZpk%H>O0}1йë`m_6k:5ܠ\'{̥;0s\湺>nkv%L\"p+6X֗:`ǔT.s6 #o$֘6XXk|~FuZ!8dgM7d]G`!?^O귟W?Ai^g/5sѾg. h^ {/7@1 R=实3>~8_M| \uN]93|x#/6LA=_BJT.Ŷ)^`5F,ގ녑l~1WOB}w|r?!fv4"ۉt{^ow]z+C#^󼔛\t_f}X_EfȔ}#~J2ٱȗ̎>[[XĆ9Ț\qAP̵1`k)c$ߓdH&drHF|&y|K 6;_Z cc=;E \) 2*W_J%$e'Lwҝt'mڡXp? uυ9[yB:oY2{ z/PH`;ݫ'}l۰򔇼@1eX}`!XP)ͅ m.\~X~ʳb*_I\:eĮ5`])\c:/BS2:"YkRZ%c(T-XbuJXm_$Iw;E/-[ttk:?YD{E}lHLJ,;N"X.`{w0 \tSX`)OumZx6Cbʅ9/DǢ/X`oڰ$o7зK)kǎ/MP@O"wZR&}\ƱHsT]a,{`?REtU4e^صH| e;kάps~bc*־ c۹<«Xvnz1ҫx/*ֵC7;eov~JGHsb0;m;־]Iy>zudxk֮ u/8cv@Y#2`yG`vՅj}HjWV,xK7yRo_1Aٕqߵ4X~/bJ~/b|?=wYVKs !Ex膀? oHg .M׊vr7R.r{$ap%]7etcX902k V/yˆˊѯ A]9`̈́݉f}[DnA ޤ;t;,`{<#bҕɇ n|ۗ;Pk7ղT9?e|? >LGHFXcPr}_1Zi殿5u΂_m瘌'Veq/V}[f%/;=5tH}]EMI v]n˞2F؃/L|yRy`ES$_J2Hf? mCX15 ,.(ֹ1-=r1푋eR`#g 49|!Ë-WC2z Raoׁ+bNwX`m `> ɓS]!LKj[H ɨk < Dү$Ep%pteKENl |3:K3M9ɞ`R{وr{ _5{.|AHsҕ;?=BFF𞟥8_'|9 w_>`^G||6;|콑daW~k7{Y[?=j_|10 C/RTNT)JR4JJ5E"Cr %I`oq>{Zi{kY{?U׵|Ԯ ]c.pR&&?k-~H|<}7^ߧBl}(b{c )?O<Y 'H~N@=?AC`#ࡰU0$*|a <@|1l~``go;Է %Iws'[@~>l$ӹ0t. w:ʷP506Y$MH9_sy_<'k c?2a-Լ4 LQN3RD=#ElLρ%&<y"~1X0LiO:u/e /%F&^ !cBjsoao1 o?n}!q§O~R|=5X? NW_N,|-߉OZttt#tsZjk-Dx$_!NEQZڹk-᮵֢[ܵCz\k*Y{-cE$xroMxܛ5gb>OZ3(0ո 繈I9.&{&t-{('SO?kceEυ>ޢ7l.͆%X$i8ɰ$}ӹӹ8t.u:Gb/[\܋tB:%N ˷H&јvjE/9_sd䖄t{hT0NwM b 9k0y7'y:jl|`X;0rCjodb߃'_/k/9R2[|\p 3әktuv:D(pD}B:o"w·I3?y5U$/JBw.xGpS s3`z.ީˡwr4?8k>|!ﵐve}7<[lQlk]xN}t-oZΡCkky#XV `f0%!gђ!b+S?[Ml?k+[2Nl53dl",q$d|{ zKʹyQB5]km>ﶃsTꣾ >bz/6>ұ D})k-a7Xmԟ [t.R)>Z.ZlZzxZ[a;V!E $+ςao< }oH+%Ve#u=K x=(x8Sq_18X}w; uW%{ςT¿_jOρ%&\G;)ϔ^$+ ֍I/COƧȽ 6"qX2y~7x*y<!V@թһmSݶĚ`ib0k:5JN{\bXRϠaIշ_Q}UȆ,5LbC0>k>`}%y 1a霐ƭt ւe0g8Ge7lFǼ aQ.l~kgY'5òYew7i=`֋,Kje1,{$w444u42"#ˊi Gi n ۹1_ƐƐC7/_Q]6Ԑ55|p>K [b >[5&_k-:r_Nl 1:#\^f6G[جgcĞX[a^b+9I7-"Yl!^p:_H\ eyBJGQc]r{bWpOPyG`}UUFabODE'%&fˣC:o O;]}w[nm{[.Z>d?%٩$+6\m`ol'ٍ$]dQ/ae+RRGW]z j{V5>}{Y `]7e & ÷/vt.ފG+bZjr2\i[[aފ>b+V@$"Wx^dV@Hv"߮je\V|gىDkF=}'p>FPOv>&N|ܲ[;#+|{E#+.ﶶZ)U{+忊0woe]ɮ'Y"[)Ux+SI/C6LUchX} \NCQ\5]oyG >K oNm[Ӟ:}ksXj`䊕t.ɰK,+>r~r5XoWSRܽI ɞq\ r͜lAdwhaC@~̥/] ]jW3׼*x??L}^:;/Gsj^ `;$ ֜<T#s l}T xj$#b+"+*ܽMy$+Ux_EWdKH({W 9TΥJ'JEzK㨿i:`$0|G09?`]_5~>bHj |j}+Vz>㬭V omJ~k sVomaު{I }dYYFxdى9VeO?Ivf]k} W}ΡS0|O09:WsKg8˪!j3M|t {V0Ѷ6IkpM{kϭ=F9ߚod`Co?lmd"٧IE l5jA{Fjzo>x׃GR] E`{Xkv)X JCXaXj5`#kXs:pW`fm mFjM`_1$;d瑬_6K:s`,z6 =`bX' HcJc˥=p V8ٙaNvִLc1䋙䋙䋙 ycIII(/{:m~;yyƙKyƐK;xrf˥-W>ln<#ix="yWj)JM7:7::p6)87p6)q6)s6)Nr6)٤I ga&&ţM9Ou6)u6)^lR\lR\lR\lR,S4)nu6p6dlɶ$gm:ldۃ&ۆ:lv66dDgmӜMq6ٖlmɶ&JM9lp6&61\Ĭ.~5TQ{epGjө/#!&Xs>rݏMQru?JT #\,cN KK c~HmO/*kf^1ݜonH2VAݸ}m s?OHSc}{,}*%| ze-WeX"^"|%'5 ׿2sR/$5:d9|4GI瓢1`I`\{>nhmjGp=g!猹{;&;HA_}k)}d? Y5!fC-OqԮq<Po>R$uj˟6K u%,>MFN19svmV9%pk9ܽ9ܽp'[ɖēU>^U>^I*%{HV*aCD*\JU&%]c5 <5n}4:)1[[mܽ-b+;Ja=dwQ:"3ldwv$ٞ"+k3:ө]&pjKt3x Ϣ>Y]~ᣟeoX p#`7% #G t.ޮϽG=e.sOj<`mK)K))}d? Y>.>ޮI$;d*E}kȚBsԮ~|ڋԿhz>5/|4Ohց/ug &a?89jڐuyhwPkavw?km[~ksvobdIfD>Go":g+k*5k HoQtuś?Y_(!7GG|ցc|,gSI|? \`Gv>oLت sv_[}ɖ6t-li',X $I}IvȢ>)ʚSe]cux k!_=lj7XRhs_%|W"u7ڿ6t7ڿOuUQ5@!Wؼ=N$|{npo`gTDWtӹӹ^{O^{OssOgsOӹ:y;_til'Kށךu]WQ39>>^K5x3j>ǾW:cOg}ދ/5ߋd;%!5_68GX\\[=Rx{Fl|Z26?#~>+~19jy<=,vl&IYso-so#s_0| νW:{"}I) z{M>Iv]2˩]vrx ҴҾ@/pX rN>}CrCp7)YrLbc&``z'j d%2'0.v u2`XrZr,w#!^peL\_|=-;. _ G:CM؜3&+z{7=Sow}uݵ5sr]k_־ݵ N}octt7Zӵ>k}OYgel;Qv`?k>i.k80}K޵^DZ/u ,.`?&_ }j߯!o?)g&NbG.mZ[ab+mH'^M7,[Dyi$ >I/,w('uGP{p"xޓ3T0,3EtfHs`Z jq@8,LJHi}d-`_Ib]V*\JN@"4FN@[F"@5s9YGע]cFp?j-z@jϢr<>r>|x=b]}:Λ~Q`QD \>Zx|CzdpwVw{Ut]DkHVK)>ށ-${d:ك5Ev5s9XD}=wR% CN܏g9w7W(<]e &?|kwm`',y<^"y<^Ѝa }G$֍aXG8,&>ud cϲDj yG#R{{§wڸ:x5.߃wfݼlr=G(9t~C:"KHb;()';IQYt s:E'jbujZ^9 ڵ{ \JgҀRK7KXJh/xj8X]rW `><1܃'K%_K x~2ˋ` xNƵI> ,ܠ>X{CBj6>?i~a)CϢ}}3w:;$S?z&WY@: Ig,"NjNHpy< hu\4Z{EZoK㨿So|4k9g,e%.!_}s`}G3_b^c~g?!Grc:ǏZ'ue-/k岟JN!wF8Yq } Bc񹂾Xư"ٍa$߀u߂<;\+L"- O8(~>߸82ߠsgr.ٷܴ/!yt^p:/ /tq:vt:&9G!4;*KJ|F޻Q+\ʀRw?Ji=++XR!AlZ+55/;ϕ!s4'+FE|wRc+Kh 4/Z/{1`7/n&7ζyC){.8W]9G靖sͤ ss\\El*Ơ9O/[.>WG\Ms9}o,arl|*ar 0y@=c;YÏޱi#Ytp:;eEg.t]G: 'H狢{NcħޯPQ`=?[W\Cuu&mn k(Fsa(X28kֺ\r0e#Bjl|ZbY]ZTߕmEn>O/[Ï} y<<<zu Zzx ܞy \a3 gņ[asbC b7Od;.{O9u쉠=!wBaDIWÆ 97s9q%Hr#Zj{SJx3SHa_F}Ki-|(AR,`iJ 0't.މzR[x.,;!)-Z Qlz]A .bN=dOp-GXY3 NNvԮq <ڧS)!p>uJ,Xm .$=Ώԧ:} ?t:MDҿXruJ*sɷ_oG`Bӝo3I1̡kͦkѵ~kѵѵNҵ88ʫkGkv*UU]Vy\ uWZƶkSRѮjjIIQ{>5r%Rr| .#ڠkʇ4^|L ېM+3 Ls=ܠ>3XEʍX[Ƨ^d)3T4pOp}'8S~|U~9W~^b5swSZbܵNut:ujwS7k@xw'ީ{ZOе^kk}B5%%NoI۞/CSnC)P?)wQ`/p6|,5ʝ`wǐ)s\\{.~2>Y'muޑr?XsoXօ/l6ʺ052_s_(c6r4h.K}x.0yaGq^y ya!nmXw;}S9t%s,lt^r:φ;gγ!9469{7Ю8DZW F=֨o{S>GbO?5k K D`gb^B:]Aֆg}ώ-vBܽ_w#JIvv/ٞ Dm M5]M~S&ԁ)_csmIm<?| {!nr&aoMB$!t?u}D1E1sW`*&%c!w5|?W>b9s-淕6 Ds&67wNsϓQS9tV'b;dƹtn IayX}Pn,XЌ_G]0|],{8drΫX^QgCz$Ɓ5:%Ϥvuo^z'v.ߙ}>4PضrM]>4@]w.=MQo)|]5m Nk˷H磢5e|߻,ÌMK h5O\,L}P˥5R:s>Ag;$R3oKs|+.)+U~szM~s6pX~*5hj/ޅo_"|e6_:r;9@H:KHQy&w#ZYYY-)-.WؤZ?ُf]s.=eQoG鏀]].KSu>1?O^}~Pl/Sn}0_B]OHV6U&~C${VdoDn~u3^>vǽΦv͙} _kfSߕKy/Fi}[s`G;=^$+5y+`_&߭k9s }7XW Gaabω?oK/R} W,~ t"Ios i?_}5ç`F߯[m[ (k&'v0_|5& O+Ev@d HdאX˙*3kKzΡ_dM:Ǔis9%kRYH:w2Yt֒EwzMjիE{/.{} BR x;^ݻ!j :Z.^>ZɰIokj̶vokZO[`~g>ϒ$1~.9";HKHVņZ-v\W׀é]+QXUn_뫕`=3)Z}6O}Z:0,e=XqQ9nw6>~-so^>xm6_a_VZN5RZ&ڷY~ۭ_`gߤY|tʽ >k˽ >kO 3H|ҹtI:wX.ؤ*+vOR{}rњ 9yvz~qدG)XiҐ߯~V`{׹6~ݯs+d 'HVفM:lyd' $Of.uRu@'.gbGލ-Z_k?G,=9uH9X N݁B-!YDggρu߅>~!񻩟M|?GL|̮0S?&3I ;aW8aW[I}Q)Qa|tt~E:g΅'xil:ʹ˽86xK~NJèٴWZ8z _s>(Ĵ0`3"QӰ+0]Wvx*V9<[8kׯI3ܙd3H&Kd,jw$"ɾ)oYY3o}]5Fi=]iAp/jMe5ӚxѡGw!]Z X|}r_6y~g=!yబea]^d7ýx\ZnLK.JkF>4^Q!_'KQ_iA.7 TuQ?öרcm֓~I ?9<^'^Y7': &:N:gHg6M:lj>ϬNcz@Zu^Orj?K%u D s>G.M G(P 1,1`89*}V !_'pYlx ڭ~5k+ݯ_]lڻ~ '[ߖdy.ח繰_Jdo#D|5s@vzQӮS{p1/Z+j~Lg;GlhQ/]u=!$+g i}97H s _ }` 3W/_mKu`?Xwag?;/&GIg^ ot˳<gy Op:ï!H@9Xt?ju?V6풫+\ppt , 1"Nd1NU ? ^Kj3Se]=xړ`]L Xe~}_5`ް,dioXy9)P;B`9<.s7e^ߜC3n qc85j:Iv,搬:`:=Ng  9PS{BWW:!59k8uRs'`f֊X/'z9`Mt|ΖOj]1v 3'^ORK&z,SNO9r?5LkSN97ؐ.cCk[.mm-m+m/nlؐ5c3n-Nkh>.ui>Oa_sL^k8[x6X? mx4ZwXi=G9i_/\d4tg<'{FϚu_mH.5yPȼL8#7yS3Lt<o:<0{=K|sY V惇1p6Dzgu/YFNhh h e4n 14nиC+g14AƀF714ύn ޢ11e 뺺[k,mPc>Le_ϲ65tiu!c7uXx ӳ-^.YgsC5W#Yٰyvszz?tkˬ2~K.5|7tc8yrXbt&Yz7<}^k0s].7x!d/{`}`(W\ȱlrʐƞbrEvD5B3Pyzl>@:Ю?#Y;il_~؊hlhl؂؂nlnlv222p7`7`7؂O_qc CcmM~9_W7ESjלS>Le_s@TEM׿BG'`:33 :3Ȓg:3 YfWP]!kЬ **蛎 'Qu`ͫu/juq[we#!Lviz8x*s}:-B=rz󥀋K/I~No N'$;dCG~N\j{H7A^Oz/M[闦{+iEks`~Sloz|t>M:C:%\D8G:I6946iCG`z [˨]rWpeYAQ>XXzKp,JL.ӳ懶`O7H燤s2tդs3C:΋5XJD_?.K  sP3⡦C5u} =4ݴgYƾ XSr,OG})`]`9þ XsaƠu#`㣁``] $n/֒1? _Cju6>[h}g~nagha6~[^j1t I*'):7wbny錩t4r:c|3&Ntbc{IL*g.>M<5O$`֢{k-ּ Xﭯ;#jmO]ϦõXgڈ#\ vuc7il:l ZCCC-X=G 1q΂uܳ`WHZ::O훩]iWֽ!R|HǏ+cw1/#&I|v"ØOK OAn1f&x|;~L3 1ZEttZ^ w-/]ˋq:ȵp:ʵ8w-/]˻]˻])tZ'z쵌mw>h_v?_sGA0њ{v sώa9.t ֵ?>k> ü \|lx1bۭχbVaƞVENs~S'Yԙ~[l"&~";l߿[pGj5%''S}GՏSǯr58wu;`]yT֥.ս<kzyĭ34#ՓWOޑQvc7ƠW`l9Rwa2f꫿M R눓/$f@|)1crc}\&ׁʜ<C1xpVZ-kݵZvvjwʵzɵZѵk555+2쵌m[ΖgѮfpk޻7au#5cݷH0}Q1H1H1n.{#x"xM?: G$6ԵvkXLznHk!vNuiHks`];i I{&Ƚl5EUm^$;d6XlQ<΍TғOz6Z`@|ZUN#2~sXk]ʜ5ysb[sXϦ%sƚs:17}ecWF2`WFsI'J߃xoYoYt"]dȱA'oڃݻ&EX =oYa~vjyldj˨ldr =W+d1#͸je%ik>^ oN߇vZ=vC4fZj|ڋM2/~ϸ|Z%lN3̱3nk 9=slN3È̱9=slN3沟ʸs g-c zBƜqvw~l| ^5|*ϔA hQ|~on+oΣl_ll/#!}پ7鼝tO:%ǭNcC}h j|x"Pهf-P{ƃ_b{O5BL4Fe k {43F:1}\F oF Cg1Rod< 9>V>.j.>=> _<R'§l-~|*gQ¶~ew~;j89Z9:;D'ɢty鼛t>B:%ΩlؤkUsڵ|ܟ5_=΢A_뱗#:EKQ$+1a|z;Ӽ*X954sIlsWµz3,1o]}sKa]}Ɂrq:279XSk|zXS<֔/|ze{8Rl[`Fu.XoUZf1WKטR9iK;X;">Ma!9a2X݆v%ϡy^c-K6;6lcocwl):c+wWku]Zk=Bz%wufZӵkͤk-kkIגwcnmGB}.C}|µxF+cOִ ^.Zeky`߁R/90c&x?3Zklb6X$⧵>+DOk=osH6di'a.xn&R'F3XtN`}k_6S|t)t\"ZfV)]L@r-:p\]s#wέܵ:wqZwηɵ m+mm×]AԮ2PjF*<>Z?S]Ԇ6y3ZuZXոZ޼slεؘ.xv"Ll-8_l+ƘY΍1w$d7.^n.%N6V%yc#ul'S{S{{?KO/`s"0ӖMqk{7ʞ=Ķl-=.X`c-7} |{?bGMNˮx65/9/9!B:sI"ҹtnXIAyR"u#wؤK+YZD]~<ڇR]##`]GcHVN5N!: NHvNX=Bmdilkk~; VGV!ߥ/|qO'=dG[t>"~y |Te w\%t&Ios #:N.H9kmktvW]X&]J=3k]|H04jNE&YN_`+~op~o/Df$Xb>X/ZZ0f^օ/~Ķ/WtΥ1Xrxf,`A/fA9|qEHw}W ϮςXw}3;&~hNq+K|7ʣSÕmr 靐(:h<k<K{mbcO+Epkku0wG=[Nd{t&Y9}rv=RH&de=dggȼ3.{xjFe-g&{S _c L]:ᯎTtĘ'䓎IG]M>I"'qM>sg.q%N|yX̫2OkIׂ18{Oqpw/iJ{cm `_X=y.ٳ3;=Ξ u]Dщ3t@:"&OWDgONcV!}Юkp!3oP{)=Kf_p9?K}d/yk ؉uD1IcXc6Ā!4_ yet.~ٰO랋7 }nVGHMp EBdK1N6 ɦ"ʚ$P% D܋3OvCR/7Ap^+ \Hng]g:5ieIv"lX`k$1F'/^8SCL β%a)<=(V^{ҹt΋Ngb]3==zLlt&9INgboُtY&׵4e޹µNj3Q{/9<9Gcp_xz=^k`qG@H'bO od3b7I3aO)9X`~ZNIMs">dlR '^d;,Աʺ~yRyڋ0e_[`o+l{`:SBg]LZO3.$Kg]4GyZ~vBj?i l{ңba7 ~ۮ/zIA\>8ufNgrLt&NS3Nc*zyhdp5w_2'{S>Gşu]9_wU]5WSzlU! l57Ugbabn[`~tOG ]LE}UdQ#%dS,SDsI[e]vf˩]@kh꯹w8Vpd~+ _WG 2G4C:ߟu- gmquQI{TTtQQǛ֨ͥr2I&I !@P4@)* *iCEe]teWVV}z~EUMuUuuu<1mkI^M|^0f*Fo3Lٴ3LٴytL:7Ν])gi#g[;HYNg۫ζrri}zzAӈux70g#?xt=nFw]fZָ \+0ٶ1ߴ}ŷm&p緶ݞ񚶳?׷CQ@D7vžm5!Ib{c޼oqu}ћOCįc4X i/ߜͣ)?ֽRKͥ߰45?Jt;M%~ `;M-n:;[Q ݃@ k| ʯ*! #<1q1nC?zqof}l8t?`O|h7״ks\I:7NOi'0I9tt^(:~^>m wNt}? O=5Lg'{#L喝\r%R{ߞu~kNz -7|XS#kb%'$;d"BdWCL"ߺu8󷒵>"`?u8◚wpk◹m$~9q @Z|ĨĨ] |)J3c.;9r+5k{ΆG]G51],?BȺ{Ww!xmt[}[Xl#9۾wѴO8}IgH:gΗH Rt.tN:HE'jZ<'>DֈkA\ eC8?'Z7"#w(ãzV|xTȇG5o 8Spxr*}qz[ |ro|!k:`!dGlɖ,f,%%$d廅 -cwłEt9?K?**>!~/ϯ6FzhcDZyLKk#su1dmu1Iu1XRA֝:GՇ;ٺZjr\;`̻o)ɫ7^/q7n~"c=:%mqq^GǓIҙK:'N^r&n&\L:א7I^tZ}Pnt]ku8DtADAR?x$⒀)Z]Q5qZX> &x1|o8o|l*}ێ?[AN$;Bd ,H-&9$Hd,\Rnt]m8zCz7&u.nJFnF߉Ko;o;L\_`cٺF DhSo=P7mFٺ4@+ me݉{Xǘ ٶM[}wu~ud.47S0 =_tM{cmMmM}Ng|,L%IgOŏgG錒JҹUti}^ \jk>HCį=I_K<qy F4GKǍ58cPM?ᓡ^|aO{~K| w0^ w0^I3JUA#IdWL*v, ֫@" \JYįsy pu~eO7 ޑlwbTK1q}XcRl݈:fFX=P7b$ԍlgC,bi{:5gu#Vj&?y\@o{yui׈dimL0/։OD8$got:s:[;aٝt>):KN3s4,&sH"D/}'<еV/nEtD$=7H>-|hoȇe.k/V;ZVX~|2ϋoO/y~ BW{ w*0^TCtC|ޡsy=įkt%p H0=@Ϡ;3rV XkRl u֍zցA{ԍS[7:;j+uR| nP7ٺ5.TPT+ m/BSy"c{+%ֿȓ $g/ILLLjt&'k9`fs$u$HpYH:E'z$oH$zucQ+u{70W^Cx$S>wA|j {AG0y$sOko'yޑ<˹1krnp'Ɇ$Ld7Y-$"$+kLX;pf虂?AtC>. z >\FFl3`}Q#=B}j=^꘭zցF֍x}u#^)JWXhuj>[=U?B݈ZdF|Ox@@o‹ӏ |Lb*#onG`>?므> 1,w&G; LLL6NgNgܙDd30ɏًt"HܙDd3i}<^tէD׺} [$??B<q?S>$нb ÿk/;>8y$[|>w+I|$S%\d#~'f,$ۊdHV'XܱctW7]O]=M3/s9xϟ'O=ED%F\ x)ԱeRlHn$YoS[7FٺH%^)lu'x16|^ nHG!En&Ƽt Md*bW2?%+?dXm$1#;APb.c8@M8tu:S.q:Sq:SnogRbΔNgJtv&sD/2i}}~^-K|p+_y&j!ɇ``ʇ4 pv`]x~>΋oJm ⷃ7yxM-)IɦJTUɦ^dS$+ fRWcImq~ s2)~l ~K_U#TC1` `cٺUQ7zցu#,1u#,5֍pRJaYw|nFXn&cޥ M ^/RG'-AL=o|Lĺ!_|LFѤy#hRCSytq:;Dg6L Ύ~NgfNgX){p({p듎FOZ]vp /<nEG! L{d0zy֮n[0tv|8^>Iy(k:PtJq=!1߈,ߒY'vMFdۤ]+K^}]D?A:%~]{u)zG1|Lzo }|u1MeFMˌ8(L:kH)Vt':Ϥ$q:;5t:;]tvD/aOIfpЋEt9D_BQ_E<)|H9!Usx c?4dN#.FGEntԚ"0]?ӹ%b:˫ζ/۹;bΙG>Ջu zmh:ϐ\J: C:%!rt>J:&INg˝.cs.7֫AZOkiZˁOړ,S|.|H!-C2`WkzxrS@7]:'vI^[E+c8bK)." "_Y-] ك$ wu7ES7Z5F]JD?F:7$~]7&~=wuyn^'9+uu`IntҳN{ntFٺѩlRAJok>o;7tYGٺYkN`̻.Mn`ykkT>| ^fA0ʝt;?:t9s G5t}t$4u cʺf}zuc7Z."zDEړ^BQ|||C.:kw!pŮ ]v{fU7.ȷ8|MnGtI$;d|b-t[BHd,znxv,ޭW70wyIX!z\83GutA.zցtѾ`s֮k4^@bٳbb|]zU[[l>NE6)X 1$ Y,}H>WYg=wmLt][ ܄1į͈:pŨkQW߂uy!<;X`_9Uб?K_+>hzz˻-ZeNO[<Loy6_ޏl "ف"Y @2|ѻ_ ܐ7o51/q X You]nz^8vsı[_,1y$[E$+s0F`ochp@cz y9{!u>[W_[wzl W 9/Ϧw-s:\ts12}q:!ɤ$ '}FZs0~VDWD{{{37"Y9X'"%@w}9]u?|dO'Rk>ֱ< I܀:Xg ]wȷgGt_t_ttt[|?!Ig9t!jפ7O.AŇ.gĿx/>Xmq=Csk#>]Re{)I_ XosӦst{I7I'1}e}L˜l[lߦ$Jd?ڱ}TCwe=\@t{5vOwlbC#F=tkVM:73} XL_z!r'o!#w,5}໠?m<υ@y ?ǝ?8=:٬"f],虳.qY7:٬I"Y-=Y;VAZZElkk"rYB ucj'=NRaS^ƾ u]WPp0=Ez=^:wFyH/zg3ҋEwFz;蝑4zuMLwP{s\|bcu,5gkO֚S |S;>Z)MH6F`}v }t=cMtÀGc7X-XP23~Wυg#>6}$oz$d=ZaokSo pꆽZֳ[_jjɚ/5$xɮ"$CdQvgϫQ]y= f5hG~kZ8|O{zK?}>; y?}'Y'iR''V'qaodI[?,':=G{=)9`i$d?WX[mtg@'Kh}4b_σ=5A/=u Qm\ { {An0C =`]4ۻaσHD/g_ l&Y9:?-b{u ~{fn,Xwrc28ۍeX7SX ^2x7X|Jc"xQ`NjZmqcrːX<2$֍eHː^n,C 2dːn,C^rcez7!oXۼ[.~H9Ҟppkz$zu=J&~s/"!Xk5e,u;{2/}Q'` kSB'`]PNCZ ,u;{glfc'fl6擬ډcؙ=lFL_:RejO:=9d{DPh[j5:L}uu>!`rIvs~hvg`{ͳѰ$Co[P+'Iv xcϞC!`mmh< 86mxmPgζ%ζ/mȶddMˡ&r_5 ?J}M&lgۈm#vhl6"6mSb[9@6^1]sg .."z1:<TOl!b9r>[uQ'C6-9o5C=թ=V`.`!{齹l:Ȧ3 s~$s- CW`=C7pg(;{;{:{s;3TJo>D{w5v;LzĻe=J|Xƒ2,t9ˍeXyX˰-Dמ57awϹ'z8QA$XOsπ?WAN <3t%'f ׳kpk6Iwz$\K=t6F݃L`#lгg(VAU;g#4CC5b#۞$GڝٓCUN'Gy#Kes;i9:Ol6:iD2R|k?YlYl9Ɋ3gtF<~wLSm!z]o)~{,|KľoL1{{="z7GhlG}9~qLbIk=M}wbWAfr z0sx=<`ǃ\/29?!<{$U`~I(;̬qg=|sBᑿψer3b~r4k}حO;x0L&lOȳ:N]yS#IM]jN$cD q4p-Oԥĉ>~ǟ/1q [&X}f! 1|̧t_"K˼N ,:':=[}s{* lSG6< kouQۿۅ<2xn?+x۟ԙ=H$ n?x&jxXVnM y4Qk;گ Lb&;}Xp ɞ NHHcd>oԷ犨-Ea.{ͨ-EzދRpJmEedԜģRs?! 'Ȇ3ΆI>gäFΆII1ΆI8&z XOe\ǁN:6.o40#74ͨ/1ۨS}<s>h7~tt+`3Ѷo;=2t`.-^ѣ}ZO{Ό,6-J'۶mɶOȶɶȶ8\l#&7cDf6ngۘVζ1ζ1]mc2mc9ƌsl3l[DQ^zKu?u X_{3_s֖ou?םV{. OӾiW>'`Wdi_9Ӿr2+'Ӿr2+'g98i_9i_9i_9Y57`WN}dWӾŴ,}e1+i_Y?ΆgC1e-^E6T dLo;nş=V?kO 3g>Q32gĶEg1t1a~髫clh[C|W7}w;z:0}u Ev|us< `GAmljE~,jE~W0M':gmɶ umvll;Iq96P^!W:8>l66lm@g\g؉ζ3ȶɶbG=lǮ){%>_ko$B DoJ#/eO ],@J`yBWK/j IMn uS ]\#z`P_77\F_櫫r_]w_|uu`6>w7PҀ{ԁq,`{u` &k3Nm\m drl{l{llllmEb֝ Ķ;lm| g8g4gtgζmvl2of<_^~>̯P[ѧ˚zg5p35 XP+`B? ,}N1:X}`NM;Ӌݜ.[(XP{*=DIV矡~Y 񃭟3n 0C) 3ucUԍYζ#m3 m3G G+ȆJ@f}tl(;tTqS^J}x)ݕ*{_ΆYdޕB,8JdO%#kb(X$Ceu>|p&hfD#E9 { :xmCƨ?7u;͇}^>@ψQ n᫫M[@} uQ`ǂQ ?:P}=N](u9ԁ;)c^lg[g[A)ٶlH !>&۾"N[lúS {ߝmW8 oq6u>l+Lpvuf8 mζbg[Y'>)ROBO eK܀n{x9\ X[#-룭a; c7WN: W8 7,΄E}[I&9'k2!ŋ~- ّD׾to%~#F$C#{P.m}U9g=#y1&qt,f('ۋlBCWe02⫵0v3adw!=.[&[?%S$';ԓcPb~*sD׼-.!z):B}~OT3 FHV):OtnN9`/ XĖ/F=_My J,LI$;dۉ(N%$dIVĺvbh蚫[] 8Dk/po L/=Y~,zou:O\R`Ԩt,f/џs=_] y* WE,KwgY$GHb)JY5E}I6d'/-|^"ϼ0vS"ϼ0vS2dgb}Ud%"{x n'wHcE_T'[7#%]̻KW]`EUDB7Lx$?}.F/JL Xdc']| 0x@b]%]hڵzvW/"WZ_jZ+L 7O*"0-d!ٹ$XdēcFR%Wn"mҭyD'~gn.!R^4`Z^}Iw]$&l7>tzwO֎eEIɠ: +ZR p3_c8GX-"F.FLx.R{KM,3z=:3=Ib4}pD|es8E|j+L_+dw{$W>.#INv"ܘq'k2RQ.$nFt[=H~]<g/Di5vU˯u >E3D8矏8hP?·}x8|ffV𛙑EHdDE}ȌHvn&ٝ"!7ՍEoxsAך38@t]GF7#z+e,pgHJLzg5|][ u=-JHduNH>yލ^c/uzDZg:S,4XAIϻ[3sROy^J}}O1*8ߋ]}ĺn/)G)iKz"=yX'=SH#焈)Eߕ4˽ c].]L4u^]]-Di-p Jcxt|ź\rĺ\IUۛ5_"z61 <]V$GdqW`^.$+.o[l6 x?>3 eaqǾ{ew/{fX/x>9:_j/9nAH6d?fvJOlʻ#ڱy^?vt ];-}KLVJ<0; NB-3p`Y7-) 0z9:3g9s΋ќJv?'|%Ϫ0v3GUafΧ${ddʳ*̕gUνmJwC3WGW.5'|p>ѥ΄50į,;0"|>7z~b} s|Xπ98ٰ8ٰ8ٰXz:Fk~bx {X{XF% 37= 7xo-DLK|gnS <k$Q`Ws+#fz;Ms7yt~F:#X%:e:e9ew8e9e2)Yʚ. T]b[@^D;!^DA`Ykk-j,}EQ`ee:S ź,ndl{o =_al$d"ެZwH3deb׍_矍.1>ItY g~| FgTa싗R,;'Ke^#G_*R{D_Bt/KWRc,;P? |}񞟟ookWt,f~KgAw W+r/c7Gl1!Y?f܋%$dIVEf܋˻]yk-Z|Ά#qט$Sģq\ Lז1Z%Z{K /e` Xy/yZp93e+,K|unmMa.ǀ=Hv0l"7<ڱ,Rzt9+u[5M[#~/˵7F>>ODbյӨT転SwEe'JE(wܢd*F~w3q 'ѓwWHݰ} Y#lߵBm6FS/w?bZ!toE?ka{̂^Gw,otttt:r3)'s$@:;S.ߩ>)/w]DXwg}k \Dģ}na#Va~`G}`e3:SZxw߃v[+ݔ+dd^d^+EvuNv=$Ƌlpb, ]}}܄1?nJ_`Ø+c?HDD~ |D_upa(~0 m/}܋ ?ςo??o-k٣|Ys,K|e!gYOgY;AY&fh-!Hv6^.ײ}W2/K}K^DWw܄1/kq͈HO^~9e;bd_'c_eXX̲d.;,{ee/ j՞<_af0vB'dA<,?fy3M ٮ$!~",+Ǘ%>u.U Ҙ6nB1ģql w*Ui.FbJzVłz퀱.,бS-/~P|yH|UL|U-BZn$٣$?f"dlFEnDoY%z}WrХ$'Nt>nI"~oϿWľuuCǿZ=jz't5}euk箖5SVwwyg'j{k5SHWәj:s[5'Eǘ+MᄁC@M~Ew)݁Eo M41U p4([D@OXۿ~&*Gg ' ҹtO:?أE?أEtt\qӹzssjŝN'@(/pѵ^B(k\E[Gz `}JˇWN|xU5Ok-,}EZ⮀ŬHbpOχ+?<(#~ c7+ م$*ɾ&Wl($6~L_*=ٺ}Wr>&Jt9H ALs|<'驒=W.F=We^'K\,R$ 5'ԮXW/Fk;_l<( c7k W I9]HEWDkWI-}d{Y+ӮO|ZsìmLt3ǭmBb"emZڿ kum>wJM $c1lċѺkj]9j] O=_ c7<_af]dl&ʙ3cə3c֍$bCr urlDznIu5?O%)?'z-Zi?C!r3-2g#KL#wG/c1{}k|j,_M^|5n֗d_&M$+Շz>c"HKwC^nԟȃ9 c_s~V/kP>X ~Xj^/C˼< ,s9XXKaK|~|`מl3 >gzA΍#-u5~wa{ArҞlкΝ w{y>{nELzݐ ^z@}u 7&GAh6"SIs\K:Xs7):nJ:%I7g_щxN i>\>Jc/9I>I:Oё$rc#/ޗܨ9!?7k9 d,]~nF~na5d!`cG`1"|wb\~VvY%=F0} b*3wc[`[S[Azq8x/'xq8ً;h6K?C:_$+Hҹt:0eDI秤$鬺鬺Bti}RuUH_K#=K^J>K?*7*Z|@nTuQwtU|MZ]A.?75sy)sSMMD5|MZ3u_HV]}/MR#>FETCL{xYF5U鈩|*^^ܫz-߫z}wT͑%+HFYM:c=^ǢyttntӹI!1'Lh.&z,KDo_{1f͐7rc@>q5.?7sYq3.?_|Ms=kxjkT_>XX)x" kQ>b2p bqk@o6uAL{)xM#S@)q z%< /ٴR{ˤuҹt%Γ/:-ӹrs N;Ny:O673Az.p-ѵ'O׳}->ǿ٢2`ˇ-EQB>l|~X /c>p]%D_EtK'-|;˓Yz<}N>Mϐ]lۮ|m7ϱvӳ>g[k )$~a[d{`-gxv\?C]{}Lj}nZ ~m!ģk~uzuXN.Zm`]wu> =ٶk*n>=⫣0vzm dY?EsۯqcD$?Cƾsk%!%~)jx4'ϸw\7V#Fo ou : =)bဎlm 񕭽__z+۟%%$deW$.'"'[7o?Ct9GugJW5Ŀxt;D6FwFޔu6/`=8 ߁Ʀ`\ob]]@b[MO{~oJT۽|SZn#n6b:d3HvɎJ"[\@ϒl9ɮYUjO֎UR.]3/D5%bD#~YkR..!~E) gG)x7 Kr) `)WkOM*VlߵUk.Ota+}jRNGwukwmձ5ՀT\$yub_߳okq1 X~a#fǭ,ۜ͝q3t&YDg`Y@:IrҹNtWz:OvK@->[#ܘ#&D!~)7#V#u;`zVˇ9[wk ,5->`:#/;jχ;}=w0vSnv^dwƐC$+m?f$ۙd3H6[dCEc9LjvʃKMi \KtYOS>E/s9Ͽ5p<ۤGJiL6ꍷQoMzG= {tsx@bvwwF{;7?j<,Bϳ֒O$EOw\yjdw5YdXvWǃ %m"p%ѫ_$G<Di-Fk6ZKNIy s݁Q7vб]?^ve'F?b$|c75d$d,]Ekj=B[CKuc^] LkAgI-0֞o֞=ouGwmGwַ{Rs΅knEt?g"~͙Y_?9Lb.p˱]z 9KC9^,>u͑]\:H~sHMθj茫F:Ɨ+epݚ25.kd.,>Xt ͞1 /zt|Xsoϒ|q4{Hܭۤo;ys:JbfNsCNv3t>.:{{x:O>Q/]FjD׵> |g_r ew#ǿ[k+k> 7v]n~[sU`ssjb.Ov ?wkn#?wS8pٰ'XX { M ܓso4bϽ//ELuo}}w9E^9EI s EY};8¤;|Rt>ٗY/?_]mK.NyįkVj!lȇ=zwˇ1w9.`{b\:o&}V?o*~omaf|k c7'${dOl"̾_Nv5Nv|>4v,cd{pu."z1k?p#YRr1[bWߓ1:vXkBGu.FOx1mU6sP|5W?U|z 'U$[%D{Iv~H_l lXj 5'O=j׾DA.~"l 0ޏu1ڧ[`=CXp 3D?Kt]wN}!5?U@`\7}|K]ms-Aay>4}wz?@ do p.>CsIVX d; dUtGzpk~$z#/o ?x2 z~;b_p-&2gSozzq9,c1kTÇ_}YK^|wW7[=r=r=r"G,{^mG)$ȦdX:9fj ХJm  kLx4m]c}B5-퀥Nm,cj< w@b?-R|i%Z j+,B~5O" Vdѓdd߿ɾ/wXܝcyc@ߖ:nLt?k|#oJ<:O;v1zۙ.Fo,s-]ނq5X?!/F''yz԰ Ԉj竷-+ݼGSHdlc"=Hdw"z=c9t3Ԟڑ|貎% >!5 %YkRAAwOk,ke`R,t,}f=%F|uj竣{:*[ c7GoKa$GHVcߖu=mP50RaϛTSQ*tN*TU*trN*[9RaI S0 {v_W~u]\Osߟ]C3Hߖ 2m)3?Ը)k|Zg JS #>Ho8GmL`YZW' kA߂: ٸ)ʰq'gW߳+3kSJw2ysw9+ uawÅVv%$;d工`Cwˆ?ḹk><~3s_q%>=q=(:7M|$%<}XsstcņqA6g +zOlpJMcy6&H{Qdo&7DH!wGf.G A5 5KįO1į)`-!Ytoo5\~x5o~w灥XsE`+IU6_}c"7O8)4`ӫ=Ӎ3ߎCl=n=nG:&KII秤S5(|n\G:wjynunMC&7´ tr"k\Lį/yį9 XsM$+{qoN1~Ā˺8+NX?|?ƾ{S q7 /^g~Tede_6{qY}$gagwet~C:巊#wV|nJ:#'Vgyk\n26)tK.>xї_O_Ӛ>| v`}3䂹găW~g7g<ߎ{z==O^kW:ǵ } ;?>+AyqA[>ȏ\}\v7<`ӟ*1$}s-G| 7\M:!I|1˷Ynycundun.wu16|m]D׺ xы_k9įf_"G`ll bm &wF ΈL q^T >m|F|OcXdǰ^9zn/.~ ^A9>"7n^.~ g{Yw? ίIg9$ĀYsp7:8VVV -=-D'jNc-@[~1D%~ $p'"eχuRǁ28sq\}e:ob{aņ/v{ƷU_ sw{u_oy68 |ac]aҧ%7\N^y\ܭs^|[mm5޷|Upj;p!N'ٻHV [`}d Y&lnol}|%]b2=rKxWHpx^p%H1G^|Q1# {^DtYw;O!L%AuGZLַsEϒ?~Cy}|osw9 /Z=;*EPdWDHv"!_}Y3|5wHN.%GJ +_jo8!9SVǁl sw+ЫW6ledb~"?Ɏ&,s[)(\*Ћ+/&֙$\W^Hw^B[7]ar;;;,Iw8XqVvso+Yk>5a`aA[7/+S&l~6>rzʟ}n ;Iay]t /:O5u5%I<]}x5g諈_߅k󁯷h [$K $X .fu.. |_z1*bï 7]VIذ[ YݱVvwWobÆn&?gI~t׀$r)<'~ۯ/!~ߗu}xj w[4*wo8[J^ce[V7 Xz9w0jww>l.gvO3lK_?;_~ϝ[~vvwE:?!ߑ YE:|Zչչչչչgڴ'ilgr]է${!!~ˉx$?м+4 돁u^ u3`u."]{f&@&11_w<|=3/}vpFg¿87$ ?!:D/ <'=/!=$y-2ռ^Ly]Ay]QIҼ.sbԼ=&$:m::n_>jkI~^TͿ_eo}WEUu~^Tw>agJ ;UI3t.)_ȭ/|V=B:%oΕ3D:C׭w _YI:Vs b+{b7 5Aco蚳#{k^G{m[٦>`bl|6}?1Hn?!`ͅ \ܽƿٛ ۷a= m.VnU5=$>Ool-2~d?&oHV^y0Zπ.yxѵ:k_z0 N<)M\4|~qOr$)/)r/:9]s>%cM W3߿4>N9ο.lK09>l'ggi+[-agZnu3+[}d:W Tpr~9e*&눿x $_ӽtkI~$xpˀQc:z|2Wdb+Uͷ#r~)V[Hl$ɾG,[¿_fCD~u/0I]ܔ|D7%x)ї4x&c{kOe|IᣟƦKM,U`)E_T \m`LG:g:mu`poɾ0w@ {${= Y{@-d#IV-lzkr֜w] l<'~dĿxJO?}r#e:ZJCʔ[Ʀy+sq` h$Q&VÀ':(`1w݃V`CE=DEOrpɦ$;UdWf.t{k]>u'O:Ǿα{?c ҇~:೰_::ܷ9 6Gl%vsa$ ZCrq==s CrP?k{Ï9;XH˿Scq߉x? ࣝcvMhOk./֜}X|5P=ѡ VaV?.s>{H`Ie}d?ewkea'$d&D6 w5s')"k5o'JWA)oU*χ*5k. Xל=9Qs*KsR͹Jz_fTٌJ9 p.}]\.KܩݚvK~\t.[3>}o{8pl}\|~tk<[3t%#ϐWI;k щ޵?Kҹt =m _IM"RH'D\^|'@ _s#įk]kll@4>۱񹻉z>q[ϛ!>w'ܭM`ǰ{nC9.r]is:r5'jp<|*A"?~c?t. ϑ7H绤S!r 1tn"HAy<.:K#|&G"߃}W9pu7@FįZssg=[WwNwNwNy3I6ⳊΨTQ ^5G`O.UEUzYg0E=>ޏ#C~$>]H!eߏ Gn(~;_.!OR6t$Ā{D&!#_I篤 \NtuiJW_G<˝sb;P{^TyԷ0`iN.ż:%Y:: XE"gCGomG'ЯBw|ߦ}ܣ۔{i]FG9@ŠR.NjouD/#~i_E<~wB9 /%gSKΦI9DZ<6_P%IX{oڦ%Njoεm/\ٷ3Ɖѫv!${ɦ,4-N'ى${+#ڹKߗKM]zԫW]jo!!~++_z+HV>+WdBsHVz`RSƼ~]AzHv#%5É'Sj9ROR o/vvk_} 2'._!~6sE]R|-[/V_nXXXgX/Q_OkkkſWO|#Ez[ҹtN:κ&Vg]n-:kXuAYD:SHg.uԍZkJtZDu D/!~9^D6} kKIVoogj&C:iOtDhOt@c'zq1<@е~0?ձ@G[Ok Obo~u߭Y s;OFX`qGd;֠]ΓΓ 9t=OĀ{RybXis.\L:N=)269_OZvĉ=i%z׵7k 9sb˚9/iO5:5.6TgKwFz|/loUϚ')b=u'iznu"=R; NѹS}N%13iu2tƩc؛u$5Sh[OJ\IR7:0zN :=-==,Moi?&c_yDqb_vZjT'>^gSWaz٣g/&z`eFjz$'\1d1{.yI71?ӹ87d$HVƠ&xtS~z%z_'sЫoA9eAyaz5{;9sm=&00vl5 {5a%NG03QD!zWe_~@O"3xRGjQ:g?Ck=x;k.]sQHnzxF|*+G uxjH^Osb>9{Vcr,}}:w;dz2wSUcg=v@=<ưưP)׽X8X5lj='7=9WRV}x @, !7/uol]@s.[7Od|,A-:G/$~O٭@ V3`VԺ!;V=hanZ٭@=~s`h`2;+u.sE/$fijd>l^AZ~yE]3/]_0'o=[|aϖZ?a:~-e̙]elZ\g}RpԺVK-{Z[|lCt5$_Lk%533>cAGG?j]5.6gL}؅7W@?_tZr=Rz+ۤm6*EcޏCkr1&}Dg0jf9Q 15bk2f|||ѹ)#s7.Foo#|cߘv 1sbJh RW39bo 1p?5K]ͼXj&ޘzZ~pike[3Gw"8[g7zjZ枉>3zwޭ_:<`Nh60^}f_IZF{/lFc+.{ `YLkYڢjrsPkliKBk`Ժ&_*/rz^(u`-6u?>=nevF1ZnM$^hۣ4AxM/y?^NYzOA"3m|k:\˅֦Wس25 'ѥV1s+p )"I#O&R2mKl{ˆ!"QԺ%`9˾,{5ģ 6j|չ }Xcj=5X&v@]Gc(1l1h]*s|Xa`i3Ot.+Տp`.񔐬և瓬(ڛ'yt] Fn'}l;?v2&:/Z_gdu49sj/u.s&/ֵ\ܼ25ÂQ> lz%9zmS05WeG$5n&JMFߘillj]8czNS65kď4x|Aiߤ5oz.ƒ>6\ƞ벒@>'JR/%[NeanˉxO%H|faMo/5' r{ݓ":[yd7A﫠uX16hGp #/c`c{[`ow8j]G{F+Q{ ̷>|;P:cbб,:Xc`"YӀ5zK],u5 }orQG<$+sϊ%YQY/y]`.g@,{_O1VS]X_\}8j݅z5` 5f')ej݅:;G^IpC &./9 *|^ezez.^G.{/rd'+)Ժ BDnzczNSv</|\fa$3x'xXU'_Cuo㭓<`'|swLPyM<=5jv h i Zs9y@/5';~/q=t.w=ģs8xI6I0IVl=\J:҃Υڋ>z=vYS?cX=+Yd}SﻢXžjk/#ُ8$_LHk:`SO>j>zQvZW'YSgzլ rY: Y/苚G]jv #1$-91blͮ .u"7fcӬAxf#/t`muLΥ'Kd2ON"b3AGgIN6j]uM8/%NW7szuίe#_fe;Y,5 {E>A1~ZaE`ãf,[] 1/DD_ݧR+rЋBtsgN]g'&ہאZLNÜI li^yq 慙k9KO3X%gpG9w:!m=QR73~ofZ|Xc껗e 2`}г YV J;vja2?9oK6p_+;gD;/F \Dzy\/,5Ou"-}P9gu\Y,!p۠ q gtXWmַOuD/#Dww߃=gwpv;i?Xss`.>zti`.uCX!A?΂ //{K]kPs-Z/ [ќc'1;MCע^S5x/6-.6*`QoF5)fyTmon |'09&o |;p fn{vQoڹGo=j{;ji;v-ڹl޲{!v-son;[ζsoY"s7ڹ\d;عνv-ڹk޲νc*νU;VA;V}[%ڹc*νU{b;VrO#d=عzνvٹzν՗v[sou~={tk;h=";AvїٹGڹGڹGd}xx-x@EK<3zyz/xcucl=x 6kσ5΋緐ߌ2kYEEzb"Bc"fNxgi/<؃t S/<v|-Rj{n{e":K#Z#z6 OqV= zkSXsdfM>9/S}}]3a+ e!k_xG\)dwC~P_7Tz_ xP=ӈ^evJPꥇR/=t ?\KkWlieacg m Dzfݷ{tK|B)N`'7 /=2\`rNO!͏GuY ,$=z4ppՇkk^H47]'ҽDw,q 1q =UVGd[˽V1ꗉRr{>q8΀g]G~!q;aֱ0`uGʞ%F8̋Z'$'PZs o6zskPc_4Gij5ϑ$ɆDiΧ'}^#<j#頾y1?_|afAx13Nx,Ay1:Lxζndw|{}ll:_%_r3#57g']sskL z-uV9$+3w*\ySםۀiO=Rk)raj #5gK,rpt}<Ey:Jy!Dhu&;IIg\}x[R )%=Isk8 `w:˴81:qND{c'; 9{\93z*ɑ_6cGFkpG޵~VioHZѵҵ6ӵvѵеNk# MVZmzkh&^MV$I~t;Zk=Ez]֗r-ԓ6k@7,gG=r @%,c_۪Cs%ȻHnߺ5v:ݰgtbtdYBD/<}d{z(3ۑ}y@9 N"xy މտÀ{_QNϣ1z #=mH`F x5CD| eDW_M `םw;K<̷s܇ݼ8yqV6 !Yl`[/nɦ$;UdWqDs.=E^ 芳Xʳ4(r&p{^:=/ɪsccc|`:3z!^(Xm^! InGi,kJuEM^^.ŏgSŏ؏n kb܇ǯum_{'q5:+Icuviiuvhuvg[Em^VgjҙC:H&]nszZc'.fޭL>?o*pk_sypߧW ."Y(΋&yd7 Xa60Mt^4Yv yyd:/LEh<˻ h x/ڃ]n .85ow9|7U|3MrS_^J/.HQkٵk sU:t!s"!:o`^4aе;pѥo{蓈_(⿓x>,wR` =LByW`3 s]kgp=xVϓH8yH/:_a?շsF# ?۹['ߞ{ol_IDbdBבl1ʾ vɾ̥ݲi.]D' ~x S_kGEįX}!p1J oSomr):\N5$[oeӴX/e5$-I+z&XkԷZOÞ=Aͬe+:{U9;'Z7sW};W !~6Zʦ;1 b ]%!5Kxɖ5]J`8L_KzZ'C{=u]A~'S}Gg?n a]'uI6o Lϩ;Yr9?%K^%k9W}%G6ɪ&Kl>z.IéՏQZ0l#-s̟\"F`+2u/XkKۉGƜ"p ԒlC{h+TcsP*׀xXm`s2QN Wz Zk,uN!O~;`u32`?z.1)3{/s)r5a\W*`}N ;VXʚ^n5Տ˜@(<-ݷzO$9oM_X~+0kDV`|oӋOz5~(^E9$+ﳣz;VO:֯bY<ŋσ4y2dO O9"|ě_ ޼g-<3Mc0d "i<_ >}΋_+_˚Qg68OO zڇ7Oϳq'm=Icϕ'X??686s!N̺%;^wG?- o{07@ ;xzDO%{ _D<ӵz}/5'`}W5D:Q~7R&jo`csc<+loSc v9bgGl^GDhtŞh`1G HVX@9ci2-c?R}}ԏDO"~eG r_&q {^~Ǟ@,U$[ce uMP*8ާSHZg~.g>6>v~ mY \!~4Ձ4o}=HY_ yfyA]A}As \Gs<9tA:"E_46󏀮})*kP \CZ\s#-x1`ُ5N$5uUp#H>x[#K HV5sMs%O ׸F HpK`A/ޠ?}|T|W+ 8 ߿/ s78=uD/#=R >GzIVs`UuG/|&}ȗ? _&2QkZcCEىt&|" Hg'JHg'ҙ!W^fkA;أݠ} : Z󱏻!ds2`Cէސ"ͷ{ yx_CV"fޓt{!Ag=Cb}><11\ l` ^!fy 1%4JJj^+!^+aVB]Ko#98nk͡k=Hz%!Ze_еZZZZC#k @AxC7PvZcKt]1A(pkP$덣IV937 ፺QztNƵ$[NZ_QsIͤgR_gR3I$Bv# O*~֎݂jgoe?w3-o}=t.|~l ]70/oӤs|t!esYtb;t!gaQVV簠 il2,g-@#b4iWk_ga+`YG cIVzX`ɱ1pn/ K[^&n3746$}KaG`}qxS) Z nMa=3ܛcæO/DOuy!zQ[T{ÞMrsQ߇*q [~p+;Ua]09c?zZsx+sx'sxOs1@ xb>t!ysI:.g Mɋ@P8I3<)/w%xi7~%N cMg.1o/݌ogKUdA78|/m={L|oDuo6Xz]KGWl&^+XIvOY |Y3?T=dY wD^xr_$~Y G&1ģ1ptWO'XNp!P/y=O~|҅cgwP荈݆ pD<6·ሁ#}&)l⍸dsHEd3#nف3IA]Hrg}3rZ4貦>\oSKn 6// $I$Kׯf LoO{Ⱥf)ҷ dC$[I$+T/ڏ= m*Js^.㙪{k.cҎmjȎm޷fjPm0MW| ô8;iIv 2Mc6Ŏa;isͧ1h?:[ӾlZ9Vo::zsNNN㟮ksHq)S\M}/a7]|T8 X{kˉN!e]Xy7SK_][S_]h ]L†\$x s/Xm1 lR6Al/).)V>ūllUtS c1pÌ(;f$1c0#ǎaF :>δ>yk<X9RO ou/;u X}zE׾E[#‡g]jE|`ɯk8poY{ޢ{a[jzvpuOk"$ ~Xu,y8t1JoKD}ʗjLC D0df=gZ/uFG^ۀ7 Fu!#~ PooAz#YّVvK=}Yȋc~?Hձ&z#Wǚ su#7koRcF<G72=>鍔1v@s\g]yNv,,%NZYC珳$L.Ϣ珳$ LJk\hm'Jmls'g@=̢3*h Uv Iofmq_y7=6(no0AkA7r-bulKTe@? 2HKA~E"&TZK kp=z"&| y503. k%_+\\\\k\k0*Ok-kkmk} :(:*GlqĶK_Zת__=ZkVx?oͱo/pWy<l5-/]vjun6;D0=" |ʏ[5?n~llu5TD(r腯"=l͞ [~}f5Xlc`{5c#Ge3?7[\ឳ< lfs{y |(m /Cp{_d;Nn)؞|1~nu֝<\J]2x4lHH\ۃ<l@ }"#A E.^_=, l_LZtso/!dA7yxr0.<kOW߻FtߖI}0ƃ@lFOP uN6wȃ5 rG9mzz\|q . `Uf\Y5&|ڴ`xs [5YAwm'<\台 ֵ r?OM>1۠hk_7GM)!59go߳#mJ c9jƽ=COgzZm l5v0=NO`ӳ mFMycO`}>G V: Ïͩ!zsۣgvBn :aȷ99"@9"("&9/)%c/c{R̠~|?A=!ru/PNRzi:}^"bF"zK\so=KĞ^= hc{ӏ[jzs]hq1ƲT];[hyEO!댾I"ȓh37ROψ%iDkWUE^M䌥毁-^ym}"7/-.[^ y-rpi[{ο[b=AȟW>ubx, ;c\f\=rNu Q[#c+%Z2v?Tˏ}(^?v/"Fmt(msMX\`Kب6FubpnG#F#/F#/FQ=mYw;"[`'Ҟnqx/6Edԓr)W2Y\>i3r Ԝ}OZ`׷kz}늼&EQ˄H7wXa 4iwU/4K|;B'f ]bm%z{=//ag8NΕI_~7pnj0D~7ޥjyn+r-R"ϑ3>_pm.kpwwE/ș[yșׁMG.Gؖ+l07PR56%s Iv\sp@6HJb_FR }{Kߡ  ƒ45vrZp3NyLs"Y[)rZE.o65:#?`_0֝wDnt=ȳ;åMio{b@gYZn}}E}A lx`;=g豸#ӏ6?~y_\mѳC|*z=?Qڱ5OדzדZIz=u5Rjm c/gKM &{  mq87':+p-k{[y0` ` `rSGW~,s 8.#[Nl97kMjǥv ____+G `g~ It_Γ^gZLꄏ\šNȥ]u{i{iE3ԉvZPg`g?_!gMx8^"#^P?=׾ijo<"9`m(؞R*",rJ"g/ox$n=D4Ԟm۹ֱ`VXf eB0yP a(?b0@sQK5|oӌ6oAcf Oa.CIZtuW:ӫz)bƥۧ:^gâI仮7w]g2ĪK9'D~R3&^VɷVٷƜXl&5a+ kW<ʊX\:3'Sn9V뿁-wu-.0ÌZQx>QFڪ3s#m|m522FVw]*}Y>. 2ޖ; 6[1rcr֮":pK{~ }>0k%b!.g'>a]!gGSԱ#b`>3L|l}\[}\fu7 yl |"e&G:Ue_Pf(:sDP9AtK3:usTt~#:Yÿ.5p`S6wr|o .zioi~iO'l?`M|SwF~gwF&`ρJ_yy</n?V97ǑHGo*{UèFq Jl$JuGYM& %j>uY7!~|]'Xj8iRc)+mo:p[UV6IWYyYa!f\hdV\V^ak!]k!]Z-+k_uZ-kk_eCMx-O l<O>o#r[ZD~X\h>%-Or}93%gK̷,qogno>K|Rr;l 1vč \_wu}%1x&jw-s0[[2&@ފ~[eFa p\Kk*z/DwSzP׵iu^O+ĆkU-"ڡVw}"ϓV OV۵֋`9O8Z덱ƞnSSc1Vc7jQ`okq[fؼOb^/~p}1 <4F~h5; Z͡_P+:WMs,|>r>|Z:[G֗x:[u:Q? l>OH9$N> \"Ҟcji_*mN|mu~k97;֞oLǓV3%;֙ۄ׭_O `I07hkTݵK]"-_갏kۤo=&}eߥ¾c9}FmcEc-| ΓҦ@L6;rXaՄXۻ9d<,I_[:;عs=SU`ώ~0/ l}l"I[ZWٷg,_1߈1q cN-5j?ecg*8Ǝ1gkXɼ'qerVooc\ f L?&] Np +rMicl\$}-OmoM:l>Ɨy潠KzQk[1obx/ࠦ ]dȃ^ '񞃹?kܟ{NB6kG@0ׅ`9=IxO3ޓl~] 6{^*cbI'M{\d{>49a~l!}s9F0FRlc|4OJMa>O^l VI7g]pPlsN0|]`li5J|)M_sK.H\a%ߦs$:`I p5n!„|[hA}^Q"I'ȷm&#߶٦fn$)=sAsO6<PWGKM2E~k0#6mЦ?t L tv L '% gbɵ,@,6&mB'Sipm R7a3#6\!6ogn$̅{ sE: |pK{u }9PO,}b!$S-&QOxC?#u0Qk 06VVo[-V%} ~i(mJo^aCזz 忞JZsԖS5sjѩ"I{E]vg-Ϡ+}-PNSwKQN-#=´J4yuu4PN|Zt-0ZNQkd{y*|$Rwn{c_`g8|lwٮZݭ^g;(ȵc\Eg :==׵T Y Ensv-D WϧJ{[CׁJB=?m 9Ā-5t1}7{cN=t.fتOڕa{  6_K|^G1~>i}=q_;vxkzo:u[#מo\GE糢3]tv9s0u. u6i?r. 5#"Z'E~Js_q$o_d^}o',sErζHY})3p-%5L-jע22"W`aQk ?_v/{ f/q藗 ;Χ_Η:_utR}oD Sy љ*:_9swq_g7wI߁|98A fֻ8CZ=XŞ!ߙa'[{i#'S`i0KfF0~^ ~6/_~ !>C0ܡFu~AW{j{gD'ی@@*:;ξs,:P'jsCM:?BN%9|Y"ϗɕҞs?l0׻sK/>fʙrf{ײ`C`9w4KJ cm,;̋}\ f CYB$x/F 1VsBt \)KG ]G ][ΎEgSmurvԉ5c{љ+:G)s|:Q?w\ lO2dUgm9|2|/#c<넴Oƾx׻dg}+-`Xu˳beׂ-XuJ_yQl|6<|r3QxO//W+C//c }*2G;=:ٽ||Bt>':EK'uP'ܗ{Qs/:_k .gϭ]rp 3'gO\O'k%{,̖wOf[< fs-K lp7x*}J_纑9-lcypC^7_oGw6緣;] M࿇~t'/N:2uzDt>-:SDg;]t=2u{d4HtNsEk>uo u6yr.1p-';(xO@FbsJ} ̑wOp-K~lXb͕Xs,\m[k 4#w5NA<OJGBt'~9_:?~4Kgu끝]'Egl#:Eg3:u3:u#:E+s|Ot~Dཡ&?@nuKsR[Z3ios`[I_SJn>cDγyeɉ`$[!};H_dm X*EqT/ Uড_?KP<K#_,K/B,Dˢ3WtD'ύG ύG\ѹRtn{Dguṑ&]? =ϋ_Wy~>^lY~%w[6wv;nB_wnڰ+2/6mCv]WNu}N]o/g_w]x[,}oU2Xg6Bn ~[#"/Ӿo3&rnp/rp<l1ըuN>C[u;< Ui+p+h+fݪnu/(>[TI_uPҭ_$s PE /'WKRic,g6YrVj%OǓ9g9`6m3.Q7l'>Khx]7x]ViKnK#$#v1l_q?ayh8Q DV[.J{{/g [ [C-coISK2|-couD-aprlcD\-(x\W.cow:Ōu`+~FyYփ{T ރG׃GjGmqyĀ#Utv}EH9Yt<&=$p[ 8Q1ioC~wՙ|<,-$ Z<=ig3[[`{|6 ꖟhß?vyvh+S.XSnwy3_t2RnwÔ(TDDr/r'fp<5@J;0kF`*`["gL\(m8_R*Y\.6' Ss\)10QJMp%J\CG)ׂm/"Sî')y1| x8XsjQ8s%wE*fĿɳ͈s-}J_>oYh?䊞&76Ϯh97ls9mc.|ym}5h/rIf58mJףͳlsV}N.sV}Ns}s apS< l>~A`~YΧ_`g׋vv6νKy:{GoG%^gx^gz ggMz?wF̄5|p"_.m.oH #}-,[ ވx~A a̽Obp=LfH_%``{ "S*z䷼7Xo ޭH [Wx \ 6>jvv{38=<ws_W\p c_7'\<.::\uN}Sr^g[>:<&:|q 68S w3ȭ~^ NyCiokFp3io:p!}m l+< 9϶b]0ꔭ`9϶Bγl+-6[Ͷ l"Wo=+\J9`U1V2S>3S>c'5;>0ߡgwkߥ`w6x.x#a_ {E7י{י{יoV*|rܻl.:DnPg`VCm뀷|wbwOoF|7+6oV6U oƓ{E9Xf+oZ"6޴9ulc`أ``3`>5s?2?}G {U`jj*{_eb= z&v XQ*b{U\kb=#*yZRŃİ]͜Ks`{&\V{ć|K0'_[En2icii:<^mϐ1Ʒl\[~oٸsM޲c|Ǝ1e|.{=[x5@y`GSm~ g&[X\= f=kyȋDn5X|[|۞Zk"!B0ǰY:j9gV@z+X+qM`o*k3};VhЏ}Gv]ߑU`Qw]"}Wocjm~Kn싘Mطb,9*sWl 䶎`YZK|^ +a8l~~eM +瓥|x2x'G>Ű ߯6l>8CB{y~πs׀]?;~+:GɢkG( 7Ef<(:RgX3IS 7bNmnNwygiu!=;åV.=Edy߱fx9>߾c#}}z}Zm2hm{m.kZ[vkZڽV)^Za܃ؿ`/.B^{]Uu`M\^D|_|. c0? R'fzb] 0ggqտ8؃c=3?D̸ZrirrrrrV^3S Zykʋkʫke 6pwbCn8O|f[y \"-O ^*W>I\'9s5`˙5}8_z7r}܃`zr2O8`w5Gf_<0+xJ@{dlb<~tyEFѹGtGE'o5bV#\o^瀋xjyzxla` ;x}mMO io.pw3 6X |Zn/x @|nsk(rQo(7m:g pݍr];ܸFXp?G x4jw ~nB~/|'~_}C~%yStnίDODNgy:^u9ux3'ΈÐs{D7i~c ꦪ&{}&{r\SƓV N6sM\e?G=*nsrXn7mo\wRl> ,V([VW`ԥ'G-Nuɫ#q5C[0VG !.!X Rør#0ncȃX4?3 yOCZ{Ðr J=V=={8$p\ᴿ{aP¼sCy*9SgAny|뉜G<0c,u>8&JҦɖ6`>SJ] .=B<_}֊ "q,&˻f]m6 6bߺ{mvϝrvt&gGY %=nvR>vُoϕ\S܏v m|]Ψo=9jWG{N}\UWςkInIm OX5G; ƻÞK`;,~^yKjspgt;[wZm}Ia g)N{^[jc|SrNyfgNc`104ԍ;۹NY_vS֗4:z. \,GyDs\8XM |><\t#VžVx{9{*cQ`n`c vM;\Llq[~ -߂wo[n-x7}Z.{8awOM{j{SÞ+/`]!ziՇoľx Ҟv7x\Kl &H_ε4A>䫏JWԏ>̵ >iwo woݛC3!"E k5a]"iy쉆]a&Nk 8xU`? mίEO^Pg u^|:υ: MVk>HV&߻PK=gҞ5^Z#0c q=Eړ2>{NxHk 暒o+Oj}11)èxQ?qx σ/ ghpCel ܈~y8. Qag7Qag7|Ft:Guq-u"gpԉ|5:sĝ^GDgcLtfP'rڈPg`Ygj}S9}ھ#"/Ұ/wڷ8|51 e_+?}nj4>f [pBDuǁ[Fnؼc'#ƃ_K`N`_3ߣ~vs#Kaۺx;;rw$0n$0cϳOAn }_eҞurka"2;b}R[~~B m|l}\&}ͿGZ ,k~YZ?m 6_y/W/Us\-r@v>'`9`5>r=("?{fPuA"6Q1QMC-QCoMz n"z^6w^'nyAQ)!_$R "1j_-D_ĭs[7w?"?ןןןן/ ~2%1ߚ߿O+U!3 y ȿ׌ןѾrp1QOk*>~sOm =;p].}K7~c=]q}yAl5crG=/)!F9R)#~3qc*wQˍ&jGcc<& Ɗx8e0pmm cf1sc1E-c{ >pO]1._³Xç+ugEY|Z3:g9۔E|JMn/ڑ 8 fܦ7w e<e\7{;6[E^J;xxo17|:e\<=(EM~ ;c~cz]0םt"?6FŃ{y;AyOɾI`=ڝ̹bX-|hC{}:R?jir>1gU|~%xϭƀm?焇{>\ᨷayp]o6[F`9zXtx ӯ[Ow`^H6\ 9E~\~/ߠ 7X!Rks 5d"7_o%s+[l'W[ _iv,d0/'A-Xp Q˙n tw'=8ꓱ΍9ec~(CoVҷ/}G/j&gc'rO7vJӍ-DD[%l<mE*֗6nkak7t~;b;^mP]6}f`=l$ltcm{nAM;k w|;>2rE"o*x-O~SF.[NM}!OW`C!|%92WCf-Cg7y͝`KQ_-]AH*pN ^}M:Z<9u3 7)%=x7Z-d3˵ɵ&ɵȵ^kk'Y5ĉ+Y5ĉ+'Vָ]5:qkY5Ğdzj=7~qOk{A%$#&Y5ijdzjY68iH\Om-^6{^i_X}~h$x05 VsmM_ 9.69}5x7e̯ *ׇ&c?yMNjZp- p6g}ccLf` v@ Ǟq)xCo~V'm,&"o*r>@mcr\n\bcp)yxm /m8H_]?K].ϝ}9n('Mr]yXgi''J{9t``&Gm]p^!X֑QGqA-uݸo!.RQߎ)\q?s *}ǟ;zkbM7Qs-ԉ5|qΏ[;1q;,} ;\29_2X7kf7>1!>%RQE{uš`g7~ hRѹVtDעG |uuNp9!uNuN{^L{;2HNj9!ApmבJ{z`C&җkhF}p','Xd4[<< ^!}2k0-rwm2XH&:6Ae2>an݄s#:ΣGnK܄߼Ή{:':':'TM{M&68#~xV\3E#sπ=~` o9|g;w︆f<xh^~ >^~ msD%[=5xpEL6oB?ML~~~y= &Atν :P'\:']uNTt9!u u6IxB_fiox/#%e},R`=?p-h xh?8?8?X<[ܾ<lcFx&/A9'~΢_J-V [$;IkEyHtyy>ry>r/:'_uN|9|: l2 -}"q'+yI=UE^M[%m .\WZ s'c>NZ< Nr- xu?)gOZ<[- hcA#䧣f7|\pwe lރ~)_s藕^ @ &oDW9%uNw_#7}ܔK)^۽)E3Y4dʳgȭn)7QDǤ1;s/8N.bG[?Z< ~~nJbD?SG/`Q\p>K)x 5 즼O4oe,<,:ըknaYxYxY@t>%:SgE3Ia3r[ E^D.|?\*m nxsˌ!~x@   u}ߟHDklqlyl)Ʋ_5^[8w ab%s7su/+A`o^St~.:xS/:Vԉ5wj s߼ΩySON}T} l25yr["?%-ĝ۟Mw5|S|l$"NZ8e8e})p-%y-vlcj,jqSo3u8x+闅`~cgjf;S7W/;Cn.[t~!::EiUi;iW{j{gD'Mi6]`igVȭn +r "o(-7m;җ2U/!~眿XmC|_/}_-?[[lc?--jqӂgk?Fߧ_藠N_6w/|vv/ADWGs9^KPg IZs^D瓢yљNO3BMg?!8W?y%Xzwlҗ32߬l-X~M~-AZ<-n-X~#Oϊ}|`?ӧ/K`闷`!ߺ~( NΟ΢J^ge^gѵ^gѭ97Ě[tY|Rt6u;:|F9}qUO|/# .'}G*[O;-zOp,̳{n6W4v)uQ1gum+m#vV;a}d_w3"} / 2Ϭ ybBs>f^^!ҞͼU6ܛd^.Y,|y)̪``wDm,nFӄHfG3RVr#V}V/fۿ1JΐK/Ff%}Kҗ }vÙ7sE|W=3\ڟ6GDW\<Uz]f]f}p(5O`ɬQo[fe7Yaf4 kV&35 cwfa8_\`W5 qŷK3d*RxF.>"^.^_fiG6Ma>6?sl~?+^,VYxwwg,}otsl:ܘ9+Rl;U3Qv~| 5^cpSs_4fM9'lga9p;mY9a{N[ s/m9 9v v;'[>=L{({(uw`K2jUz%[Fmj 6_79D/JK+58[_y\Sɯ+ ߂9/nV?{̷06]  ׀gׂ#??r~q`-C{Xgh Fip>`0]1̢H2;? r)7BH#7;? +f>6X[g6%hȁfJJ! +r767I{u`ype XrԹΕuwoG-gVՖ,(sk웣f7|-whfnZhKk0i}O>Kw|[tnD; Sg s9 sN99>D3'3໐sfmݜsfIפ:黝}[wo[NNξp,yNosf .9yY":w =i`TYJ_[ɵ묳GD'떬M$rzx%` qRc N*8\mUVK\*zDOsod]o.YqR] 1ʺyu5s'B0s~u`Ss#Q{b0&ށ=D*ro)#W}.7Dr4pa䊹A#ăۓ?DDѿJsF\\ƵE(?'Di_RW5_r_R/y/VR?S%i/%?2d 9Ys!6pK{aMuG w;{]ޅYu\3f f0jŕKd[("dsm:-6mfh+ݕ,Y-}IOW=`= ZΫc nc ˼?Z>yr,/,9kz"!ͧؿ_xXڛ۵E.E9$ {~e57o<y>9< Owe=?}C{6Gg;Լ>G95oXNEBѹRtn;s+xu_E^WR'v~Pg`Wq 0 {؋̧{^t˫ЧY W,*}-YV) rUի4b1_Wa da?[1 , {*܇fa_Y}Qnp~"thτ6%w m!ݤ;^ >n,.Kuҗ5lFNqϭU&W}9 io7l99ib/g6b/y}Ŭg,} /봬`/m]ȇwE&nws*}8-szhׂ3B/Η>}9}9QLEg9:^,D ɢs|UtQ'֔[CMƼO%=D^C\%kKeػ3%6K2/la?<0)e Y-jcq nC_/- $z6\xWhÅ7›C[an-~H}a7Kv}ط&8}1}Ϙ +r#E~Dۺ<|Jڟm.;,R߱`ǁɚF _΄}>ZZT}1].]TKer=a`,慐[^^-R4foҾLصf? >jF࣪W,plzx>8G>ZJ[e>hV[4B]4VΖH߷58YT*}wIϤ<<[1gh|\$r'K ET[ \*KrD[ի2˥yl[ &ױ- Yh/m{%{e3*?)}ҷ+X܍}'P;Ab_؋opUe3r;s- rցsD+-Kic5&6]V}t= |dt3j-9{`[b\s6x} : \ cw\ cw}\.qo6\XR[>,}ϳoY7˒ΘG sMEn{=3圽lio>l>'}m X~o|嫽.r?{E5 [>[!+p[تyw~_2?ZHE-${G-얰ݒEg\tu.=\zuS'bu^қΥwyKON2~,eY@n<\6gE^(K` y^?m|jƏ`]?-Om%U?}\0~ _K(<78F /|n;|n;E{׹"sGnGnU^ۼeyO$ڴ,|&Rس 9}\fӧ-^i9#Ҿ\pn\]{VS ƛGTI(B(!h0~)̫AHdoL.42Hˤ{jHY9{^k/`[ӭOOg $H8D`S`\1z)8>XkCKuhCKq0v7U"NdY/>n%Ǎ)G^v|cʢ ' :uÄι|?H~`=˅T?,st˧\r.'\N~jr/`ȇl,n:3Lɣ-|3MX\#h;Ǵ!VOjbx2 &6[l{Dن7Qsa"Cd<6Χ,2ZxЭxm-(zIUe-wΒwΒw΢'s0y n5X&l,nGG@[U>eO??Dbnj%$I| qNzID 2 21> z\J\ \諅G¿Gx̿"&&0 +w ~@ޤ*fcq} gV/>IoH[cwJiE! (:vOELZ(EvHM;c9|L[Bk x(~9 p/1y-"W>QS˥㉫w]1#1,7W/mMgEho^ f0vMm~'DȾ(}7}7o";AdSv,pE(w->g{;XKwcyi/pQSwH`~`[nq}o~}~jw*֠?c0vWނ>Odۋ"Y+,Ǖw'E@dK([\(͘[R#7&t)zNAo,G M9j9 >j6> RP7{>9umRNnqr)BfDRЏZ cwhU"P'ɔEL>NًEjʢ|M(er)]@gIn| 8Is@xO_)wsޥ-pNj*SǺ%c$ڜuKʵ l^y{/r^0{3Rr.3h5=0(0&Ucwp3->ijNKq\y4ޟ+'ۼklA";Ld㧜 L ra$zE\Rb{--=\ &y01";Ydٟ)2vJ7w7MOv&G;yj*oцSC[anJJhMI[#k-g )kgB#6g?,sV |~B!sRws<,9\JN>r_[Nl9y0)l,nS%l?g+hڧA0e?꟞jڐ+J~SOxoM=Yz1G_|Ån7xӄBx,>Wzs8Wz\CRcƂ^COE 2A uSYCbn?X=ȏb#G1ur_{SmAo)t=g%obokٯ1;_*6\yE"3A-EjAgZ9P-:{h!߶o[X-m ̍Y,R*̋1 11'p ç CNÚ8 NYzZ;֠iᷣ?iwӮD#3Ct3ED5%9Lt~&:Dg謤No dOdc$z nt3pS ?c e+po'<6lp^lDC_{"ІߢLV[C}˽5}˽5}^do"DY>AY>)}D%}1(|;Rn=AB~#cH8㽏η>::(0TRKE}혍}[G>_o7M['O}~w?^Z]G_z!pknjp(9rSBK9s,:Σ^=ԉX~99"s^E'_7`MwgSSR^ 8S;_@ :8/z; __80󀙓Sу_`~o ޘMB_Oܜ6DMO=6dM鬩.dlȮ͔mӷA/[QVl*x-KE9f:mz3ǦF<7XXZKVWj&0lj.u`j0֗3b6Wq5w*n`>HNi+Ê =KEȾ,o,w>aWNٙ"˳K٥ڱ%A"sL} xЫ|Z \-滧ه>^OKzJz%ڼ{֗-l}d1>.p3Oqӡg\=A~q p#͸% ft_.":Ht>/:_N3^NEǢsVtR'vPg`N`HWn t˷7zS'~7[[[[ ׭-lRwx׌176(_ mYk o zhyVcw Bd;}"e?NY'lEXs \%tyQ$zQ_y.<冏.Ev >lV)u4_`\ol, hl! #ڇ1^=wcmϬG~8#kMB$xVK"iuh|| 0v7Dڪ$/;}^IYwv{¿D} eNi0&:4m"(poCo_dͿg>pnS}׆pYeпm|h[9ږs6)pq3`ím\CbM3槆~i?}7h_Ox_E7"ag7"ag7{Eu6֢ii2'n[*t4m}i+p.],l[Yg:{)v1wXcv/aB^>| |ZK |Z+ڍ<~`/A/c}/#{y^6q?F-E X[1 ct^B/~k-w.Y{U.s+ץ_\/ҮD/\^󲗵YrW'`7۸nƚM1ؼ}_E_MG!/?IΗN&~;q\/:wC^^ |0N#7'uiuιsStD`93o=B3ִ;g }iw/SEXΨ3j;=^`Zi=-z#y$f n;#;h ɝ[GusGY(EvZỵsν@Ԏe^ۜ l_趞> 6g?*tiW F0m_oyso9c`9^=w'{''~l190^eݿz?oCU&v T@U@U(CESGj E]GChcY̼ _˅n" Lzf`B:pH:{Ou50_zzuIK;`k;,ׯˁnWW_rM6Ʈ{&kF]> ]Ԅ SB$najȃ-LϷk>9jal0t~[:ߙ_8?yv_'݁' ˘z k "k-6œ>0sK-5^s#/9v<e0^Gv;3dg>"3s`n`X;:k 3W ӻyzi]_Pw1% ]l{x6?!g#.fضKC׎tb.j ; ׎ ]f/R)[E5%# k}Fpޚeo*vyvϨo/zF2.nF`U/q] ,{ɞm^m6/Jyvp#6/=`K{߻22 3Q u 3c̖L]N{f^\J|14WJg^ ,}DW#k1jۭ@MxCDM~{<v#{oy{ۼMnO6/nq Ņ6/Z[]l5'lr{O S׷K.qxeoex;x;>10;wt"$vyIcRS!z*EIwXDz ^^;-?l93p;eNyz~ɸɸٸqFftf dfy"֚wyoDŽn0:8N"kJ`;-1޻Xn 0s]&z,o4f~DvjW }Х;B];xyQTnэ >zE݈;,z8RPKg| /_)">OA=(ol~Avc|.!:GOO?^`u³rmܢz| u[kgܢ_z=Z:%IUI$3e^`\|k[<;`{{ X_"~[t<<=. x{ sAō"|vħ[|6x6R[ Cbi3 jY| x O%A<Ⱐ"b䙻 5@faB.+\/2.~S'w{&wK>[=̇݀9w2A>G={8|x{$#9Ɂ0flc~J#a^wyݝ5dCA3Řϳc>fvow$跆t8Ѓo/[-pW0Gx>x\#:^ΟM?7Nϧz?u":N̯ u6~>AНuB&z B3;InB.z^dns#\G2ѧtgd"NuKD'!3S~Z|^{1zL&Z̠_WGߛu+9ljVf=W=bfss_0&܋?&X 233?x-pp޳+0(ܣk/gkr/kr/Z6^+wV\)Kr7Z#Z| ~H=wrJ fr#ZKN䵰,9)V% 5u}3Q;HWQ_/NDv_;o/<2Y X/}ּlp`#Fd~ \q%žC\жKn} mжK -20vI#/,%V DLd+(xe|In :Ot Pͧs?&+B[z":I3Gt:'n)#gj#nuB Co~ ֝Q`kE @Njyѿˀ7w=^z^Se\\oOn=_eE筢|BtR'zeφ:,8,Κ!,Bg.Og5N a~j, S`JjNu"/^Exx*ɓIHe"YxXeyi%hhC;/sq/Cd,Q"%"۟=_ e,u::Y{d/tzzup'xp7 Sznɺ XΏ=DY]#чml aywa9ypV7`ϻK: 0cfgkYuI H<] v 8+=7ׇB_na5#^犆^ uhuhunv+n=D瓢@tAԉtū&+^c>0cε,4W?K<WV*emWjG#rfdT`HfJ.qDf>"g3a-u+^?&ם :jo3γ#3u\y #W9W'~_= ѭn}3Et~s{ sNtVs#u lr3|ޡY]n'#sXxJ#``9KuYo[ ,l<O5-`Y5Dhcy&ނ=D{j=p1DsD}`_qVc 5b喘5xkFM)p?Vu=fXg(nUOdD6VG !ztUԹ@]b_UmC@P$ y[V1_?nyB}BO~=Gxlg\{ypm㌁j`[[D,o&~,fcq/sFGbMb>7}tv Xμuܫ̾k_v0Ur]9'z'OI9/d'< 4d`III=O=|n|3p<1d Be7.<̀~e;DA=l1Z4x`֟وB:}s%.0~vjIe? W[?!λW !_DwK#.W cR07r>[=Od&Cـ<;Ξ ŭfυVO'пߕB5bխ9 <5_a1x797A<5ִO/iCAoR?PK_:b|MBハDS,&'7zC[H:='O',<]`۩>)Ⱥb1Y1"g[_n |-Dv)A~X )0o'uȚߨ3 'bխ3Ī[<[o͜ ϬZkIxpkOPCѭ3֞S璧y/C`I_-*#[C-ӗ<KseHm!M6]9X29X2X Mj ey1[{7 jݵq6:B? |kZ~+cwk ݭ$#D [w`v"=3 L[928rPd:sKο BYvX$K93Ü>ʔw3rNfɉ3 ̜)n-zRŭCsruCsN mVO mkh+ݭ*CdE6SdlqlqWE=1/ Ʋn}dvFM+wfйF,z3栆"̽9 2{sPg&=L~HNH4i ,s3Kf,m\ lcDߔ53uKa asCW6:E6UWu^ UO_fjuV]-:o^3:'28StD09RtSW[lR[`2?bΚ& ӏ9ٲl˪³GxdQe9Yoȹ8jl_[<|($べ?:-b^6kmϬ٫}fQz*^O9QFAcc :0^`=#>JeB3-o?lg$k̾#sn#tn~=oN&18I6Ӂon?V`c1ޙs#lk!UԙCtV{y1/̳9X&:DgŢxuT΂H4p!0Ϫ 1 jO $F=\8XPVU#{X=؏E磑OzF>qe7V"wrs+@[јn=GcκFkp8AO ^ U3:C=p9p\CodpZL}|y_+j`捜R ^R X->d=Fn)g?HX`yc-w+%9BF<6z#7:sHn nOG3aM_KK3A:>~Ԯ냚jiWa!NWA|DnD7!o/B{=g-[f8/ABNzۺS\,-/ l{B 6[ZBW(~0E.9yV~ooUe5пAY%:w΃^ :7l|6l|6unܐ :oN~q6M6$]܆ӿg:Ӏk~7n{3rWf}ްw<1X-r{3f-yޒ{36{%{}>rѣ C~HO}D'kKaOq[`RbGńHn07 |*gdI$48;O+Aoܘ|ĉ۰qU 8kmtZmlﯵnV ]!ZIr\ֳrArarr-kgZ`ۍZbjBg]OkNH)[5L)G~)Xn`UnG` oʽx}W JncD4p#jZm\ s&6se='k{k$l61On^ϦDOSnY^vKkJdol@˖[?t˥(t[G#jyL$Z{b[Gb#5Un_`'XFV_LquXܖ؇_m22ڪm|c-"}o,"KdRy~ߡlX㣁' m}NdRCr/C`,[糰[1p[3 ?{Ra?\xJ?w;G|dt>9;ָO#gm>K`䷭_l,nk|Wsk#hKC[m;>էOۚxm-E+ m_QmBd;"(e?c?QޝA^wB*t#y蕞e.ʻ8COO?zӿy=Ӽ`L`15UĨɟ|̻72`7HoeNλ X;ሙm|5;kv@ 7QdN_9ӗy)|_梼km=lYg0>P×pO\l5d`gxB=~#< r'~Sג>KF}Z. l5t6H9`s?,t9 1.^\O)B\Xr`~"z,w`sL9jJ`y&<ycou>|>u>@kzw)3GtJ|贼x+:gNyyy<{jM V m6_#q!`h5 iD>B<{~̫:Ǖ#0끼ysqW ̹~̫lc<~?ꄿ9ܿm.0G;{xȫ ,K~g{YK?U=`q^?~y6;lurZi_bbkE[kNf Sdl?-%)\ \&P!zD#kӀ9Nd?%y͋:xpJDO#zXl xxٗ˴m%^xx`6w.>CvpqBo tye|ޟ?9o _wzw' rj CF{Ȩܶ"V,{^Qn<"0im7Qmo1j!_) l?5A ඟpPnw!VyȃmGe/ y! |Cޞ` bWM|_6w.loz7:ouޒ:~u"~ouAtvE'Pg`s@[Vu=B~|Pb@C?T>9?1ci@KX0Dtrg@ub:>kV>C>`0GMG߂~>:}YI$?Bm}7G!oq^Ӽъ:_H?;Z{;D3:kBMv3Q{ 4/t|[ s oI7Qo &!%&(@m2Qo d?\dl2Ę?XM1HjAۃ$YlG2"`v~[`; bfg㭄Ha(ҿ#Ӂӧgѧˁ0~8vp,:kΝy;O:w:s'v;yMtI3::cV@zB"|x5Fᷜp%0scU{DrcHՈW-yv[<#~^gJjr˿k_ nvGY}uZ7&`՝㉻ۜ%?fvv;߄Ou|s|w/aUo;/r;7^8sש^f^.4|vkBsWGy_t>.:"N.MvnyDZs~ǺZe{Mά&g^@C=-n#{ nQBOz7wzz1luvs.8鯯{i3M[6wGw=g^POp#>}׳QI=ww }?秂νB)tc>VX>%zl[>^uK/?8y+ m\O[ /Fn}wlvga<.N19p=DÄ>\6wVOvGnɈa; xV'ZC z V焱1`~{_V'ۗ E?F~ ~ܾDrѿIzէxgQ;&nMY/Y-t3[ ֈ{^-vlDCm}>&^Pkju6`G*CeuCeu pk<}՜I݅C=(t)j6\uTw !}}')s 72N8 U``P߉JѿJop5Wo?߅5mmߠ3 բ˄^.\ W ?jAp% /BL1|y8v>];{8W):SD'׋̷ W~"0^p pЧ B#8y~?8y#eL(.?AL8 W2NГ_ ׉ ^{MI<ˁnO9>n>8/8tCAs,8@}uA3A)8 9)0z]l!>߳!c f^-87}?eߗe}؂0EA `O=D`|x3k3 #N􎙝݁!a 7ȇWҿE> lRL!B!B&#n.~[C{;T]36 z3`߂@\̼| zs~-G{!%GcõV二#8#l^E~)] > j&§|Q=3Ԗ[BÏf+>x^_g{]DC/N!]uuCt>$:Eg>u.u6~ tЙ ;=Am,!V''%N>h"N>l>V?~R.r1a8å } Z#K[{+RK/?1s)k~.-!F\*՗D/s ї.rFo;5s# Nb/4S,7l,s 5-b6;p>cpA녱s9x3:x/z $Z VoV?rZ_ȵk;lY0tw D' ͣW 4Xb#ۗ@}dϾ{qNl+ sO`X$1Ӄ?l,j@3 mw]gPh jh翛MiD )܅IlOMBb( w?V0t'{ [Y ecY7?uRlA9Swl,GG[M}Vs'V+^J[^&D=9C㰏;t=t=BdR6Rc9t}d19#y nLB~~,l>4~">D||pʹO',DG>zraqH_g_ ,kHYG=eF/{s#彈O彈O/m~a|5S3O1Y C#f}( {X1j&cl,P`u u#o u#]uĘ;#ܡyrrrZ7:_0sFܺ|q:_Zk%ɵrZr-;l{V֗͠Э`[C_pz`0ށ1;<v[";/ݶA-uwoyqyqy=GNz4z\zi Uf8G j£;gYO֍D!,Or$/q!3~ O Of(<.<VHt#WlHlx(ˑӞa7~ȻGiQ%L=B{>Ds5$3G,=D^G>/(da:pkzq0Y:|I$I 1/ B^lia?`~G~(| R\w _f,6[xf$:0yg(s51p#s4raSo%FM؛˚5Z֬ѲfUlqx6Ye-kf}nne?&=E%0si=|>L9g*ʶ/5/ۿ0Z8L={.D/,P~OcKW f 80ŽQWɵ,l9{c'`^ "+Ͽ1f[{͏GSc̏3 Dx/9ŗK!w3 s/9ŗKyN{m\!WxW2ǿ|Mؼ~c-Pe_`bBۺq$5\p -wґw4َ%n|-p"|֗ }]GGµk;ך6Ol>'R/ .F:jRXy>%4ȃ34R[7 Bw <_g:yPs 3sG+S<ÁO1OQ~>rGW#\[_*x[FϹS~kˁ},t˾.oq1p[n\lqk_D`yk9SW`užecyٱV_kvXltl7ѓ#zE[j`BkcLj]"6婢\03Nc~8F`PϏ3_gvF1.130wEy$kl8l ԁ#w GӀ\xqm|6< /0&z?;rrqrZZKZZ݁7Z=7ʵתUT:_N+:Wk LضyN ѣs/,ۺmY.tU:޸XB73x%x3s,~bY":Nsп~N!{^%tׄOz#7zS uBQ}6M1K:鈍I^0Ѓ6_'W3fܾqoqu: Ezѿ[66ƨ pP0c^*: t:[>tBSuHѩO5'E&H 9| "M6؛^Y^sYY}VYYE8EB=*.Rz˅>MEVG/ޝͽu{7cnnI0606ꢞ) (x8pCݢSuObi#?;P?k׻w_V}1~<ح^ckk2>QrbC7~~Ƣ -.fOTsbc1v)pW?B|N9Fe}Oc~bS7M|)'I/;II7MbSso$}$&I4tͅ@k\Iӿ1XMZmNnc5@'b3 FLλzdܢ8E 1-A8EjzGj넸%a<5<0N׍׍_7nܭq=!͕m,\ r/SK庿u___.u/謫+D6_^H+-:lW"t[k̹Qn/(_(wPON`{' m~!Luͩ ͩ?M&'zLsd&8x pE~=w2sEdyoON)Qу7z -&B"/rWl:=jn\|?l0130 0 0JR>+T*S8Q9J&B5TU*(EQ׽u}Wq=z׏3ǒ\u%Xu983/eo_־KއyIވycHÚ~\kEdvA<s2P4ȅ?5߶¼o[a^{ R+o)IDn֖w X~kw_o;cNy ䷝1ll?y$䒇׽OrSC$=>E,vӁ`ρ#LV͇zWGoͰ<ߪK`]g^/Vzjj+`_=z~s0=/kN 3/KNzeCWϼL5ezF;nX{ sxb>q|\r737M8_~װ>i?6Gwծ԰Q?s y5̔BN6mj8u!]jV^rZ#t-t]tZӵѵN۵5k7|ۨݚA9>~6:GP]?w݇m:G#6#X߶Fsd͑m:Gl96#hl9sڋi͑m4Gy+:G^Wto8$ך+I^H$_E$_Cr]#!(9Y[kT>X9HmHmQ,A#~IHB](krȥ&,O$, ,֦:TPXj#9PH@$ ]KI.y[/'C8RK<[ ^Arə$0=V\\>t};o߮6]jt};oN۷,Y{ ,sAXvYO ^x-k.tjȯg\c|k :7Y$8L$_Ire9;Xk3uԦJgI.`rV*8W齣W齣޺}G0C;2Lzo|n.$aҹt#Us#5 t"I)yt0;yASpܙf:wfΝsg\L:Ƃ`{A,X-h XR} 50XǙ`<k γr=x%C~z-2u;ƹ g>bP8P0*Pw/b,n\#wqzX{\껐^I}0?/D3ZE3ZEP;=sߋ=U/8;>"xrvp~CSn\=* !ג0ɏ\״5]&cڥ`wuZ NsXɤ_{y|.U6wvٵ.zwAhڥ(<K:B&txޣ{ b{Yxπ5q^~dy12pטw' w'5e o1;}!`.Dx0}1 `i v6a7^ v?Duq!.r ݁jumOY7P6~lilil![>"[--͖fKd%2l`D4["'-͖ȋՑ-X#-fKJ%%rYME"[-'̖mD6[BfKT؂stT煨fKT5l7[0[J͖[̖fK#fKfK6 ="Zc]k^%oD'-ifK%:ll^fD-+͖5fKtlbD`_yܚoJzZGY$`+8>sI/u¯ gUSk=`]_}u^i_{7dw֦|#CtրMs !o,'aҩ} sI:kH>Iu@ܛMѦ&}f|3tq?~XcW BiyǑ/usI3䭻n9դx?_ ?_M\[;MN'[= j&,"Nɝy].#N4ilضަ}Bci=6llM\Dkt8[ә6ؚ^cckZickz>4hl/؜|_CcvYcgCllؚMa}narUk/!9Up\Kr=#|>B8OϘF`OZ5zF8 5X߃,,s8X_ϭ't/FmsF˿|vFKX7jnP]C5v 5ӁӹjTc{/{ޫY0{K50{/{.<tV%GM[bcap|+tb:J3oηHXtU{k-\O:&`ca3X,\*v,Ԍ#Y 3\ցfcn:sq;8͞ v Rw5Kjk^ t:^ K1uRLؽ!&+꥘4{?kEL&ؽz)F=/F=/fll -1-1̖̖-fK.]Sd/fK͖M͖ۉXۉXfK^fKtxy"rfKfKufK fKfKjl9Hz5k5rlilikdH1[Z 3[Zd--f--.2[Z\m(7[Zbli I xUe)rllia3[Z̖)fKte2lio\j,m,mqkB⿞/ [C!쁳I.kxa[pR|e^jv`Y 7,gXߖ̭o1oK-]^ga[Dd* e*5<Ez=}>ُ r.(Lޔ 0>/ g ip?Z  oe< "j;i^KsRs~}WyޗO{~ڣ} p9tu"^^<_'嵞E:/#E&y7W:OZ?(k*'O\>y!\j/ x1az q@M X#>\r#(_RjZw}8buz <"xQ}0I!ŋɏQWn:!z%W݋*L}ߦPo/Ξ Qַ߳}m/O>to5 ,j'ypcp"ɓMEQtjAmd]-j 瘇9!zyH5W ǀe˞[5}ېŨ}8U{06WQRWk_ {˩j}L6k\hn5M(}-u+jƫ#5oۃ('rF+wD?I>I>{E!͢n`iQ2kTCj<M:(z=Wp0D|3rt;ΥK%RR{ s1|ussbrSב\sx7R{~ԾU4L)|BgO5:g%8}ŹUl:T?%F{)>c~Ӿ`7Uw5^;IxuC8+|yRo8[h%h/c>LmQ4JS.1T .Fr^(뜝 傱{y!5ʏw+8S|OgqX`m_a^oR? =m}Y ْG$ \Yd3IOͦ' .Sg. Yvu./K_ZWS៸K ?c0<gYsfKk!#;;P$ncz wI瓤e:߇G\}xKt~K:5ΎMgGQSԨ3ΎID9t= QQ8?wX΀^F!8R]'bjkuBjƵ0uLF-nQ .=ts#` V'^ϏXlX/Vj| zUxti:;51ښN]MgkZ~s18tvC:sIBy9,X::O:3\czxɵ6X ^KuԾJV&j/nk{ x+Lr@KE|k`]c{_dX/]`9 }PK|Aϻ_}/5Z֮um| %N!߈W ,;ح,٪[74:xy~tv!9tvNkCE'HgO:/#S Oro}N] ?> N!<08R]77˰K}oR5kM MG< $<$W7q6_A?:~HnX|vz;%,{5=Ʀ'4='$ؗeCP*CzrI"sAzy󅷁\$/^/u{ V tX@.ȥZ;UδXoZM!_K}|c\-||vCj!?]\-}D|V6X+u9 {]>?Pַ߳kcھkEm5vmo}FCgKW?#NA.{tyS$[ &&kjg?SbZ|>b 7z`iq0} }N[+Z_a s9`zZtD֢HEMt%*~/<@y]L:"-r."ǼwHgu/J&o&~#ZN!y |?KBs/nJN%Uݺ'iU~&6+դ~&}VrU!v^<'B켤oHi٣k:{$R!^wG/#tN"sHŤSO:r!'tY|w~6 6 $`_kΠ6%~%~%~^p}`gdNE}\ᇝ$\,9U;.Dέ]@{y|xUT?%yk'<)$O%?eFQkGKׅ4#o`(vɽWwHC~m$]zԮ+Ԯ+?9'w0ɦ?yOkw^+YWAץ@.q,~ Z<^G*jk^ױ'[a`zf#=Ysεg,D42HiySO,hy~<錍6Οzsy Xk$_Fr$_E$_G*'7[ȫ`3B^rrCOɫI>z\p#%_S¹OHRs?W^k_g=߳`{&i絞DxMg%@}o=y1} r%եOhݾAhjyMo5TңyLN[ޞ{b'4`~ytBs ouB̯6N:I.${?IOjԷ_`̿yD } }C`><Ic{HI~$_dusWͽ#`)= i~z=_B?#!Gn\n끺yѫ>`ny<%1^ros5Ȯk],nuWuWuu7uqf.^uuߠ~M=i}]wn6r]w[kE=ٛJC.V J4KtK]ZϥKRj,6%.Od$>a m˯toW7%ȽSo%1`k%/V? O)?dqrJ)uIk`U~<6z:>d>9DޯON'V N5OK||9g^b^n3U6i~]ֵQ7oN !y,C$O$y2SHX4%%$_JraAiGW\sxxu$&k/iuw|H;+#PKc=][}e8P-5 r:yY3oR߇&OT|DŽy0OF~Ӡ~Sn-zo9~:kd-L\S%3$8L<\Ρo%Ku͇<;E9<}ӒYj9=0O8#uW\> mPod3|pXxX;F~LȱƞYOrY\tFrـ0j jCW;ͷq]n<qP,*qrY+J.\-qV=WK6W#4g8G^D'%=rr)J\^`LIC gS@>-PϦL|AަOEʥ~>#'$SKZtUtZҵkBzS9R#r:ҵ>kkfak`#0w>r_O/9Sܼ*׀cIy{-8]N6:: ZW\Ρ6:c Z#|.)>[RZNZ+`=kc>ozL7=f?u { ̅$_Gr$D$B$&%k!)e<g9ərjw3\>m-~^!O>/yvk6X'<$O36&cnuuBߑ8 vc\=/uپNzN뽾wo~m?"?&:ÁZs~5^6;[礴᷁߼;65a? em) $6]Ho!VW|'e( >Bt-YJ^`ɓށ`d@8,s8GJS܎̰܎|.=4 kr,Rq7#ŇnF&nFV cFnF܌gQ6Ψ|g=F٤tXU*O=Fm!=Fs`=Fs`=FSm5\#3y:-z3z'3mmMmMmM8&lM8HT:,*q69niZٔӦ6ΦmM8.q6q6U`nzܔjTK7Ӝ 4 ,,܌jfi6f6fmͪl͎ژ1>C` 12q`]i6ch'91l1ؘ17y9 3luM5a2XW)|ÞܞG$~& o$O y2HIr٣Kb5{$#$oaӯ]uݯ3[7=~PDpRw/w tbw-gRJp@6M\}`F=[,66_![![>#[--͖ԠْlIg7[R'-3͖EfKfKjْzز Rl lIْ%y%5=sҿҿҿҿز