pybox2d-2.3.2/000077500000000000000000000000001276457661000131235ustar00rootroot00000000000000pybox2d-2.3.2/.gitattributes000066400000000000000000000000411276457661000160110ustar00rootroot00000000000000* text=auto *.cmd text eol=crlf pybox2d-2.3.2/.gitignore000066400000000000000000000000511276457661000151070ustar00rootroot00000000000000build/* dist/* *.py[oc] *.swo *.swp *.so pybox2d-2.3.2/.travis.yml000066400000000000000000000025031276457661000152340ustar00rootroot00000000000000# vi: sw=2 ts=2 sts=2 expandtab language: python os: - linux - osx # Travis/osx doesn't support Python yet: # see https://github.com/travis-ci/travis-ci/issues/2312 python: # - "2.6" # no dictionary comprehensions in 2.6, sorry - "2.7" # - "3.2" # waste of time, coverage module doesn't work - "3.3" - "3.4" - "3.5" # - "pypy" # swig doesn't seem to work :( matrix: fast_finish: true allow_failures: - os: osx before_install: - echo $TRAVIS_OS_NAME - pip install setuptools nose coverage coveralls # linux - if [ "$TRAVIS_OS_NAME" == "linux" ]; then wget http://mirrors.kernel.org/ubuntu/pool/main/s/swig/swig3.0_3.0.7-2ubuntu1_amd64.deb; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo dpkg --install swig3.0_3.0.7-2ubuntu1_amd64.deb; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then which swig3.0; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s /usr/bin/swig3.0 /usr/bin/swig; fi # OSX - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; fi - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install swig; fi install: - python setup.py build - python setup.py install script: # run tests from test directory itself to not get Box2D confused with # top-level dir - cd tests - nosetests -v -w . --with-coverage --cover-package=Box2D after_success: - coveralls pybox2d-2.3.2/Box2D/000077500000000000000000000000001276457661000140415ustar00rootroot00000000000000pybox2d-2.3.2/Box2D/Box2D-License.txt000066400000000000000000000015441276457661000171040ustar00rootroot00000000000000Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. pybox2d-2.3.2/Box2D/Box2D.h000066400000000000000000000046141276457661000151350ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef BOX2D_H #define BOX2D_H /** \mainpage Box2D API Documentation \section intro_sec Getting Started For documentation please see http://box2d.org/documentation.html For discussion please visit http://box2d.org/forum */ // These include files constitute the main Box2D API #include #include #include #include #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 pybox2d-2.3.2/Box2D/Box2D.i000066400000000000000000000166111276457661000151360ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /* * This is the main Python SWIG interface file. */ %module(directors="1") Box2D %{ #include "Box2D/Box2D.h" %} /*note: swig generated names: _Box2D._ python obfuscated names: ___ */ #ifdef SWIGPYTHON /* To disable assertions->exceptions, comment out the two lines that define USE_EXCEPTIONS. One is here, one is in Common/b2Settings.h */ #define USE_EXCEPTIONS #ifdef USE_EXCEPTIONS /* See Common/b2Settings.h also. It defines b2Assert to instead throw an exception if USE_EXCEPTIONS is defined. */ %include "exception.i" %exception { try { $action } catch(b2AssertException) { // error already set, pass it on to python SWIG_fail; } if (PyErr_Occurred()) { // This is if we set the error inside a function; report it to swig SWIG_fail; } } #endif /* Director-exceptions are a result of callbacks that happen as a result to the physics step or debug draw, usually. So, catch those errors and report them back to Python. Example: If there is a typo in your b2Draw instance's DrawPolygon (in Python), when you call world.DrawDebugData(), callbacks will be made to such functions as that. Being Python code called from the C++ module, they turn into director exceptions then and will crash the application unless handled in C++ (try/catch) and then passed to Python (SWIG_fail). */ %exception b2World::Step { try { $action } catch (Swig::DirectorException) { SWIG_fail; } catch (b2AssertException) { SWIG_fail; } } %exception b2World::DrawDebugData { try { $action } catch (Swig::DirectorException) { SWIG_fail; } catch (b2AssertException) { SWIG_fail; } } %exception b2World::QueryAABB { try { $action } catch (Swig::DirectorException) { SWIG_fail; } catch (b2AssertException) { SWIG_fail; } } %exception b2World::RayCast { try { $action } catch (Swig::DirectorException) { SWIG_fail; } catch (b2AssertException) { SWIG_fail; } } %exception b2World::DestroyJoint { try { $action } catch (Swig::DirectorException) { SWIG_fail; } catch (b2AssertException) { SWIG_fail; } } %exception b2World::DestroyBody { try { $action } catch (Swig::DirectorException) { SWIG_fail; } catch (b2AssertException) { SWIG_fail; } } #pragma SWIG nowarn=314 /* ---- classes to ignore ---- */ /*Most of these are just internal structures, so there is no need to have them accessible by Python. You can safely comment out any %ignore if you for some reason do need them. Ignoring shrinks the library by a small amount. */ //%ignore b2ContactManager; // TODO %ignore b2Chunk; %ignore b2DynamicTree; %ignore b2DynamicTreeNode; %ignore b2Island; %ignore b2Position; %ignore b2Velocity; %ignore b2TimeStep; %ignore b2Simplex; %ignore b2SimplexVertex; %ignore b2SimplexCache; %ignore b2StackAllocator; %ignore b2StackEntry; %ignore b2ContactRegister; %ignore b2BlockAllocator; %ignore b2Timer; /* ---- features ---- */ /* Autodoc puts the basic docstrings for each function */ %feature("autodoc", "1"); /* Add callback support for the following classes */ %feature("director") b2ContactListener; %feature("director") b2ContactFilter; %feature("director") b2DestructionListener; %feature("director") b2Draw; %feature("director") b2DrawExtended; %feature("director") b2QueryCallback; %feature("director") b2RayCastCallback; /* ---- includes ---- */ /* The order of these is important. */ /* Doxygen-generated docstrings. Can safely be commented out. */ %include "Box2D/Box2D_doxygen.i" /* __dir__ replacement. Can safely be commented out. */ %include "Box2D/Box2D_dir.i" /* __init__ replacement allowing kwargs. Can safely be commented out, but tests will fail. */ %include "Box2D/Box2D_kwargs.i" /* __repr__ replacement -- pretty printing. Can safely be commented out. */ %include "Box2D/Box2D_printing.i" /* Miscellaneous inline code. */ %include "Box2D/Box2D_inline.i" /* Miscellaneous extended classes: b2Color, b2Version, b2DistanceProxy, b2BroadPhase */ %include "Box2D/Box2D_misc.i" /* Typemaps that allow for tuples to be used in place of vectors, the removal of getAsType, etc. */ %include "Box2D/Box2D_typemaps.i" /* Contact-related classes (b2Contact, b2Manifold, etc.) */ %include "Box2D/Box2D_contact.i" /* b2Vec2, b2Vec3, b2Mat22, b2Transform, b2AABB and related extensions. */ %include "Box2D/Box2D_math.i" /* Allows for userData to be used. Also modifies CreateBody/Joint. */ %include "Box2D/Box2D_userdata.i" /* b2World only. */ %include "Box2D/Box2D_world.i" /* b2Body, b2Fixture, and related definitions. */ %include "Box2D/Box2D_bodyfixture.i" /* b2Shape, b2CircleShape, b2PolygonShape. */ %include "Box2D/Box2D_shapes.i" /* All joints and definitions. Defines b2JointTypes dict. */ %include "Box2D/Box2D_joints.i" /* Extending the debug draw class. */ %include "Box2D/Box2D_debugdraw.i" /* Include everything from the C++ library now */ %include "Box2D/Box2D.h" /* And finally tag on the secondary namespace code to the end of Box2D.py */ %pythoncode %{ # Backward-compatibility b2LoopShape = b2ChainShape # Initialize the alternative namespace b2.*, and clean-up the # dir listing of Box2D by removing *_swigregister. # # To see what this is, try import Box2D; print(dir(Box2D.b2)) from . import b2 s=None to_remove=[] for s in locals(): if s.endswith('_swigregister'): to_remove.append(s) elif s!='b2' and s.startswith('b2'): if s[2]=='_': # Covers b2_* setattr(b2, s[3].lower() + s[4:], locals()[s]) else: # The other b2* if s[3].isupper(): setattr(b2, s[2:], locals()[s]) else: setattr(b2, s[2].lower() + s[3:], locals()[s]) for s in to_remove: del locals()[s] del s del to_remove %} #endif pybox2d-2.3.2/Box2D/Box2D_bodyfixture.i000066400000000000000000000407761276457661000175730ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /**** BodyDef ****/ %extend b2BodyDef { public: %pythoncode %{ _fixtures = None _shapes = None _shapeFixture = None @property def fixtures(self): return self._fixtures @fixtures.setter def fixtures(self, fixtures): if isinstance(fixtures, b2FixtureDef): self._fixtures = [fixtures] else: self._fixtures = list(fixtures) @property def shapes(self): return self._shapes @shapes.setter def shapes(self, shapes): if isinstance(shapes, b2Shape): self._shapes = [shapes] else: self._shapes = list(shapes) @property def shapeFixture(self): return self._shapeFixture @shapeFixture.setter def shapeFixture(self, fixture): self._shapeFixture = fixture %} } /**** FixtureDef ****/ /* Special initializer to allow for filter arguments */ %extend b2FixtureDef { public: %pythoncode %{ def __SetCategoryBits(self, value): self.filter.categoryBits=value def __SetGroupIndex(self, value): self.filter.groupIndex=value def __SetMaskBits(self, value): self.filter.maskBits=value categoryBits=property(lambda self: self.filter.categoryBits, __SetCategoryBits) groupIndex=property(lambda self: self.filter.groupIndex, __SetGroupIndex) maskBits=property(lambda self: self.filter.maskBits, __SetMaskBits) %} } /**** Fixture ****/ %extend b2Fixture { public: /* This destructor is ignored by SWIG, but it stops the erroneous memory leak error. Will have to test with older versions of SWIG to ensure this is ok (tested with 1.3.40) */ ~b2Fixture() { } %pythoncode %{ __eq__ = b2FixtureCompare __ne__ = lambda self,other: not b2FixtureCompare(self,other) # Read-write properties friction = property(__GetFriction, __SetFriction) restitution = property(__GetRestitution, __SetRestitution) filterData = property(__GetFilterData, __SetFilterData) sensor = property(__IsSensor, __SetSensor) density = property(__GetDensity, __SetDensity) # Read-only next = property(__GetNext, None) type = property(__GetType, None) shape = property(__GetShape, None) body = property(__GetBody, None) @property def massData(self): md=b2MassData() self.__GetMassData(md) return md %} } %rename(__GetNext) b2Fixture::GetNext; %rename(__GetFriction) b2Fixture::GetFriction; %rename(__GetRestitution) b2Fixture::GetRestitution; %rename(__GetFilterData) b2Fixture::GetFilterData; %rename(__IsSensor) b2Fixture::IsSensor; %rename(__GetType) b2Fixture::GetType; %rename(__GetMassData) b2Fixture::GetMassData; %rename(__GetShape) b2Fixture::GetShape; %rename(__GetDensity) b2Fixture::GetDensity; %rename(__GetBody) b2Fixture::GetBody; %rename(__SetSensor) b2Fixture::SetSensor; %rename(__SetDensity) b2Fixture::SetDensity; %rename(__SetFilterData) b2Fixture::SetFilterData; %rename(__SetFriction) b2Fixture::SetFriction; %rename(__SetRestitution) b2Fixture::SetRestitution; /**** Body ****/ %extend b2Body { public: %pythoncode %{ __eq__ = b2BodyCompare __ne__ = lambda self,other: not b2BodyCompare(self,other) def __GetMassData(self): """ Get a b2MassData object that represents this b2Body NOTE: To just get the mass, use body.mass """ ret = b2MassData() ret.center=self.localCenter ret.I = self.inertia ret.mass = self.mass return ret def __SetInertia(self, inertia): """ Set the body's inertia """ md = self.massData md.I = inertia self.massData=md def __SetMass(self, mass): """ Set the body's mass """ md = self.massData md.mass = mass self.massData=md def __SetLocalCenter(self, lcenter): """ Set the body's local center """ md = self.massData md.center = lcenter self.massData=md def __iter__(self): """ Iterates over the fixtures in the body """ for fixture in self.fixtures: yield fixture def __CreateShapeFixture(self, type_, **kwargs): """ Internal function to handle creating circles, polygons, etc. without first creating a fixture. type_ is b2Shape. """ shape=type_() fixture=b2FixtureDef(shape=shape) for key, value in kwargs.items(): # Note that these hasattrs use the types to get around # the fact that some properties are write-only (like 'box' in # polygon shapes), and as such do not show up with 'hasattr'. if hasattr(type_, key): to_set=shape elif hasattr(b2FixtureDef, key): to_set=fixture else: raise AttributeError('Property %s not found in either %s or b2FixtureDef' % (key, type_.__name__)) try: setattr(to_set, key, value) except Exception as ex: raise ex.__class__('Failed on kwargs, class="%s" key="%s": %s' \ % (to_set.__class__.__name__, key, ex)) return self.CreateFixture(fixture) def CreatePolygonFixture(self, **kwargs): """ Create a polygon shape without an explicit fixture definition. Takes kwargs; you can pass in properties for either the polygon or the fixture to this function. For example: CreatePolygonFixture(box=(1, 1), friction=0.2, density=1.0) where 'box' is a property from the polygon shape, and 'friction' and 'density' are from the fixture definition. """ return self.__CreateShapeFixture(b2PolygonShape, **kwargs) def CreateCircleFixture(self, **kwargs): """ Create a circle shape without an explicit fixture definition. Takes kwargs; you can pass in properties for either the circle or the fixture to this function. For example: CreateCircleFixture(radius=0.2, friction=0.2, density=1.0) where 'radius' is a property from the circle shape, and 'friction' and 'density' are from the fixture definition. """ return self.__CreateShapeFixture(b2CircleShape, **kwargs) def CreateEdgeFixture(self, **kwargs): """ Create a edge shape without an explicit fixture definition. Takes kwargs; you can pass in properties for either the edge or the fixture to this function. For example: CreateEdgeFixture(vertices=[(0,0),(1,0)], friction=0.2, density=1.0) where 'vertices' is a property from the edge shape, and 'friction' and 'density' are from the fixture definition. """ return self.__CreateShapeFixture(b2EdgeShape, **kwargs) def CreateLoopFixture(self, **kwargs): """ Create a loop shape without an explicit fixture definition. Takes kwargs; you can pass in properties for either the loop or the fixture to this function. For example: CreateLoopFixture(vertices=[...], friction=0.2, density=1.0) where 'vertices' is a property from the loop shape, and 'friction' and 'density' are from the fixture definition. """ return self.__CreateShapeFixture(b2ChainShape, **kwargs) CreateChainFixture = CreateLoopFixture def CreateFixturesFromShapes(self, shapes=None, shapeFixture=None): """ Create fixture(s) on the body from one or more shapes, and optionally a single fixture definition. Takes kwargs; examples of valid combinations are as follows: CreateFixturesFromShapes(shapes=b2CircleShape(radius=0.2)) CreateFixturesFromShapes(shapes=b2CircleShape(radius=0.2), shapeFixture=b2FixtureDef(friction=0.2)) CreateFixturesFromShapes(shapes=[b2CircleShape(radius=0.2), b2PolygonShape(box=[1,2])]) """ if shapes==None: raise TypeError('At least one shape required') if shapeFixture==None: shapeFixture=b2FixtureDef() oldShape=None else: oldShape = shapeFixture.shape ret=None try: if isinstance(shapes, (list, tuple)): ret = [] for shape in shapes: shapeFixture.shape = shape ret.append(self.__CreateFixture(shapeFixture)) else: shapeFixture.shape=shapes ret = self.__CreateFixture(shapeFixture) finally: shapeFixture.shape=oldShape return ret def CreateFixture(self, defn=None, **kwargs): """ Create a fixtures on the body. Takes kwargs; examples of valid combinations are as follows: CreateFixture(b2FixtureDef(shape=s, restitution=0.2, ...)) CreateFixture(shape=s, restitution=0.2, ...) """ if defn is not None and isinstance(defn, b2FixtureDef): return self.__CreateFixture(defn) else: if 'shape' not in kwargs: raise ValueError('Must specify the shape for the fixture') return self.__CreateFixture(b2FixtureDef(**kwargs)) def CreateEdgeChain(self, edge_list): """ Creates a body a set of connected edge chains. Expects edge_list to be a list of vertices, length >= 2. """ prev=None if len(edge_list) < 2: raise ValueError('Edge list length >= 2') shape=b2EdgeShape(vertices=[list(i) for i in edge_list[0:2]]) self.CreateFixturesFromShapes(shape) prev = edge_list[1] for edge in edge_list[1:]: if len(edge) != 2: raise ValueError('Vertex length != 2, "%s"' % list(edge)) shape.vertices = [list(prev), list(edge)] self.CreateFixturesFromShapes(shape) prev=edge # Read-write properties sleepingAllowed = property(__IsSleepingAllowed, __SetSleepingAllowed) angularVelocity = property(__GetAngularVelocity, __SetAngularVelocity) linearVelocity = property(__GetLinearVelocity, __SetLinearVelocity) awake = property(__IsAwake, __SetAwake) angularDamping = property(__GetAngularDamping, __SetAngularDamping) fixedRotation = property(__IsFixedRotation, __SetFixedRotation) linearDamping = property(__GetLinearDamping, __SetLinearDamping) bullet = property(__IsBullet, __SetBullet) type = property(__GetType, __SetType) active = property(__IsActive, __SetActive) angle = property(__GetAngle, lambda self, angle: self.__SetTransform(self.position, angle)) transform = property(__GetTransform, lambda self, value: self.__SetTransform(*value)) massData = property(__GetMassData, __SetMassData) mass = property(__GetMass, __SetMass) localCenter = property(__GetLocalCenter, __SetLocalCenter) inertia = property(__GetInertia, __SetInertia) position = property(__GetPosition, lambda self, pos: self.__SetTransform(pos, self.angle)) gravityScale = property(__GetGravityScale, __SetGravityScale) # Read-only joints = property(lambda self: _list_from_linked_list(self.__GetJointList_internal()), None, doc="""All joints connected to the body as a list. NOTE: This re-creates the list on every call. See also joints_gen.""") contacts = property(lambda self: _list_from_linked_list(self.__GetContactList_internal()), None, doc="""All contacts related to the body as a list. NOTE: This re-creates the list on every call. See also contacts_gen.""") fixtures = property(lambda self: _list_from_linked_list(self.__GetFixtureList_internal()), None, doc="""All fixtures contained in this body as a list. NOTE: This re-creates the list on every call. See also fixtures_gen.""") joints_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetJointList_internal())), None, doc="""Indexable generator of the connected joints to this body. NOTE: When not using the whole list, this may be preferable to using 'joints'.""") contacts_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetContactList_internal())), None, doc="""Indexable generator of the related contacts. NOTE: When not using the whole list, this may be preferable to using 'contacts'.""") fixtures_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetFixtureList_internal())), None, doc="""Indexable generator of the contained fixtures. NOTE: When not using the whole list, this may be preferable to using 'fixtures'.""") next = property(__GetNext, None) worldCenter = property(__GetWorldCenter, None) world = property(__GetWorld, None) %} } %rename(__GetAngle) b2Body::GetAngle; %rename(__IsSleepingAllowed) b2Body::IsSleepingAllowed; %rename(__GetAngularVelocity) b2Body::GetAngularVelocity; %rename(__GetJointList_internal) b2Body::GetJointList; %rename(__GetFixtureList_internal) b2Body::GetFixtureList; %rename(__GetContactList_internal) b2Body::GetContactList; %rename(__GetLinearVelocity) b2Body::GetLinearVelocity; %rename(__GetNext) b2Body::GetNext; %rename(__GetPosition) b2Body::GetPosition; %rename(__GetMass) b2Body::GetMass; %rename(__IsAwake) b2Body::IsAwake; %rename(__GetTransform) b2Body::GetTransform; %rename(__SetTransform) b2Body::SetTransform; %rename(__GetGravityScale) b2Body::GetGravityScale; %rename(__SetGravityScale) b2Body::SetGravityScale; %rename(__GetWorldCenter) b2Body::GetWorldCenter; %rename(__GetAngularDamping) b2Body::GetAngularDamping; %rename(__IsFixedRotation) b2Body::IsFixedRotation; %rename(__GetWorld) b2Body::GetWorld; %rename(__GetLinearDamping) b2Body::GetLinearDamping; %rename(__IsBullet) b2Body::IsBullet; %rename(__GetLocalCenter) b2Body::GetLocalCenter; %rename(__GetType) b2Body::GetType; %rename(__GetInertia) b2Body::GetInertia; %rename(__IsActive) b2Body::IsActive; %rename(__SetLinearVelocity) b2Body::SetLinearVelocity; %rename(__SetSleepingAllowed) b2Body::SetSleepingAllowed; %rename(__SetAngularDamping) b2Body::SetAngularDamping; %rename(__SetActive) b2Body::SetActive; %rename(__SetAngularVelocity) b2Body::SetAngularVelocity; %rename(__SetMassData) b2Body::SetMassData; %rename(__SetBullet) b2Body::SetBullet; %rename(__SetFixedRotation) b2Body::SetFixedRotation; %rename(__SetAwake) b2Body::SetAwake; %rename(__SetLinearDamping) b2Body::SetLinearDamping; %rename(__SetType) b2Body::SetType; // pybox2d-2.3.2/Box2D/Box2D_contact.i000066400000000000000000000224501276457661000166470ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /**** b2GetPointStates ****/ %inline { PyObject* b2GetPointStates(const b2Manifold* manifold1, const b2Manifold* manifold2) { PyObject* ret=NULL; b2PointState state1[b2_maxManifoldPoints], state2[b2_maxManifoldPoints]; if (!manifold1 || !manifold2) return NULL; b2GetPointStates(state1, state2, manifold1, manifold2); ret = PyTuple_New(2); int state1_length=-1, state2_length=-1; PyObject* state1_t=Py_None; PyObject* state2_t=Py_None; for (int i=0; i < b2_maxManifoldPoints; i++) { if (state1[i]==b2_nullState && state1_length==0) state1_length=i; if (state2_length > -1) break; if (state2[i]==b2_nullState && state2_length==0) state2_length=i; if (state1_length > -1) break; } if (state1_length < 0) state1_length = b2_maxManifoldPoints; if (state2_length < 0) state2_length = b2_maxManifoldPoints; if (state1_length > -1) state1_t=PyTuple_New(state1_length); else Py_INCREF(state1_t); if (state2_length > -1) state2_t=PyTuple_New(state2_length); else Py_INCREF(state2_t); PyTuple_SetItem(ret, 0, state1_t); PyTuple_SetItem(ret, 1, state2_t); for (int i=0; i < b2Max(state1_length, state2_length); i++) { if (i < state1_length) PyTuple_SetItem(state1_t, i, SWIG_From_int(state1[i])); if (i < state2_length) PyTuple_SetItem(state2_t, i, SWIG_From_int(state2[i])); } return ret; } } %ignore b2GetPointStates; /**** Manifold ****/ %rename (type_) b2Manifold::type; %ignore b2Manifold::points; %extend b2Manifold { public: %pythoncode %{ def __GetPoints(self): return [self.__GetPoint(i) for i in range(self.pointCount)] points = property(__GetPoints, None) %} b2ManifoldPoint* __GetPoint(int i) { if (i >= b2_maxManifoldPoints || i >= $self->pointCount) return NULL; return &( $self->points[i] ); } } /**** ContactManager ****/ %rename(broadPhase) b2ContactManager::m_broadPhase; %rename(contactList) b2ContactManager::m_contactList; %rename(contactCount) b2ContactManager::m_contactCount; %rename(contactFilter) b2ContactManager::m_contactFilter; %rename(contactListener) b2ContactManager::m_contactListener; %rename(allocator) b2ContactManager::m_allocator; %extend b2ContactManager { public: // TODO contact lists, etc. same as b2World %pythoncode %{ %} } /* ContactImpulse */ %extend b2ContactImpulse { public: PyObject* __get_normal_impulses() { PyObject* ret = PyTuple_New($self->count); for (int i=0; i < $self->count; i++) PyTuple_SetItem(ret, i, SWIG_From_double((float32)($self->normalImpulses[i]))); return ret; } PyObject* __get_tangent_impulses() { PyObject* ret = PyTuple_New($self->count); for (int i=0; i < $self->count; i++) PyTuple_SetItem(ret, i, SWIG_From_double((float32)($self->tangentImpulses[i]))); return ret; } %pythoncode %{ normalImpulses = property(__get_normal_impulses, None) tangentImpulses = property(__get_tangent_impulses, None) %} } %ignore b2ContactImpulse::normalImpulses; %ignore b2ContactImpulse::tangentImpulses; /**** WorldManifold ****/ %ignore b2WorldManifold::points; %extend b2WorldManifold { public: %pythoncode %{ %} PyObject* __get_points() { PyObject* ret=PyTuple_New(b2_maxManifoldPoints); PyObject* point; for (int i=0; i < b2_maxManifoldPoints; i++) { point = PyTuple_New(2); PyTuple_SetItem(point, 0, SWIG_From_double((float32)$self->points[i].x)); PyTuple_SetItem(point, 1, SWIG_From_double((float32)$self->points[i].y)); PyTuple_SetItem(ret, i, point); } return ret; } %pythoncode %{ points = property(__get_points, None) %} } /**** Contact ****/ %extend b2Contact { public: %pythoncode %{ def __GetWorldManifold(self): ret=b2WorldManifold() self.__GetWorldManifold_internal(ret) return ret # Read-write properties enabled = property(__IsEnabled, __SetEnabled) # Read-only next = property(__GetNext, None) fixtureB = property(__GetFixtureB, None) fixtureA = property(__GetFixtureA, None) manifold = property(__GetManifold, None) childIndexA = property(__GetChildIndexA, None) childIndexB = property(__GetChildIndexB, None) worldManifold = property(__GetWorldManifold, None) touching = property(__IsTouching, None) friction = property(__GetFriction, __SetFriction) restitution = property(__GetRestitution, __SetRestitution) tangentSpeed = property(__GetTangentSpeed, __SetTangentSpeed) %} } %rename(__GetNext) b2Contact::GetNext; %rename(__GetFixtureB) b2Contact::GetFixtureB; %rename(__GetFixtureA) b2Contact::GetFixtureA; %rename(__GetChildIndexA) b2Contact::GetChildIndexA; %rename(__GetChildIndexB) b2Contact::GetChildIndexB; %rename(__GetManifold) b2Contact::GetManifold; %rename(__GetWorldManifold_internal) b2Contact::GetWorldManifold; %rename(__IsEnabled) b2Contact::IsEnabled; %rename(__SetEnabled) b2Contact::SetEnabled; %rename(__IsTouching) b2Contact::IsTouching; %rename(__GetFriction) b2Contact::GetFriction; %rename(__SetFriction) b2Contact::SetFriction; %rename(__GetRestitution) b2Contact::GetRestitution; %rename(__SetRestitution) b2Contact::SetRestitution; %rename(__GetTangentSpeed) b2Contact::GetTangentSpeed; %rename(__SetTangentSpeed) b2Contact::SetTangentSpeed; /**** Create our own ContactPoint structure ****/ /* And allow kwargs for it */ %inline { class b2ContactPoint { public: b2ContactPoint() : fixtureA(NULL), fixtureB(NULL), state(b2_nullState) { normal.SetZero(); position.SetZero(); } ~b2ContactPoint() {} b2Fixture* fixtureA; b2Fixture* fixtureB; b2Vec2 normal; b2Vec2 position; b2PointState state; }; } /**** Replace b2TimeOfImpact ****/ %inline %{ b2TOIOutput* _b2TimeOfImpact(b2Shape* shapeA, int idxA, b2Shape* shapeB, int idxB, b2Sweep& sweepA, b2Sweep& sweepB, float32 tMax) { b2TOIInput input; b2TOIOutput* out=new b2TOIOutput; input.proxyA.Set(shapeA, idxA); input.proxyB.Set(shapeB, idxB); input.sweepA = sweepA; input.sweepB = sweepB; input.tMax = tMax; b2TimeOfImpact(out, &input); return out; } b2TOIOutput* _b2TimeOfImpact(b2TOIInput* input) { b2TOIOutput* out=new b2TOIOutput; b2TimeOfImpact(out, input); return out; } %} %pythoncode %{ def b2TimeOfImpact(shapeA=None, idxA=0, shapeB=None, idxB=0, sweepA=None, sweepB=None, tMax=0.0): """ Compute the upper bound on time before two shapes penetrate. Time is represented as a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, non-tunneling collision. If you change the time interval, you should call this function again. Note: use b2Distance to compute the contact point and normal at the time of impact. Can be called one of several ways: + b2TimeOfImpact(b2TOIInput) # utilizes the b2TOIInput structure, where you define your own proxies Or utilizing kwargs: + b2TimeOfImpact(shapeA=a, shapeB=b, idxA=0, idxB=0, sweepA=sa, sweepB=sb, tMax=t) Where idxA and idxB are optional and used only if the shapes are loops (they indicate which section to use.) sweep[A,B] are of type b2Sweep. Returns a tuple in the form: (output state, time of impact) Where output state is in b2TOIOutput.[ e_unknown, e_failed, e_overlapped, e_touching, e_separated ] """ if isinstance(shapeA, b2TOIInput): toi_input = shapeA out = _b2TimeOfImpact(toi_input) else: out = _b2TimeOfImpact(shapeA, idxA, shapeB, idxB, sweepA, sweepB, tMax) return (out.state, out.t) %} %newobject _b2TimeOfImpact; %ignore b2TimeOfImpact; pybox2d-2.3.2/Box2D/Box2D_debugdraw.i000066400000000000000000000141261276457661000171610ustar00rootroot00000000000000/* * C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * Python version Copyright (c) 2010 kne / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /**** Draw ****/ %extend b2Draw { public: %pythoncode %{ _flag_entries = [ ['drawShapes', e_shapeBit], ['drawJoints', e_jointBit ], ['drawAABBs', e_aabbBit ], ['drawPairs', e_pairBit ], ['drawCOMs', e_centerOfMassBit ], ['convertVertices', e_convertVertices ], ] def _SetFlags(self, value): flags = 0 for name_, mask in self._flag_entries: if name_ in value and value[name_]: flags |= mask self.__SetFlags(flags) def _GetFlags(self): flags = self.__GetFlags() ret={} for name_, mask in self._flag_entries: ret[name_]=((flags & mask)==mask) return ret flags=property(_GetFlags, _SetFlags, doc='Sets whether or not shapes, joints, etc. will be drawn.') %} } %rename (__SetFlags) b2Draw::SetFlags; %rename (__GetFlags) b2Draw::GetFlags; #define e_convertVertices 0x1000 /* DrawExtended This was a feeble attempt at speeding up the drawing routines. It converts the incoming b2Vec2s to screen coordinates so the Python side doesn't have to. But while I should have been profiling to see if vertex conversions were truly a bottleneck, I didn't. I think it only results in maybe 5 FPS gain at most. It makes for an interesting concept that I can extend some classes in this fashion and still have them work with Box2D thanks to inheritance. I'm going to leave it in for the cleanliness aspect of it. The conversion routines can be disabled by setting convertVertices to False, or the base b2Draw can still be used. */ %extend b2DrawExtended { public: } %typemap(directorin) (const b2Vec2* conv_vertices, int32 vertexCount) { $input = this->__Convert($1_name, $2_name); } %typemap(directorin) const b2Vec2& conv_p1 { $input = this->to_screen((b2Vec2&)$1_name); } %typemap(directorin) const b2Vec2& conv_p2 { $input = this->to_screen((b2Vec2&)$1_name); } %include "Box2D/Common/b2Draw.h" %inline { class b2DrawExtended : public b2Draw { public: bool convertVertices; b2Vec2 center; b2Vec2 offset; float32 zoom; b2Vec2 screenSize; bool flipY, flipX; PyObject* __Convert(const b2Vec2* verts, int32 vertexCount) { PyObject* ret=PyTuple_New(vertexCount); if (GetFlags() & e_convertVertices) { // Convert the verts PyObject* vertex; long x, y; for (int i=0; i < vertexCount; i++) { vertex = PyTuple_New(2); x=(long)((verts[i].x * zoom) - offset.x); if (flipX) { x = (long)screenSize.x - x; } y=(long)(((verts[i].y * zoom) - offset.y)); if (flipY) { y = (long)screenSize.y - y; } PyTuple_SetItem(vertex, 0, SWIG_From_long(x)); PyTuple_SetItem(vertex, 1, SWIG_From_long(y)); PyTuple_SetItem(ret, i, vertex); } } else { // Pass the verts in as-is PyObject* vertex; for (int i=0; i < vertexCount; i++) { vertex = PyTuple_New(2); PyTuple_SetItem(vertex, 0, SWIG_From_double((float32)verts[i].x)); PyTuple_SetItem(vertex, 1, SWIG_From_double((float32)verts[i].y)); PyTuple_SetItem(ret, i, vertex); } } return ret; } PyObject* to_screen(b2Vec2& point) { long x=(long)((point.x * zoom) - offset.x); if (flipX) { x = (long)screenSize.x - x; } long y=(long)(((point.y * zoom) - offset.y)); if (flipY) { y = (long)screenSize.y - y; } PyObject* ret = PyTuple_New(2); PyTuple_SetItem(ret, 0, SWIG_From_long(x)); PyTuple_SetItem(ret, 1, SWIG_From_long(y)); return ret; } virtual void DrawPolygon(const b2Vec2* conv_vertices, int32 vertexCount, const b2Color& color) = 0; virtual void DrawSolidPolygon(const b2Vec2* conv_vertices, int32 vertexCount, const b2Color& color) = 0; virtual void DrawCircle(const b2Vec2& conv_p1, float32 radius, const b2Color& color) = 0; virtual void DrawSolidCircle(const b2Vec2& conv_p1, float32 radius, const b2Vec2& axis, const b2Color& color) = 0; virtual void DrawSegment(const b2Vec2& conv_p1, const b2Vec2& conv_p2, const b2Color& color) = 0; virtual void DrawTransform(const b2Transform& xf) = 0; void __SetFlags(uint32 flags) { if (convertVertices) SetFlags(e_convertVertices | flags); else SetFlags(flags); } virtual ~b2DrawExtended() { } b2DrawExtended() : convertVertices(false), flipY(false), flipX(false) { center.SetZero(); offset.SetZero(); zoom=1.0; screenSize.SetZero(); SetFlags(convertVertices ? e_convertVertices : 0x00); } }; } %feature("director") b2DrawExtended; pybox2d-2.3.2/Box2D/Box2D_dir.i000066400000000000000000000077001276457661000157730ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %pythoncode %{ def _dir_filter(self): """ Using introspection, mimic dir() by adding up all of the __dicts__ for the current class and all base classes (type(self).__mro__ returns all of the classes that make it up) Basically filters by: __x__ OK __x bad _classname bad """ def check(s): if s.startswith('__'): if s.endswith('__'): return True else: return False else: for typename in typenames: if typename in s: return False return True keys = sum([list(c.__dict__.keys()) for c in type(self).__mro__],[]) keys += list(self.__dict__.keys()) typenames = ["_%s" % c.__name__ for c in type(self).__mro__] ret = [s for s in list(set(keys)) if check(s)] ret.sort() return ret %} %define DIR_EXTEND(classname) %extend classname { %pythoncode %{ __dir__ = _dir_filter %} } %enddef DIR_EXTEND(b2AABB); DIR_EXTEND(b2AssertException); DIR_EXTEND(b2Body); DIR_EXTEND(b2BodyDef); DIR_EXTEND(b2BroadPhase); DIR_EXTEND(b2ChainShape); DIR_EXTEND(b2CircleShape); DIR_EXTEND(b2ClipVertex); DIR_EXTEND(b2Color); DIR_EXTEND(b2Contact); DIR_EXTEND(b2ContactEdge); DIR_EXTEND(b2ContactFeature); DIR_EXTEND(b2ContactFilter); DIR_EXTEND(b2ContactID); DIR_EXTEND(b2ContactImpulse); DIR_EXTEND(b2ContactListener); DIR_EXTEND(b2ContactManager); DIR_EXTEND(b2ContactPoint); DIR_EXTEND(b2DestructionListener); DIR_EXTEND(b2DistanceInput); DIR_EXTEND(b2DistanceJoint); DIR_EXTEND(b2DistanceJointDef); DIR_EXTEND(b2DistanceOutput); DIR_EXTEND(b2DistanceProxy); DIR_EXTEND(b2Draw); DIR_EXTEND(b2DrawExtended); DIR_EXTEND(b2EdgeShape); DIR_EXTEND(b2Filter); DIR_EXTEND(b2Fixture); DIR_EXTEND(b2FixtureDef); DIR_EXTEND(b2FixtureProxy); DIR_EXTEND(b2FrictionJoint); DIR_EXTEND(b2FrictionJointDef); DIR_EXTEND(b2GearJoint); DIR_EXTEND(b2GearJointDef); DIR_EXTEND(b2Jacobian); DIR_EXTEND(b2Joint); DIR_EXTEND(b2JointDef); DIR_EXTEND(b2JointEdge); DIR_EXTEND(b2WheelJoint); DIR_EXTEND(b2WheelJointDef); DIR_EXTEND(b2Manifold); DIR_EXTEND(b2ManifoldPoint); DIR_EXTEND(b2MassData); DIR_EXTEND(b2Mat22); DIR_EXTEND(b2Mat33); DIR_EXTEND(b2MouseJoint); DIR_EXTEND(b2MouseJointDef); DIR_EXTEND(b2Pair); DIR_EXTEND(b2PolygonShape); DIR_EXTEND(b2PrismaticJoint); DIR_EXTEND(b2PrismaticJointDef); DIR_EXTEND(b2PulleyJoint); DIR_EXTEND(b2PulleyJointDef); DIR_EXTEND(b2QueryCallback); DIR_EXTEND(b2RayCastCallback); DIR_EXTEND(b2RayCastInput); DIR_EXTEND(b2RayCastOutput); DIR_EXTEND(b2RevoluteJoint); DIR_EXTEND(b2RevoluteJointDef); DIR_EXTEND(b2RopeJoint); DIR_EXTEND(b2RopeJointDef); DIR_EXTEND(b2Shape); DIR_EXTEND(b2Sweep); DIR_EXTEND(b2TOIInput); DIR_EXTEND(b2TOIOutput); DIR_EXTEND(b2Transform); DIR_EXTEND(b2Vec2); DIR_EXTEND(b2Vec3); DIR_EXTEND(b2Version); DIR_EXTEND(b2WeldJoint); DIR_EXTEND(b2WeldJointDef); DIR_EXTEND(b2World); DIR_EXTEND(b2WorldManifold); pybox2d-2.3.2/Box2D/Box2D_doxygen.i000066400000000000000000003750521276457661000167020ustar00rootroot00000000000000 // File: index.xml // File: structb2_a_a_b_b.xml %feature("docstring") b2AABB "An axis aligned bounding box."; %feature("docstring") b2AABB::IsValid "Verify that the bounds are sorted."; %feature("docstring") b2AABB::GetCenter "Get the center of the AABB."; %feature("docstring") b2AABB::GetExtents "Get the extents of the AABB (half-widths)."; %feature("docstring") b2AABB::GetPerimeter "Get the perimeter length."; %feature("docstring") b2AABB::Combine "Combine an AABB into this one."; %feature("docstring") b2AABB::Combine "Combine two AABBs into this one."; %feature("docstring") b2AABB::Contains "Does this aabb contain the provided AABB."; %feature("docstring") b2AABB::IsValid "Verify that the bounds are sorted."; %feature("docstring") b2AABB::GetCenter "Get the center of the AABB."; %feature("docstring") b2AABB::GetExtents "Get the extents of the AABB (half-widths)."; %feature("docstring") b2AABB::GetPerimeter "Get the perimeter length."; %feature("docstring") b2AABB::Combine "Combine an AABB into this one."; %feature("docstring") b2AABB::Combine "Combine two AABBs into this one."; %feature("docstring") b2AABB::Contains "Does this aabb contain the provided AABB."; // File: classb2_block_allocator.xml %feature("docstring") b2BlockAllocator "This is a small object allocator used for allocating small objects that persist for more than one time step. See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp"; %feature("docstring") b2BlockAllocator::Allocate "Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize."; %feature("docstring") b2BlockAllocator::Free "Free memory. This will use b2Free if the size is larger than b2_maxBlockSize."; %feature("docstring") b2BlockAllocator::Allocate "Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize."; %feature("docstring") b2BlockAllocator::Free "Free memory. This will use b2Free if the size is larger than b2_maxBlockSize."; // File: classb2_body.xml %feature("docstring") b2Body "A rigid body. These are created via b2World::CreateBody."; %feature("docstring") b2Body::CreateFixture "Creates a fixture and attach it to this body. Use this function if you need to set some fixture parameters, like friction. Otherwise you can create the fixture directly from a shape. If the density is non-zero, this function automatically updates the mass of the body. Contacts are not created until the next time step. Parameters: ----------- def: the fixture definition. WARNING: This function is locked during callbacks."; %feature("docstring") b2Body::CreateFixture "Creates a fixture from a shape and attach it to this body. This is a convenience function. Use b2FixtureDefif you need to set parameters like friction, restitution, user data, or filtering. If the density is non-zero, this function automatically updates the mass of the body. Parameters: ----------- shape: the shape to be cloned. density: the shape density (set to zero for static bodies). WARNING: This function is locked during callbacks."; %feature("docstring") b2Body::DestroyFixture "Destroy a fixture. This removes the fixture from the broad-phase and destroys all contacts associated with this fixture. This will automatically adjust the mass of the body if the body is dynamic and the fixture has positive density. All fixtures attached to a body are implicitly destroyed when the body is destroyed. Parameters: ----------- fixture: the fixture to be removed. WARNING: This function is locked during callbacks."; %feature("docstring") b2Body::SetTransform "Set the position of the body's origin and rotation. This breaks any contacts and wakes the other bodies. Manipulating a body's transform may cause non-physical behavior. Parameters: ----------- position: the world position of the body's local origin. angle: the world rotation in radians."; %feature("docstring") b2Body::GetTransform "Get the body transform for the body's origin. the world transform of the body's origin."; %feature("docstring") b2Body::GetPosition "Get the world body origin position. the world position of the body's origin."; %feature("docstring") b2Body::GetAngle "Get the angle in radians. the current world rotation angle in radians."; %feature("docstring") b2Body::GetWorldCenter "Get the world position of the center of mass."; %feature("docstring") b2Body::GetLocalCenter "Get the local position of the center of mass."; %feature("docstring") b2Body::SetLinearVelocity "Set the linear velocity of the center of mass. Parameters: ----------- v: the new linear velocity of the center of mass."; %feature("docstring") b2Body::GetLinearVelocity "Get the linear velocity of the center of mass. the linear velocity of the center of mass."; %feature("docstring") b2Body::SetAngularVelocity "Set the angular velocity. Parameters: ----------- omega: the new angular velocity in radians/second."; %feature("docstring") b2Body::GetAngularVelocity "Get the angular velocity. the angular velocity in radians/second."; %feature("docstring") b2Body::ApplyForce "Apply a force at a world point. If the force is not applied at the center of mass, it will generate a torque and affect the angular velocity. This wakes up the body. Parameters: ----------- force: the world force vector, usually in Newtons (N). point: the world position of the point of application."; %feature("docstring") b2Body::ApplyTorque "Apply a torque. This affects the angular velocity without affecting the linear velocity of the center of mass. This wakes up the body. Parameters: ----------- torque: about the z-axis (out of the screen), usually in N-m."; %feature("docstring") b2Body::ApplyLinearImpulse "Apply an impulse at a point. This immediately modifies the velocity. It also modifies the angular velocity if the point of application is not at the center of mass. This wakes up the body. Parameters: ----------- impulse: the world impulse vector, usually in N-seconds or kg-m/s. point: the world position of the point of application."; %feature("docstring") b2Body::ApplyAngularImpulse "Apply an angular impulse. Parameters: ----------- impulse: the angular impulse in units of kg*m*m/s"; %feature("docstring") b2Body::GetMass "Get the total mass of the body. the mass, usually in kilograms (kg)."; %feature("docstring") b2Body::GetInertia "Get the rotational inertia of the body about the local origin. the rotational inertia, usually in kg-m^2."; %feature("docstring") b2Body::GetMassData "Get the mass data of the body. a struct containing the mass, inertia and center of the body."; %feature("docstring") b2Body::SetMassData "Set the mass properties to override the mass properties of the fixtures. Note that this changes the center of mass position. Note that creating or destroying fixtures can also alter the mass. This function has no effect if the body isn't dynamic. Parameters: ----------- massData: the mass properties."; %feature("docstring") b2Body::ResetMassData "This resets the mass properties to the sum of the mass properties of the fixtures. This normally does not need to be called unless you called SetMassData to override the mass and you later want to reset the mass."; %feature("docstring") b2Body::GetWorldPoint "Get the world coordinates of a point given the local coordinates. Parameters: ----------- localPoint: a point on the body measured relative the the body's origin. the same point expressed in world coordinates."; %feature("docstring") b2Body::GetWorldVector "Get the world coordinates of a vector given the local coordinates. Parameters: ----------- localVector: a vector fixed in the body. the same vector expressed in world coordinates."; %feature("docstring") b2Body::GetLocalPoint "Gets a local point relative to the body's origin given a world point. Parameters: ----------- a: point in world coordinates. the corresponding local point relative to the body's origin."; %feature("docstring") b2Body::GetLocalVector "Gets a local vector given a world vector. Parameters: ----------- a: vector in world coordinates. the corresponding local vector."; %feature("docstring") b2Body::GetLinearVelocityFromWorldPoint "Get the world linear velocity of a world point attached to this body. Parameters: ----------- a: point in world coordinates. the world velocity of a point."; %feature("docstring") b2Body::GetLinearVelocityFromLocalPoint "Get the world velocity of a local point. Parameters: ----------- a: point in local coordinates. the world velocity of a point."; %feature("docstring") b2Body::GetLinearDamping "Get the linear damping of the body."; %feature("docstring") b2Body::SetLinearDamping "Set the linear damping of the body."; %feature("docstring") b2Body::GetAngularDamping "Get the angular damping of the body."; %feature("docstring") b2Body::SetAngularDamping "Set the angular damping of the body."; %feature("docstring") b2Body::SetType "Set the type of this body. This may alter the mass and velocity."; %feature("docstring") b2Body::GetType "Get the type of this body."; %feature("docstring") b2Body::SetBullet "Should this body be treated like a bullet for continuous collision detection?"; %feature("docstring") b2Body::IsBullet "Is this body treated like a bullet for continuous collision detection?"; %feature("docstring") b2Body::SetSleepingAllowed "You can disable sleeping on this body. If you disable sleeping, the body will be woken."; %feature("docstring") b2Body::IsSleepingAllowed "Is this body allowed to sleep."; %feature("docstring") b2Body::SetAwake "Set the sleep state of the body. A sleeping body has very low CPU cost. Parameters: ----------- flag: set to true to put body to sleep, false to wake it."; %feature("docstring") b2Body::IsAwake "Get the sleeping state of this body. true if the body is sleeping."; %feature("docstring") b2Body::SetActive "Set the active state of the body. An inactive body is not simulated and cannot be collided with or woken up. If you pass a flag of true, all fixtures will be added to the broad-phase. If you pass a flag of false, all fixtures will be removed from the broad-phase and all contacts will be destroyed. Fixtures and joints are otherwise unaffected. You may continue to create/destroy fixtures and joints on inactive bodies. Fixtures on an inactive body are implicitly inactive and will not participate in collisions, ray-casts, or queries. Joints connected to an inactive body are implicitly inactive. An inactive body is still owned by a b2Worldobject and remains in the body list."; %feature("docstring") b2Body::IsActive "Get the active state of the body."; %feature("docstring") b2Body::SetFixedRotation "Set this body to have fixed rotation. This causes the mass to be reset."; %feature("docstring") b2Body::IsFixedRotation "Does this body have fixed rotation?"; %feature("docstring") b2Body::GetFixtureList "Get the list of all fixtures attached to this body."; %feature("docstring") b2Body::GetJointList "Get the list of all joints attached to this body."; %feature("docstring") b2Body::GetContactList "Get the list of all contacts attached to this body. WARNING: this list changes during the time step and you may miss some collisions if you don't use b2ContactListener."; %feature("docstring") b2Body::GetNext "Get the next body in the world's body list."; %feature("docstring") b2Body::GetUserData "Get the user data pointer that was provided in the body definition."; %feature("docstring") b2Body::SetUserData "Set the user data. Use this to store your application specific data."; %feature("docstring") b2Body::GetWorld "Get the parent world of this body."; %feature("docstring") b2Body::CreateFixture "Creates a fixture and attach it to this body. Use this function if you need to set some fixture parameters, like friction. Otherwise you can create the fixture directly from a shape. If the density is non-zero, this function automatically updates the mass of the body. Contacts are not created until the next time step. Parameters: ----------- def: the fixture definition. WARNING: This function is locked during callbacks."; %feature("docstring") b2Body::CreateFixture "Creates a fixture from a shape and attach it to this body. This is a convenience function. Use b2FixtureDefif you need to set parameters like friction, restitution, user data, or filtering. If the density is non-zero, this function automatically updates the mass of the body. Parameters: ----------- shape: the shape to be cloned. density: the shape density (set to zero for static bodies). WARNING: This function is locked during callbacks."; %feature("docstring") b2Body::DestroyFixture "Destroy a fixture. This removes the fixture from the broad-phase and destroys all contacts associated with this fixture. This will automatically adjust the mass of the body if the body is dynamic and the fixture has positive density. All fixtures attached to a body are implicitly destroyed when the body is destroyed. Parameters: ----------- fixture: the fixture to be removed. WARNING: This function is locked during callbacks."; %feature("docstring") b2Body::SetTransform "Set the position of the body's origin and rotation. This breaks any contacts and wakes the other bodies. Manipulating a body's transform may cause non-physical behavior. Parameters: ----------- position: the world position of the body's local origin. angle: the world rotation in radians."; %feature("docstring") b2Body::GetTransform "Get the body transform for the body's origin. the world transform of the body's origin."; %feature("docstring") b2Body::GetPosition "Get the world body origin position. the world position of the body's origin."; %feature("docstring") b2Body::GetAngle "Get the angle in radians. the current world rotation angle in radians."; %feature("docstring") b2Body::GetWorldCenter "Get the world position of the center of mass."; %feature("docstring") b2Body::GetLocalCenter "Get the local position of the center of mass."; %feature("docstring") b2Body::SetLinearVelocity "Set the linear velocity of the center of mass. Parameters: ----------- v: the new linear velocity of the center of mass."; %feature("docstring") b2Body::GetLinearVelocity "Get the linear velocity of the center of mass. the linear velocity of the center of mass."; %feature("docstring") b2Body::SetAngularVelocity "Set the angular velocity. Parameters: ----------- omega: the new angular velocity in radians/second."; %feature("docstring") b2Body::GetAngularVelocity "Get the angular velocity. the angular velocity in radians/second."; %feature("docstring") b2Body::ApplyForce "Apply a force at a world point. If the force is not applied at the center of mass, it will generate a torque and affect the angular velocity. This wakes up the body. Parameters: ----------- force: the world force vector, usually in Newtons (N). point: the world position of the point of application."; %feature("docstring") b2Body::ApplyTorque "Apply a torque. This affects the angular velocity without affecting the linear velocity of the center of mass. This wakes up the body. Parameters: ----------- torque: about the z-axis (out of the screen), usually in N-m."; %feature("docstring") b2Body::ApplyLinearImpulse "Apply an impulse at a point. This immediately modifies the velocity. It also modifies the angular velocity if the point of application is not at the center of mass. This wakes up the body. Parameters: ----------- impulse: the world impulse vector, usually in N-seconds or kg-m/s. point: the world position of the point of application."; %feature("docstring") b2Body::ApplyAngularImpulse "Apply an angular impulse. Parameters: ----------- impulse: the angular impulse in units of kg*m*m/s"; %feature("docstring") b2Body::GetMass "Get the total mass of the body. the mass, usually in kilograms (kg)."; %feature("docstring") b2Body::GetInertia "Get the rotational inertia of the body about the local origin. the rotational inertia, usually in kg-m^2."; %feature("docstring") b2Body::GetMassData "Get the mass data of the body. a struct containing the mass, inertia and center of the body."; %feature("docstring") b2Body::SetMassData "Set the mass properties to override the mass properties of the fixtures. Note that this changes the center of mass position. Note that creating or destroying fixtures can also alter the mass. This function has no effect if the body isn't dynamic. Parameters: ----------- massData: the mass properties."; %feature("docstring") b2Body::ResetMassData "This resets the mass properties to the sum of the mass properties of the fixtures. This normally does not need to be called unless you called SetMassData to override the mass and you later want to reset the mass."; %feature("docstring") b2Body::GetWorldPoint "Get the world coordinates of a point given the local coordinates. Parameters: ----------- localPoint: a point on the body measured relative the the body's origin. the same point expressed in world coordinates."; %feature("docstring") b2Body::GetWorldVector "Get the world coordinates of a vector given the local coordinates. Parameters: ----------- localVector: a vector fixed in the body. the same vector expressed in world coordinates."; %feature("docstring") b2Body::GetLocalPoint "Gets a local point relative to the body's origin given a world point. Parameters: ----------- a: point in world coordinates. the corresponding local point relative to the body's origin."; %feature("docstring") b2Body::GetLocalVector "Gets a local vector given a world vector. Parameters: ----------- a: vector in world coordinates. the corresponding local vector."; %feature("docstring") b2Body::GetLinearVelocityFromWorldPoint "Get the world linear velocity of a world point attached to this body. Parameters: ----------- a: point in world coordinates. the world velocity of a point."; %feature("docstring") b2Body::GetLinearVelocityFromLocalPoint "Get the world velocity of a local point. Parameters: ----------- a: point in local coordinates. the world velocity of a point."; %feature("docstring") b2Body::GetLinearDamping "Get the linear damping of the body."; %feature("docstring") b2Body::SetLinearDamping "Set the linear damping of the body."; %feature("docstring") b2Body::GetAngularDamping "Get the angular damping of the body."; %feature("docstring") b2Body::SetAngularDamping "Set the angular damping of the body."; %feature("docstring") b2Body::SetType "Set the type of this body. This may alter the mass and velocity."; %feature("docstring") b2Body::GetType "Get the type of this body."; %feature("docstring") b2Body::SetBullet "Should this body be treated like a bullet for continuous collision detection?"; %feature("docstring") b2Body::IsBullet "Is this body treated like a bullet for continuous collision detection?"; %feature("docstring") b2Body::SetSleepingAllowed "You can disable sleeping on this body. If you disable sleeping, the body will be woken."; %feature("docstring") b2Body::IsSleepingAllowed "Is this body allowed to sleep."; %feature("docstring") b2Body::SetAwake "Set the sleep state of the body. A sleeping body has very low CPU cost. Parameters: ----------- flag: set to true to put body to sleep, false to wake it."; %feature("docstring") b2Body::IsAwake "Get the sleeping state of this body. true if the body is sleeping."; %feature("docstring") b2Body::SetActive "Set the active state of the body. An inactive body is not simulated and cannot be collided with or woken up. If you pass a flag of true, all fixtures will be added to the broad-phase. If you pass a flag of false, all fixtures will be removed from the broad-phase and all contacts will be destroyed. Fixtures and joints are otherwise unaffected. You may continue to create/destroy fixtures and joints on inactive bodies. Fixtures on an inactive body are implicitly inactive and will not participate in collisions, ray-casts, or queries. Joints connected to an inactive body are implicitly inactive. An inactive body is still owned by a b2Worldobject and remains in the body list."; %feature("docstring") b2Body::IsActive "Get the active state of the body."; %feature("docstring") b2Body::SetFixedRotation "Set this body to have fixed rotation. This causes the mass to be reset."; %feature("docstring") b2Body::IsFixedRotation "Does this body have fixed rotation?"; %feature("docstring") b2Body::GetFixtureList "Get the list of all fixtures attached to this body."; %feature("docstring") b2Body::GetJointList "Get the list of all joints attached to this body."; %feature("docstring") b2Body::GetContactList "Get the list of all contacts attached to this body. WARNING: this list changes during the time step and you may miss some collisions if you don't use b2ContactListener."; %feature("docstring") b2Body::GetNext "Get the next body in the world's body list."; %feature("docstring") b2Body::GetUserData "Get the user data pointer that was provided in the body definition."; %feature("docstring") b2Body::SetUserData "Set the user data. Use this to store your application specific data."; %feature("docstring") b2Body::GetWorld "Get the parent world of this body."; // File: structb2_body_def.xml %feature("docstring") b2BodyDef "A body definition holds all the data needed to construct a rigid body. You can safely re-use body definitions. Shapes are added to a body after construction."; %feature("docstring") b2BodyDef::b2BodyDef "This constructor sets the body definition default values."; %feature("docstring") b2BodyDef::b2BodyDef "This constructor sets the body definition default values."; // File: classb2_broad_phase.xml %feature("docstring") b2BroadPhase "The broad-phase is used for computing pairs and performing volume queries and ray casts. This broad-phase does not persist pairs. Instead, this reports potentially new pairs. It is up to the client to consume the new pairs and to track subsequent overlap."; %feature("docstring") b2BroadPhase::CreateProxy "Create a proxy with an initial AABB. Pairs are not reported until UpdatePairs is called."; %feature("docstring") b2BroadPhase::DestroyProxy "Destroy a proxy. It is up to the client to remove any pairs."; %feature("docstring") b2BroadPhase::MoveProxy "Call MoveProxy as many times as you like, then when you are done call UpdatePairs to finalized the proxy pairs (for your time step)."; %feature("docstring") b2BroadPhase::TouchProxy "Call to trigger a re-processing of it's pairs on the next call to UpdatePairs."; %feature("docstring") b2BroadPhase::GetFatAABB "Get the fat AABB for a proxy."; %feature("docstring") b2BroadPhase::GetUserData "Get user data from a proxy. Returns NULL if the id is invalid."; %feature("docstring") b2BroadPhase::TestOverlap "Test overlap of fat AABBs."; %feature("docstring") b2BroadPhase::GetProxyCount "Get the number of proxies."; %feature("docstring") b2BroadPhase::UpdatePairs "Update the pairs. This results in pair callbacks. This can only add pairs."; %feature("docstring") b2BroadPhase::Query "Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB."; %feature("docstring") b2BroadPhase::RayCast "Ray-cast against the proxies in the tree. This relies on the callback to perform a exact ray-cast in the case were the proxy contains a shape. The callback also performs the any collision filtering. This has performance roughly equal to k * log(n), where k is the number of collisions and n is the number of proxies in the tree. Parameters: ----------- input: the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). callback: a callback class that is called for each proxy that is hit by the ray."; %feature("docstring") b2BroadPhase::ComputeHeight "Compute the height of the embedded tree."; %feature("docstring") b2BroadPhase::CreateProxy "Create a proxy with an initial AABB. Pairs are not reported until UpdatePairs is called."; %feature("docstring") b2BroadPhase::DestroyProxy "Destroy a proxy. It is up to the client to remove any pairs."; %feature("docstring") b2BroadPhase::MoveProxy "Call MoveProxy as many times as you like, then when you are done call UpdatePairs to finalized the proxy pairs (for your time step)."; %feature("docstring") b2BroadPhase::TouchProxy "Call to trigger a re-processing of it's pairs on the next call to UpdatePairs."; %feature("docstring") b2BroadPhase::GetFatAABB "Get the fat AABB for a proxy."; %feature("docstring") b2BroadPhase::GetUserData "Get user data from a proxy. Returns NULL if the id is invalid."; %feature("docstring") b2BroadPhase::TestOverlap "Test overlap of fat AABBs."; %feature("docstring") b2BroadPhase::GetProxyCount "Get the number of proxies."; %feature("docstring") b2BroadPhase::UpdatePairs "Update the pairs. This results in pair callbacks. This can only add pairs."; %feature("docstring") b2BroadPhase::Query "Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB."; %feature("docstring") b2BroadPhase::RayCast "Ray-cast against the proxies in the tree. This relies on the callback to perform a exact ray-cast in the case were the proxy contains a shape. The callback also performs the any collision filtering. This has performance roughly equal to k * log(n), where k is the number of collisions and n is the number of proxies in the tree. Parameters: ----------- input: the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). callback: a callback class that is called for each proxy that is hit by the ray."; %feature("docstring") b2BroadPhase::ComputeHeight "Compute the height of the embedded tree."; // File: classb2_circle_shape.xml %feature("docstring") b2CircleShape "A circle shape."; %feature("docstring") b2CircleShape::Clone "Implement b2Shape."; %feature("docstring") b2CircleShape::GetChildCount " See: b2Shape::GetChildCount"; %feature("docstring") b2CircleShape::TestPoint "Implement b2Shape."; %feature("docstring") b2CircleShape::RayCast "Implement b2Shape."; %feature("docstring") b2CircleShape::ComputeAABB " See: b2Shape::ComputeAABB"; %feature("docstring") b2CircleShape::ComputeMass " See: b2Shape::ComputeMass"; %feature("docstring") b2CircleShape::GetSupport "Get the supporting vertex index in the given direction."; %feature("docstring") b2CircleShape::GetSupportVertex "Get the supporting vertex in the given direction."; %feature("docstring") b2CircleShape::GetVertexCount "Get the vertex count."; %feature("docstring") b2CircleShape::GetVertex "Get a vertex by index. Used by b2Distance."; %feature("docstring") b2CircleShape::Clone "Implement b2Shape."; %feature("docstring") b2CircleShape::GetChildCount " See: b2Shape::GetChildCount"; %feature("docstring") b2CircleShape::TestPoint "Implement b2Shape."; %feature("docstring") b2CircleShape::RayCast "Implement b2Shape."; %feature("docstring") b2CircleShape::ComputeAABB " See: b2Shape::ComputeAABB"; %feature("docstring") b2CircleShape::ComputeMass " See: b2Shape::ComputeMass"; %feature("docstring") b2CircleShape::GetSupport "Get the supporting vertex index in the given direction."; %feature("docstring") b2CircleShape::GetSupportVertex "Get the supporting vertex in the given direction."; %feature("docstring") b2CircleShape::GetVertexCount "Get the vertex count."; %feature("docstring") b2CircleShape::GetVertex "Get a vertex by index. Used by b2Distance."; // File: structb2_clip_vertex.xml %feature("docstring") b2ClipVertex "Used for computing contact manifolds."; // File: structb2_color.xml %feature("docstring") b2Color "Color for debug drawing. Each value has the range [0,1]."; // File: classb2_contact.xml %feature("docstring") b2Contact "The class manages contact between two shapes. A contact exists for each overlapping AABB in the broad-phase (except if filtered). Therefore a contact object may exist that has no contact points."; %feature("docstring") b2Contact::GetManifold "Get the contact manifold. Do not modify the manifold unless you understand the internals of Box2D."; %feature("docstring") b2Contact::GetWorldManifold "Get the world manifold."; %feature("docstring") b2Contact::IsTouching "Is this contact touching?"; %feature("docstring") b2Contact::SetEnabled "Enable/disable this contact. This can be used inside the pre-solve contact listener. The contact is only disabled for the current time step (or sub-step in continuous collisions)."; %feature("docstring") b2Contact::IsEnabled "Has this contact been disabled?"; %feature("docstring") b2Contact::GetNext "Get the next contact in the world's contact list."; %feature("docstring") b2Contact::GetFixtureA "Get fixture A in this contact."; %feature("docstring") b2Contact::GetChildIndexA "Get the child primitive index for fixture A."; %feature("docstring") b2Contact::GetFixtureB "Get fixture B in this contact."; %feature("docstring") b2Contact::GetChildIndexB "Get the child primitive index for fixture B."; %feature("docstring") b2Contact::SetFriction "Override the default friction mixture. You can call this in b2ContactListener::PreSolve. This value persists until set or reset."; %feature("docstring") b2Contact::GetFriction "Get the friction."; %feature("docstring") b2Contact::ResetFriction "Reset the friction mixture to the default value."; %feature("docstring") b2Contact::SetRestitution "Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. The value persists until you set or reset."; %feature("docstring") b2Contact::GetRestitution "Get the restitution."; %feature("docstring") b2Contact::ResetRestitution "Reset the restitution to the default value."; %feature("docstring") b2Contact::Evaluate "Evaluate this contact with your own manifold and transforms."; %feature("docstring") b2Contact::GetManifold "Get the contact manifold. Do not modify the manifold unless you understand the internals of Box2D."; %feature("docstring") b2Contact::GetWorldManifold "Get the world manifold."; %feature("docstring") b2Contact::IsTouching "Is this contact touching?"; %feature("docstring") b2Contact::SetEnabled "Enable/disable this contact. This can be used inside the pre-solve contact listener. The contact is only disabled for the current time step (or sub-step in continuous collisions)."; %feature("docstring") b2Contact::IsEnabled "Has this contact been disabled?"; %feature("docstring") b2Contact::GetNext "Get the next contact in the world's contact list."; %feature("docstring") b2Contact::GetFixtureA "Get fixture A in this contact."; %feature("docstring") b2Contact::GetChildIndexA "Get the child primitive index for fixture A."; %feature("docstring") b2Contact::GetFixtureB "Get fixture B in this contact."; %feature("docstring") b2Contact::GetChildIndexB "Get the child primitive index for fixture B."; %feature("docstring") b2Contact::Evaluate "Evaluate this contact with your own manifold and transforms."; // File: structb2_contact_edge.xml %feature("docstring") b2ContactEdge "A contact edge is used to connect bodies and contacts together in a contact graph where each body is a node and each contact is an edge. A contact edge belongs to a doubly linked list maintained in each attached body. Each contact has two contact nodes, one for each attached body."; // File: structb2_contact_feature.xml %feature("docstring") b2ContactFeature "The features that intersect to form the contact point This must be 4 bytes or less."; // File: classb2_contact_filter.xml %feature("docstring") b2ContactFilter "Implement this class to provide collision filtering. In other words, you can implement this class if you want finer control over contact creation."; %feature("docstring") b2ContactFilter::ShouldCollide "Return true if contact calculations should be performed between these two shapes. WARNING: for performance reasons this is only called when the AABBs begin to overlap."; %feature("docstring") b2ContactFilter::ShouldCollide "Return true if contact calculations should be performed between these two shapes. WARNING: for performance reasons this is only called when the AABBs begin to overlap."; // File: structb2_contact_impulse.xml %feature("docstring") b2ContactImpulse "Contact impulses for reporting. Impulses are used instead of forces because sub-step forces may approach infinity for rigid body collisions. These match up one-to-one with the contact points in b2Manifold."; // File: classb2_contact_listener.xml %feature("docstring") b2ContactListener "Implement this class to get contact information. You can use these results for things like sounds and game logic. You can also get contact results by traversing the contact lists after the time step. However, you might miss some contacts because continuous physics leads to sub-stepping. Additionally you may receive multiple callbacks for the same contact in a single time step. You should strive to make your callbacks efficient because there may be many callbacks per time step. WARNING: You cannot create/destroy Box2D entities inside these callbacks."; %feature("docstring") b2ContactListener::BeginContact "Called when two fixtures begin to touch."; %feature("docstring") b2ContactListener::EndContact "Called when two fixtures cease to touch."; %feature("docstring") b2ContactListener::PreSolve "This is called after a contact is updated. This allows you to inspect a contact before it goes to the solver. If you are careful, you can modify the contact manifold (e.g. disable contact). A copy of the old manifold is provided so that you can detect changes. Note: this is called only for awake bodies. Note: this is called even when the number of contact points is zero. Note: this is not called for sensors. Note: if you set the number of contact points to zero, you will not get an EndContact callback. However, you may get a BeginContact callback the next step."; %feature("docstring") b2ContactListener::PostSolve "This lets you inspect a contact after the solver is finished. This is useful for inspecting impulses. Note: the contact manifold does not include time of impact impulses, which can be arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly in a separate data structure. Note: this is only called for contacts that are touching, solid, and awake."; %feature("docstring") b2ContactListener::BeginContact "Called when two fixtures begin to touch."; %feature("docstring") b2ContactListener::EndContact "Called when two fixtures cease to touch."; %feature("docstring") b2ContactListener::PreSolve "This is called after a contact is updated. This allows you to inspect a contact before it goes to the solver. If you are careful, you can modify the contact manifold (e.g. disable contact). A copy of the old manifold is provided so that you can detect changes. Note: this is called only for awake bodies. Note: this is called even when the number of contact points is zero. Note: this is not called for sensors. Note: if you set the number of contact points to zero, you will not get an EndContact callback. However, you may get a BeginContact callback the next step."; %feature("docstring") b2ContactListener::PostSolve "This lets you inspect a contact after the solver is finished. This is useful for inspecting impulses. Note: the contact manifold does not include time of impact impulses, which can be arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly in a separate data structure. Note: this is only called for contacts that are touching, solid, and awake."; // File: classb2_destruction_listener.xml %feature("docstring") b2DestructionListener "Joints and fixtures are destroyed when their associated body is destroyed. Implement this listener so that you may nullify references to these joints and shapes."; %feature("docstring") b2DestructionListener::SayGoodbye "Called when any joint is about to be destroyed due to the destruction of one of its attached bodies."; %feature("docstring") b2DestructionListener::SayGoodbye "Called when any fixture is about to be destroyed due to the destruction of its parent body."; %feature("docstring") b2DestructionListener::SayGoodbye "Called when any joint is about to be destroyed due to the destruction of one of its attached bodies."; %feature("docstring") b2DestructionListener::SayGoodbye "Called when any fixture is about to be destroyed due to the destruction of its parent body."; // File: structb2_distance_input.xml %feature("docstring") b2DistanceInput "Input for b2Distance. You have to option to use the shape radii in the computation. Even"; // File: classb2_distance_joint.xml %feature("docstring") b2DistanceJoint "A distance joint constrains two points on two bodies to remain at a fixed distance from each other. You can view this as a massless, rigid rod."; %feature("docstring") b2DistanceJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2DistanceJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2DistanceJoint::GetReactionForce "Get the reaction force given the inverse time step. Unit is N."; %feature("docstring") b2DistanceJoint::GetReactionTorque "Get the reaction torque given the inverse time step. Unit is N*m. This is always zero for a distance joint."; %feature("docstring") b2DistanceJoint::SetLength "Set/get the natural length. Manipulating the length can lead to non-physical behavior when the frequency is zero."; %feature("docstring") b2DistanceJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2DistanceJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2DistanceJoint::GetReactionForce "Get the reaction force given the inverse time step. Unit is N."; %feature("docstring") b2DistanceJoint::GetReactionTorque "Get the reaction torque given the inverse time step. Unit is N*m. This is always zero for a distance joint."; %feature("docstring") b2DistanceJoint::SetLength "Set/get the natural length. Manipulating the length can lead to non-physical behavior when the frequency is zero."; // File: structb2_distance_joint_def.xml %feature("docstring") b2DistanceJointDef "Distance joint definition. This requires defining an anchor point on both bodies and the non-zero length of the distance joint. The definition uses local anchor points so that the initial configuration can violate the constraint slightly. This helps when saving and loading a game. WARNING: Do not use a zero or short length."; %feature("docstring") b2DistanceJointDef::Initialize "Initialize the bodies, anchors, and length using the world anchors."; %feature("docstring") b2DistanceJointDef::Initialize "Initialize the bodies, anchors, and length using the world anchors."; // File: structb2_distance_output.xml %feature("docstring") b2DistanceOutput "Output for b2Distance."; // File: structb2_distance_proxy.xml %feature("docstring") b2DistanceProxy "A distance proxy is used by the GJK algorithm. It encapsulates any shape."; %feature("docstring") b2DistanceProxy::Set "Initialize the proxy using the given shape. The shape must remain in scope while the proxy is in use."; %feature("docstring") b2DistanceProxy::GetSupport "Get the supporting vertex index in the given direction."; %feature("docstring") b2DistanceProxy::GetSupportVertex "Get the supporting vertex in the given direction."; %feature("docstring") b2DistanceProxy::GetVertexCount "Get the vertex count."; %feature("docstring") b2DistanceProxy::GetVertex "Get a vertex by index. Used by b2Distance."; %feature("docstring") b2DistanceProxy::Set "Initialize the proxy using the given shape. The shape must remain in scope while the proxy is in use."; %feature("docstring") b2DistanceProxy::GetSupport "Get the supporting vertex index in the given direction."; %feature("docstring") b2DistanceProxy::GetSupportVertex "Get the supporting vertex in the given direction."; %feature("docstring") b2DistanceProxy::GetVertexCount "Get the vertex count."; %feature("docstring") b2DistanceProxy::GetVertex "Get a vertex by index. Used by b2Distance."; // File: classb2_draw.xml %feature("docstring") b2Draw "Implement and register this class with a b2Worldto provide debug drawing of physics entities in your game."; %feature("docstring") b2Draw::SetFlags "Set the drawing flags."; %feature("docstring") b2Draw::GetFlags "Get the drawing flags."; %feature("docstring") b2Draw::AppendFlags "Append flags to the current flags."; %feature("docstring") b2Draw::ClearFlags "Clear flags from the current flags."; %feature("docstring") b2Draw::DrawPolygon "Draw a closed polygon provided in CCW order."; %feature("docstring") b2Draw::DrawSolidPolygon "Draw a solid closed polygon provided in CCW order."; %feature("docstring") b2Draw::DrawCircle "Draw a circle."; %feature("docstring") b2Draw::DrawSolidCircle "Draw a solid circle."; %feature("docstring") b2Draw::DrawSegment "Draw a line segment."; %feature("docstring") b2Draw::DrawTransform "Draw a transform. Choose your own length scale. Parameters: ----------- xf: a transform."; %feature("docstring") b2Draw::SetFlags "Set the drawing flags."; %feature("docstring") b2Draw::GetFlags "Get the drawing flags."; %feature("docstring") b2Draw::AppendFlags "Append flags to the current flags."; %feature("docstring") b2Draw::ClearFlags "Clear flags from the current flags."; %feature("docstring") b2Draw::DrawPolygon "Draw a closed polygon provided in CCW order."; %feature("docstring") b2Draw::DrawSolidPolygon "Draw a solid closed polygon provided in CCW order."; %feature("docstring") b2Draw::DrawCircle "Draw a circle."; %feature("docstring") b2Draw::DrawSolidCircle "Draw a solid circle."; %feature("docstring") b2Draw::DrawSegment "Draw a line segment."; %feature("docstring") b2Draw::DrawTransform "Draw a transform. Choose your own length scale. Parameters: ----------- xf: a transform."; // File: classb2_dynamic_tree.xml %feature("docstring") b2DynamicTree "A dynamic tree arranges data in a binary tree to accelerate queries such as volume queries and ray casts. Leafs are proxies with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor so that the proxy AABB is bigger than the client object. This allows the client object to move by small amounts without triggering a tree update. Nodes are pooled and relocatable, so we use node indices rather than pointers."; %feature("docstring") b2DynamicTree::b2DynamicTree "Constructing the tree initializes the node pool."; %feature("docstring") b2DynamicTree::~b2DynamicTree "Destroy the tree, freeing the node pool."; %feature("docstring") b2DynamicTree::CreateProxy "Create a proxy. Provide a tight fitting AABB and a userData pointer."; %feature("docstring") b2DynamicTree::DestroyProxy "Destroy a proxy. This asserts if the id is invalid."; %feature("docstring") b2DynamicTree::MoveProxy "Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, then the proxy is removed from the tree and re-inserted. Otherwise the function returns immediately. true if the proxy was re-inserted."; %feature("docstring") b2DynamicTree::Rebalance "Perform some iterations to re-balance the tree."; %feature("docstring") b2DynamicTree::GetUserData "Get proxy user data. the proxy user data or 0 if the id is invalid."; %feature("docstring") b2DynamicTree::GetFatAABB "Get the fat AABB for a proxy."; %feature("docstring") b2DynamicTree::ComputeHeight "Compute the height of the binary tree in O(N) time. Should not be called often."; %feature("docstring") b2DynamicTree::Query "Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB."; %feature("docstring") b2DynamicTree::RayCast "Ray-cast against the proxies in the tree. This relies on the callback to perform a exact ray-cast in the case were the proxy contains a shape. The callback also performs the any collision filtering. This has performance roughly equal to k * log(n), where k is the number of collisions and n is the number of proxies in the tree. Parameters: ----------- input: the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). callback: a callback class that is called for each proxy that is hit by the ray."; %feature("docstring") b2DynamicTree::b2DynamicTree "Constructing the tree initializes the node pool."; %feature("docstring") b2DynamicTree::~b2DynamicTree "Destroy the tree, freeing the node pool."; %feature("docstring") b2DynamicTree::CreateProxy "Create a proxy. Provide a tight fitting AABB and a userData pointer."; %feature("docstring") b2DynamicTree::DestroyProxy "Destroy a proxy. This asserts if the id is invalid."; %feature("docstring") b2DynamicTree::MoveProxy "Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, then the proxy is removed from the tree and re-inserted. Otherwise the function returns immediately. true if the proxy was re-inserted."; %feature("docstring") b2DynamicTree::Rebalance "Perform some iterations to re-balance the tree."; %feature("docstring") b2DynamicTree::GetUserData "Get proxy user data. the proxy user data or 0 if the id is invalid."; %feature("docstring") b2DynamicTree::GetFatAABB "Get the fat AABB for a proxy."; %feature("docstring") b2DynamicTree::ComputeHeight "Compute the height of the binary tree in O(N) time. Should not be called often."; %feature("docstring") b2DynamicTree::Query "Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB."; %feature("docstring") b2DynamicTree::RayCast "Ray-cast against the proxies in the tree. This relies on the callback to perform a exact ray-cast in the case were the proxy contains a shape. The callback also performs the any collision filtering. This has performance roughly equal to k * log(n), where k is the number of collisions and n is the number of proxies in the tree. Parameters: ----------- input: the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). callback: a callback class that is called for each proxy that is hit by the ray."; // File: structb2_dynamic_tree_node.xml %feature("docstring") b2DynamicTreeNode "A node in the dynamic tree. The client does not interact with this directly. A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt."; // File: classb2_edge_shape.xml %feature("docstring") b2EdgeShape "A line segment (edge) shape. These can be connected in chains or loops to other edge shapes. The connectivity information is used to ensure correct contact normals."; %feature("docstring") b2EdgeShape::Set "Set this as an isolated edge."; %feature("docstring") b2EdgeShape::Clone "Implement b2Shape."; %feature("docstring") b2EdgeShape::GetChildCount " See: b2Shape::GetChildCount"; %feature("docstring") b2EdgeShape::TestPoint " See: b2Shape::TestPoint"; %feature("docstring") b2EdgeShape::RayCast "Implement b2Shape."; %feature("docstring") b2EdgeShape::ComputeAABB " See: b2Shape::ComputeAABB"; %feature("docstring") b2EdgeShape::ComputeMass " See: b2Shape::ComputeMass"; %feature("docstring") b2EdgeShape::Set "Set this as an isolated edge."; %feature("docstring") b2EdgeShape::Clone "Implement b2Shape."; %feature("docstring") b2EdgeShape::GetChildCount " See: b2Shape::GetChildCount"; %feature("docstring") b2EdgeShape::TestPoint " See: b2Shape::TestPoint"; %feature("docstring") b2EdgeShape::RayCast "Implement b2Shape."; %feature("docstring") b2EdgeShape::ComputeAABB " See: b2Shape::ComputeAABB"; %feature("docstring") b2EdgeShape::ComputeMass " See: b2Shape::ComputeMass"; // File: structb2_filter.xml %feature("docstring") b2Filter "This holds contact filtering data."; // File: classb2_fixture.xml %feature("docstring") b2Fixture "A fixture is used to attach a shape to a body for collision detection. A fixture inherits its transform from its parent. Fixtures hold additional non-geometric data such as friction, collision filters, etc. Fixtures are created via b2Body::CreateFixture. WARNING: you cannot reuse fixtures."; %feature("docstring") b2Fixture::GetType "Get the type of the child shape. You can use this to down cast to the concrete shape. the shape type."; %feature("docstring") b2Fixture::GetShape "Get the child shape. You can modify the child shape, however you should not change the number of vertices because this will crash some collision caching mechanisms. Manipulating the shape may lead to non-physical behavior."; %feature("docstring") b2Fixture::SetSensor "Set if this fixture is a sensor."; %feature("docstring") b2Fixture::IsSensor "Is this fixture a sensor (non-solid)? the true if the shape is a sensor."; %feature("docstring") b2Fixture::SetFilterData "Set the contact filtering data. This will not update contacts until the next time step when either parent body is active and awake. This automatically calls Refilter."; %feature("docstring") b2Fixture::GetFilterData "Get the contact filtering data."; %feature("docstring") b2Fixture::Refilter "Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide."; %feature("docstring") b2Fixture::GetBody "Get the parent body of this fixture. This is NULL if the fixture is not attached. the parent body."; %feature("docstring") b2Fixture::GetNext "Get the next fixture in the parent body's fixture list. the next shape."; %feature("docstring") b2Fixture::GetUserData "Get the user data that was assigned in the fixture definition. Use this to store your application specific data."; %feature("docstring") b2Fixture::SetUserData "Set the user data. Use this to store your application specific data."; %feature("docstring") b2Fixture::TestPoint "Test a point for containment in this fixture. Parameters: ----------- p: a point in world coordinates."; %feature("docstring") b2Fixture::RayCast "Cast a ray against this shape. Parameters: ----------- output: the ray-cast results. input: the ray-cast input parameters."; %feature("docstring") b2Fixture::GetMassData "Get the mass data for this fixture. The mass data is based on the density and the shape. The rotational inertia is about the shape's origin. This operation may be expensive."; %feature("docstring") b2Fixture::SetDensity "Set the density of this fixture. This will _not_ automatically adjust the mass of the body. You must call b2Body::ResetMassDatato update the body's mass."; %feature("docstring") b2Fixture::GetDensity "Get the density of this fixture."; %feature("docstring") b2Fixture::GetFriction "Get the coefficient of friction."; %feature("docstring") b2Fixture::SetFriction "Set the coefficient of friction. This will immediately update the mixed friction on all associated contacts."; %feature("docstring") b2Fixture::GetRestitution "Get the coefficient of restitution."; %feature("docstring") b2Fixture::SetRestitution "Set the coefficient of restitution. This will immediately update the mixed restitution on all associated contacts."; %feature("docstring") b2Fixture::GetAABB "Get the fixture's AABB. This AABB may be enlarge and/or stale. If you need a more accurate AABB, compute it using the shape and the body transform."; %feature("docstring") b2Fixture::GetType "Get the type of the child shape. You can use this to down cast to the concrete shape. the shape type."; %feature("docstring") b2Fixture::GetShape "Get the child shape. You can modify the child shape, however you should not change the number of vertices because this will crash some collision caching mechanisms. Manipulating the shape may lead to non-physical behavior."; %feature("docstring") b2Fixture::SetSensor "Set if this fixture is a sensor."; %feature("docstring") b2Fixture::IsSensor "Is this fixture a sensor (non-solid)? the true if the shape is a sensor."; %feature("docstring") b2Fixture::SetFilterData "Set the contact filtering data. This will not update contacts until the next time step when either parent body is active and awake. This automatically calls Refilter."; %feature("docstring") b2Fixture::GetFilterData "Get the contact filtering data."; %feature("docstring") b2Fixture::Refilter "Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide."; %feature("docstring") b2Fixture::GetBody "Get the parent body of this fixture. This is NULL if the fixture is not attached. the parent body."; %feature("docstring") b2Fixture::GetNext "Get the next fixture in the parent body's fixture list. the next shape."; %feature("docstring") b2Fixture::GetUserData "Get the user data that was assigned in the fixture definition. Use this to store your application specific data."; %feature("docstring") b2Fixture::SetUserData "Set the user data. Use this to store your application specific data."; %feature("docstring") b2Fixture::TestPoint "Test a point for containment in this fixture. Parameters: ----------- p: a point in world coordinates."; %feature("docstring") b2Fixture::RayCast "Cast a ray against this shape. Parameters: ----------- output: the ray-cast results. input: the ray-cast input parameters."; %feature("docstring") b2Fixture::GetMassData "Get the mass data for this fixture. The mass data is based on the density and the shape. The rotational inertia is about the shape's origin. This operation may be expensive."; %feature("docstring") b2Fixture::SetDensity "Set the density of this fixture. This will _not_ automatically adjust the mass of the body. You must call b2Body::ResetMassDatato update the body's mass."; %feature("docstring") b2Fixture::GetDensity "Get the density of this fixture."; %feature("docstring") b2Fixture::GetFriction "Get the coefficient of friction."; %feature("docstring") b2Fixture::SetFriction "Set the coefficient of friction. This will immediately update the mixed friction on all associated contacts."; %feature("docstring") b2Fixture::GetRestitution "Get the coefficient of restitution."; %feature("docstring") b2Fixture::SetRestitution "Set the coefficient of restitution. This will immediately update the mixed restitution on all associated contacts."; %feature("docstring") b2Fixture::GetAABB "Get the fixture's AABB. This AABB may be enlarge and/or stale. If you need a more accurate AABB, compute it using the shape and the body transform."; // File: structb2_fixture_def.xml %feature("docstring") b2FixtureDef "A fixture definition is used to create a fixture. This class defines an abstract fixture definition. You can reuse fixture definitions safely."; %feature("docstring") b2FixtureDef::b2FixtureDef "The constructor sets the default fixture definition values."; %feature("docstring") b2FixtureDef::b2FixtureDef "The constructor sets the default fixture definition values."; // File: structb2_fixture_proxy.xml %feature("docstring") b2FixtureProxy "This proxy is used internally to connect fixtures to the broad-phase."; // File: classb2_friction_joint.xml %feature("docstring") b2FrictionJoint "Friction joint. This is used for top-down friction. It provides 2D translational friction and angular friction."; %feature("docstring") b2FrictionJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2FrictionJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2FrictionJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2FrictionJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2FrictionJoint::SetMaxForce "Set the maximum friction force in N."; %feature("docstring") b2FrictionJoint::GetMaxForce "Get the maximum friction force in N."; %feature("docstring") b2FrictionJoint::SetMaxTorque "Set the maximum friction torque in N*m."; %feature("docstring") b2FrictionJoint::GetMaxTorque "Get the maximum friction torque in N*m."; %feature("docstring") b2FrictionJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2FrictionJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2FrictionJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2FrictionJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2FrictionJoint::SetMaxForce "Set the maximum friction force in N."; %feature("docstring") b2FrictionJoint::GetMaxForce "Get the maximum friction force in N."; %feature("docstring") b2FrictionJoint::SetMaxTorque "Set the maximum friction torque in N*m."; %feature("docstring") b2FrictionJoint::GetMaxTorque "Get the maximum friction torque in N*m."; // File: structb2_friction_joint_def.xml %feature("docstring") b2FrictionJointDef "Friction joint definition."; %feature("docstring") b2FrictionJointDef::Initialize "Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis."; %feature("docstring") b2FrictionJointDef::Initialize "Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis."; // File: classb2_gear_joint.xml %feature("docstring") b2GearJoint "A gear joint is used to connect two joints together. Either joint can be a revolute or prismatic joint. You specify a gear ratio to bind the motions together: coordinate1 + ratio * coordinate2 = constant The ratio can be negative or positive. If one joint is a revolute joint and the other joint is a prismatic joint, then the ratio will have units of length or units of 1/length. WARNING: The revolute and prismatic joints must be attached to fixed bodies (which must be body1 on those joints)."; %feature("docstring") b2GearJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2GearJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2GearJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2GearJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2GearJoint::SetRatio "Set/Get the gear ratio."; %feature("docstring") b2GearJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2GearJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2GearJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2GearJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2GearJoint::SetRatio "Set/Get the gear ratio."; // File: structb2_gear_joint_def.xml %feature("docstring") b2GearJointDef "Gear joint definition. This definition requires two existing revolute or prismatic joints (any combination will work). The provided joints must attach a dynamic body to a static body."; // File: classb2_growable_stack.xml %feature("docstring") b2GrowableStack "This is a growable LIFO stack with an initial capacity of N. If the stack size exceeds the initial capacity, the heap is used to increase the size of the stack."; // File: classb2_island.xml %feature("docstring") b2Island "This is an internal class."; // File: classb2_joint.xml %feature("docstring") b2Joint "The base joint class. Joints are used to constraint two bodies together in various fashions. Some joints also feature limits and motors."; %feature("docstring") b2Joint::GetType "Get the type of the concrete joint."; %feature("docstring") b2Joint::GetBodyA "Get the first body attached to this joint."; %feature("docstring") b2Joint::GetBodyB "Get the second body attached to this joint."; %feature("docstring") b2Joint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2Joint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2Joint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2Joint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2Joint::GetNext "Get the next joint the world joint list."; %feature("docstring") b2Joint::GetUserData "Get the user data pointer."; %feature("docstring") b2Joint::SetUserData "Set the user data pointer."; %feature("docstring") b2Joint::IsActive "Short-cut function to determine if either body is inactive."; %feature("docstring") b2Joint::GetType "Get the type of the concrete joint."; %feature("docstring") b2Joint::GetBodyA "Get the first body attached to this joint."; %feature("docstring") b2Joint::GetBodyB "Get the second body attached to this joint."; %feature("docstring") b2Joint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2Joint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2Joint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2Joint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2Joint::GetNext "Get the next joint the world joint list."; %feature("docstring") b2Joint::GetUserData "Get the user data pointer."; %feature("docstring") b2Joint::SetUserData "Set the user data pointer."; %feature("docstring") b2Joint::IsActive "Short-cut function to determine if either body is inactive."; // File: structb2_joint_def.xml %feature("docstring") b2JointDef "Joint definitions are used to construct joints."; // File: structb2_joint_edge.xml %feature("docstring") b2JointEdge "A joint edge is used to connect bodies and joints together in a joint graph where each body is a node and each joint is an edge. A joint edge belongs to a doubly linked list maintained in each attached body. Each joint has two joint nodes, one for each attached body."; // File: classb2_line_joint.xml %feature("docstring") b2WheelJoint "A line joint. This joint provides two degrees of freedom: translation along an axis fixed in body1 and rotation in the plane. You can use a joint limit to restrict the range of motion and a joint motor to drive the rotation or to model rotational friction. This joint is designed for vehicle suspensions."; %feature("docstring") b2WheelJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2WheelJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2WheelJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2WheelJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2WheelJoint::GetJointTranslation "Get the current joint translation, usually in meters."; %feature("docstring") b2WheelJoint::GetJointSpeed "Get the current joint translation speed, usually in meters per second."; %feature("docstring") b2WheelJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2WheelJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2WheelJoint::SetMotorSpeed "Set the motor speed, usually in radians per second."; %feature("docstring") b2WheelJoint::GetMotorSpeed "Get the motor speed, usually in radians per second."; %feature("docstring") b2WheelJoint::SetMaxMotorTorque "Set/Get the maximum motor force, usually in N-m."; %feature("docstring") b2WheelJoint::GetMotorTorque "Get the current motor torque given the inverse time step, usually in N-m."; %feature("docstring") b2WheelJoint::SetSpringFrequencyHz "Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring."; %feature("docstring") b2WheelJoint::SetSpringDampingRatio "Set/Get the spring damping ratio."; %feature("docstring") b2WheelJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2WheelJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2WheelJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2WheelJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2WheelJoint::GetJointTranslation "Get the current joint translation, usually in meters."; %feature("docstring") b2WheelJoint::GetJointSpeed "Get the current joint translation speed, usually in meters per second."; %feature("docstring") b2WheelJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2WheelJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2WheelJoint::SetMotorSpeed "Set the motor speed, usually in radians per second."; %feature("docstring") b2WheelJoint::GetMotorSpeed "Get the motor speed, usually in radians per second."; %feature("docstring") b2WheelJoint::SetMaxMotorTorque "Set/Get the maximum motor force, usually in N-m."; %feature("docstring") b2WheelJoint::GetMotorTorque "Get the current motor torque given the inverse time step, usually in N-m."; %feature("docstring") b2WheelJoint::SetSpringFrequencyHz "Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring."; %feature("docstring") b2WheelJoint::SetSpringDampingRatio "Set/Get the spring damping ratio."; // File: structb2_line_joint_def.xml %feature("docstring") b2WheelJointDef "Line joint definition. This requires defining a line of motion using an axis and an anchor point. The definition uses local anchor points and a local axis so that the initial configuration can violate the constraint slightly. The joint translation is zero when the local anchor points coincide in world space. Using local anchors and a local axis helps when saving and loading a game."; %feature("docstring") b2WheelJointDef::Initialize "Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis."; %feature("docstring") b2WheelJointDef::Initialize "Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis."; // File: classb2_loop_shape.xml %feature("docstring") b2ChainShape "A loop shape is a free form sequence of line segments that form a circular list. The loop may cross upon itself, but this is not recommended for smooth collision. The loop has double sided collision, so you can use inside and outside collision. Therefore, you may use any winding order. Since there may be many vertices, they are allocated using b2Alloc."; %feature("docstring") b2ChainShape::~b2ChainShape "The destructor frees the vertices using b2Free."; %feature("docstring") b2ChainShape::Create "Create the loop shape, copy all vertices."; %feature("docstring") b2ChainShape::Clone "Implement b2Shape. Vertices are cloned using b2Alloc."; %feature("docstring") b2ChainShape::GetChildCount " See: b2Shape::GetChildCount"; %feature("docstring") b2ChainShape::GetChildEdge "Get a child edge."; %feature("docstring") b2ChainShape::TestPoint "This always return false. See: b2Shape::TestPoint"; %feature("docstring") b2ChainShape::RayCast "Implement b2Shape."; %feature("docstring") b2ChainShape::ComputeAABB " See: b2Shape::ComputeAABB"; %feature("docstring") b2ChainShape::ComputeMass "Chains have zero mass. See: b2Shape::ComputeMass"; %feature("docstring") b2ChainShape::GetCount "Get the number of vertices."; %feature("docstring") b2ChainShape::GetVertex "Get the vertices (read-only)."; %feature("docstring") b2ChainShape::GetVertices "Get the vertices (read-only)."; %feature("docstring") b2ChainShape::~b2ChainShape "The destructor frees the vertices using b2Free."; %feature("docstring") b2ChainShape::Create "Create the loop shape, copy all vertices."; %feature("docstring") b2ChainShape::Clone "Implement b2Shape. Vertices are cloned using b2Alloc."; %feature("docstring") b2ChainShape::GetChildCount " See: b2Shape::GetChildCount"; %feature("docstring") b2ChainShape::GetChildEdge "Get a child edge."; %feature("docstring") b2ChainShape::TestPoint "This always return false. See: b2Shape::TestPoint"; %feature("docstring") b2ChainShape::RayCast "Implement b2Shape."; %feature("docstring") b2ChainShape::ComputeAABB " See: b2Shape::ComputeAABB"; %feature("docstring") b2ChainShape::ComputeMass "Chains have zero mass. See: b2Shape::ComputeMass"; %feature("docstring") b2ChainShape::GetCount "Get the number of vertices."; %feature("docstring") b2ChainShape::GetVertex "Get the vertices (read-only)."; %feature("docstring") b2ChainShape::GetVertices "Get the vertices (read-only)."; // File: structb2_manifold.xml %feature("docstring") b2Manifold "A manifold for two touching convex shapes. Box2D supports multiple types of contact: clip point versus plane with radius point versus point with radius (circles) The local point usage depends on the manifold type: -e_circles: the local center of circleA -e_faceA: the center of faceA -e_faceB: the center of faceB Similarly the local normal usage: -e_circles: not used -e_faceA: the normal on polygonA -e_faceB: the normal on polygonB We store contacts in this way so that position correction can account for movement, which is critical for continuous physics. All contact scenarios must be expressed in one of these types. This structure is stored across time steps, so we keep it small."; // File: structb2_manifold_point.xml %feature("docstring") b2ManifoldPoint "A manifold point is a contact point belonging to a contact manifold. It holds details related to the geometry and dynamics of the contact points. The local point usage depends on the manifold type: -e_circles: the local center of circleB -e_faceA: the local center of cirlceB or the clip point of polygonB -e_faceB: the clip point of polygonA This structure is stored across time steps, so we keep it small. Note: the impulses are used for internal caching and may not provide reliable contact forces, especially for high speed collisions."; // File: structb2_mass_data.xml %feature("docstring") b2MassData "This holds the mass data computed for a shape."; // File: structb2_mat22.xml %feature("docstring") b2Mat22 "A 2-by-2 matrix. Stored in column-major order."; %feature("docstring") b2Mat22::b2Mat22 "The default constructor does nothing (for performance)."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using columns."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using scalars."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using an angle. This matrix becomes an orthonormal rotation matrix."; %feature("docstring") b2Mat22::Set "Initialize this matrix using columns."; %feature("docstring") b2Mat22::Set "Initialize this matrix using an angle. This matrix becomes an orthonormal rotation matrix."; %feature("docstring") b2Mat22::SetIdentity "Set this to the identity matrix."; %feature("docstring") b2Mat22::SetZero "Set this matrix to all zeros."; %feature("docstring") b2Mat22::GetAngle "Extract the angle from this matrix (assumed to be a rotation matrix)."; %feature("docstring") b2Mat22::Solve "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases."; %feature("docstring") b2Mat22::b2Mat22 "The default constructor does nothing (for performance)."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using columns."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using scalars."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using an angle. This matrix becomes an orthonormal rotation matrix."; %feature("docstring") b2Mat22::Set "Initialize this matrix using columns."; %feature("docstring") b2Mat22::Set "Initialize this matrix using an angle. This matrix becomes an orthonormal rotation matrix."; %feature("docstring") b2Mat22::SetIdentity "Set this to the identity matrix."; %feature("docstring") b2Mat22::SetZero "Set this matrix to all zeros."; %feature("docstring") b2Mat22::GetAngle "Extract the angle from this matrix (assumed to be a rotation matrix)."; %feature("docstring") b2Mat22::Solve "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases."; // File: structb2_mat33.xml %feature("docstring") b2Mat33 "A 3-by-3 matrix. Stored in column-major order."; %feature("docstring") b2Mat33::b2Mat33 "The default constructor does nothing (for performance)."; %feature("docstring") b2Mat33::b2Mat33 "Construct this matrix using columns."; %feature("docstring") b2Mat33::SetZero "Set this matrix to all zeros."; %feature("docstring") b2Mat33::Solve33 "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases."; %feature("docstring") b2Mat33::Solve22 "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases. Solve only the upper 2-by-2 matrix equation. Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases."; %feature("docstring") b2Mat33::b2Mat33 "The default constructor does nothing (for performance)."; %feature("docstring") b2Mat33::b2Mat33 "Construct this matrix using columns."; %feature("docstring") b2Mat33::SetZero "Set this matrix to all zeros."; %feature("docstring") b2Mat33::Solve33 "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases."; %feature("docstring") b2Mat33::Solve22 "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases. Solve only the upper 2-by-2 matrix equation."; // File: classb2_mouse_joint.xml %feature("docstring") b2MouseJoint "A mouse joint is used to make a point on a body track a specified world point. This a soft constraint with a maximum force. This allows the constraint to stretch and without applying huge forces. NOTE: this joint is not documented in the manual because it was developed to be used in the testbed. If you want to learn how to use the mouse joint, look at the testbed."; %feature("docstring") b2MouseJoint::GetAnchorA "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetAnchorB "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetReactionForce "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetReactionTorque "Implements b2Joint."; %feature("docstring") b2MouseJoint::SetTarget "Use this to update the target point."; %feature("docstring") b2MouseJoint::SetMaxForce "Set/get the maximum force in Newtons."; %feature("docstring") b2MouseJoint::SetFrequency "Set/get the frequency in Hertz."; %feature("docstring") b2MouseJoint::SetDampingRatio "Set/get the damping ratio (dimensionless)."; %feature("docstring") b2MouseJoint::GetAnchorA "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetAnchorB "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetReactionForce "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetReactionTorque "Implements b2Joint."; %feature("docstring") b2MouseJoint::SetTarget "Use this to update the target point."; %feature("docstring") b2MouseJoint::SetMaxForce "Set/get the maximum force in Newtons."; %feature("docstring") b2MouseJoint::SetFrequency "Set/get the frequency in Hertz."; %feature("docstring") b2MouseJoint::SetDampingRatio "Set/get the damping ratio (dimensionless)."; // File: structb2_mouse_joint_def.xml %feature("docstring") b2MouseJointDef "Mouse joint definition. This requires a world target point, tuning parameters, and the time step."; // File: classb2_polygon_shape.xml %feature("docstring") b2PolygonShape "A convex polygon. It is assumed that the interior of the polygon is to the left of each edge. Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. In most cases you should not need many vertices for a convex polygon."; %feature("docstring") b2PolygonShape::Clone "Implement b2Shape."; %feature("docstring") b2PolygonShape::GetChildCount " See: b2Shape::GetChildCount"; %feature("docstring") b2PolygonShape::Set "Copy vertices. This assumes the vertices define a convex polygon. It is assumed that the exterior is the the right of each edge. The count must be in the range [3, b2_maxPolygonVertices]."; %feature("docstring") b2PolygonShape::SetAsBox "Build vertices to represent an axis-aligned box. Parameters: ----------- hx: the half-width. hy: the half-height."; %feature("docstring") b2PolygonShape::SetAsBox "Build vertices to represent an oriented box. Parameters: ----------- hx: the half-width. hy: the half-height. center: the center of the box in local coordinates. angle: the rotation of the box in local coordinates."; %feature("docstring") b2PolygonShape::TestPoint " See: b2Shape::TestPoint"; %feature("docstring") b2PolygonShape::RayCast "Implement b2Shape."; %feature("docstring") b2PolygonShape::ComputeAABB " See: b2Shape::ComputeAABB"; %feature("docstring") b2PolygonShape::ComputeMass " See: b2Shape::ComputeMass"; %feature("docstring") b2PolygonShape::GetVertexCount "Get the vertex count."; %feature("docstring") b2PolygonShape::GetVertex "Get a vertex by index."; %feature("docstring") b2PolygonShape::Clone "Implement b2Shape."; %feature("docstring") b2PolygonShape::GetChildCount " See: b2Shape::GetChildCount"; %feature("docstring") b2PolygonShape::Set "Copy vertices. This assumes the vertices define a convex polygon. It is assumed that the exterior is the the right of each edge. The count must be in the range [3, b2_maxPolygonVertices]."; %feature("docstring") b2PolygonShape::SetAsBox "Build vertices to represent an axis-aligned box. Parameters: ----------- hx: the half-width. hy: the half-height."; %feature("docstring") b2PolygonShape::SetAsBox "Build vertices to represent an oriented box. Parameters: ----------- hx: the half-width. hy: the half-height. center: the center of the box in local coordinates. angle: the rotation of the box in local coordinates."; %feature("docstring") b2PolygonShape::TestPoint " See: b2Shape::TestPoint"; %feature("docstring") b2PolygonShape::RayCast "Implement b2Shape."; %feature("docstring") b2PolygonShape::ComputeAABB " See: b2Shape::ComputeAABB"; %feature("docstring") b2PolygonShape::ComputeMass " See: b2Shape::ComputeMass"; %feature("docstring") b2PolygonShape::GetVertexCount "Get the vertex count."; %feature("docstring") b2PolygonShape::GetVertex "Get a vertex by index."; // File: structb2_position.xml %feature("docstring") b2Position "This is an internal structure."; // File: classb2_prismatic_joint.xml %feature("docstring") b2PrismaticJoint "A prismatic joint. This joint provides one degree of freedom: translation along an axis fixed in body1. Relative rotation is prevented. You can use a joint limit to restrict the range of motion and a joint motor to drive the motion or to model joint friction."; %feature("docstring") b2PrismaticJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2PrismaticJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2PrismaticJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2PrismaticJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2PrismaticJoint::GetJointTranslation "Get the current joint translation, usually in meters."; %feature("docstring") b2PrismaticJoint::GetJointSpeed "Get the current joint translation speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::IsLimitEnabled "Is the joint limit enabled?"; %feature("docstring") b2PrismaticJoint::EnableLimit "Enable/disable the joint limit."; %feature("docstring") b2PrismaticJoint::GetLowerLimit "Get the lower joint limit, usually in meters."; %feature("docstring") b2PrismaticJoint::GetUpperLimit "Get the upper joint limit, usually in meters."; %feature("docstring") b2PrismaticJoint::SetLimits "Set the joint limits, usually in meters."; %feature("docstring") b2PrismaticJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2PrismaticJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2PrismaticJoint::SetMotorSpeed "Set the motor speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::GetMotorSpeed "Get the motor speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::SetMaxMotorForce "Set the maximum motor force, usually in N."; %feature("docstring") b2PrismaticJoint::GetMotorForce "Get the current motor force given the inverse time step, usually in N."; %feature("docstring") b2PrismaticJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2PrismaticJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2PrismaticJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2PrismaticJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2PrismaticJoint::GetJointTranslation "Get the current joint translation, usually in meters."; %feature("docstring") b2PrismaticJoint::GetJointSpeed "Get the current joint translation speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::IsLimitEnabled "Is the joint limit enabled?"; %feature("docstring") b2PrismaticJoint::EnableLimit "Enable/disable the joint limit."; %feature("docstring") b2PrismaticJoint::GetLowerLimit "Get the lower joint limit, usually in meters."; %feature("docstring") b2PrismaticJoint::GetUpperLimit "Get the upper joint limit, usually in meters."; %feature("docstring") b2PrismaticJoint::SetLimits "Set the joint limits, usually in meters."; %feature("docstring") b2PrismaticJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2PrismaticJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2PrismaticJoint::SetMotorSpeed "Set the motor speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::GetMotorSpeed "Get the motor speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::SetMaxMotorForce "Set the maximum motor force, usually in N."; %feature("docstring") b2PrismaticJoint::GetMotorForce "Get the current motor force given the inverse time step, usually in N."; // File: structb2_prismatic_joint_def.xml %feature("docstring") b2PrismaticJointDef "Prismatic joint definition. This requires defining a line of motion using an axis and an anchor point. The definition uses local anchor points and a local axis so that the initial configuration can violate the constraint slightly. The joint translation is zero when the local anchor points coincide in world space. Using local anchors and a local axis helps when saving and loading a game. WARNING: at least one body should by dynamic with a non-fixed rotation."; %feature("docstring") b2PrismaticJointDef::Initialize "Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis."; %feature("docstring") b2PrismaticJointDef::Initialize "Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis."; // File: classb2_pulley_joint.xml %feature("docstring") b2PulleyJoint "The pulley joint is connected to two bodies and two fixed ground points. The pulley supports a ratio such that: length1 + ratio * length2 <= constant Yes, the force transmitted is scaled by the ratio. The pulley also enforces a maximum length limit on both sides. This is useful to prevent one side of the pulley hitting the top."; %feature("docstring") b2PulleyJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2PulleyJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2PulleyJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2PulleyJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2PulleyJoint::GetGroundAnchorA "Get the first ground anchor."; %feature("docstring") b2PulleyJoint::GetGroundAnchorB "Get the second ground anchor."; %feature("docstring") b2PulleyJoint::GetLength1 "Get the current length of the segment attached to body1."; %feature("docstring") b2PulleyJoint::GetLength2 "Get the current length of the segment attached to body2."; %feature("docstring") b2PulleyJoint::GetRatio "Get the pulley ratio."; %feature("docstring") b2PulleyJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2PulleyJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2PulleyJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2PulleyJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2PulleyJoint::GetGroundAnchorA "Get the first ground anchor."; %feature("docstring") b2PulleyJoint::GetGroundAnchorB "Get the second ground anchor."; %feature("docstring") b2PulleyJoint::GetLength1 "Get the current length of the segment attached to body1."; %feature("docstring") b2PulleyJoint::GetLength2 "Get the current length of the segment attached to body2."; %feature("docstring") b2PulleyJoint::GetRatio "Get the pulley ratio."; // File: structb2_pulley_joint_def.xml %feature("docstring") b2PulleyJointDef "Pulley joint definition. This requires two ground anchors, two dynamic body anchor points, max lengths for each side, and a pulley ratio."; %feature("docstring") b2PulleyJointDef::Initialize "Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors."; %feature("docstring") b2PulleyJointDef::Initialize "Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors."; // File: classb2_query_callback.xml %feature("docstring") b2QueryCallback "Callback class for AABB queries. See b2World::Query"; %feature("docstring") b2QueryCallback::ReportFixture "Called for each fixture found in the query AABB. false to terminate the query."; %feature("docstring") b2QueryCallback::ReportFixture "Called for each fixture found in the query AABB. false to terminate the query."; // File: classb2_ray_cast_callback.xml %feature("docstring") b2RayCastCallback "Callback class for ray casts. See b2World::RayCast"; %feature("docstring") b2RayCastCallback::ReportFixture "Called for each fixture found in the query. You control how the ray cast proceeds by returning a float: return -1: ignore this fixture and continue return 0: terminate the ray cast return fraction: clip the ray to this point return 1: don't clip the ray and continue Parameters: ----------- fixture: the fixture hit by the ray point: the point of initial intersection normal: the normal vector at the point of intersection -1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue"; %feature("docstring") b2RayCastCallback::ReportFixture "Called for each fixture found in the query. You control how the ray cast proceeds by returning a float: return -1: ignore this fixture and continue return 0: terminate the ray cast return fraction: clip the ray to this point return 1: don't clip the ray and continue Parameters: ----------- fixture: the fixture hit by the ray point: the point of initial intersection normal: the normal vector at the point of intersection -1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue"; // File: structb2_ray_cast_input.xml %feature("docstring") b2RayCastInput "Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1)."; // File: structb2_ray_cast_output.xml %feature("docstring") b2RayCastOutput "Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 come from b2RayCastInput."; // File: classb2_revolute_joint.xml %feature("docstring") b2RevoluteJoint "A revolute joint constrains two bodies to share a common point while they are free to rotate about the point. The relative rotation about the shared point is the joint angle. You can limit the relative rotation with a joint limit that specifies a lower and upper angle. You can use a motor to drive the relative rotation about the shared point. A maximum motor torque is provided so that infinite forces are not generated."; %feature("docstring") b2RevoluteJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2RevoluteJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2RevoluteJoint::GetJointAngle "Get the current joint angle in radians."; %feature("docstring") b2RevoluteJoint::GetJointSpeed "Get the current joint angle speed in radians per second."; %feature("docstring") b2RevoluteJoint::IsLimitEnabled "Is the joint limit enabled?"; %feature("docstring") b2RevoluteJoint::EnableLimit "Enable/disable the joint limit."; %feature("docstring") b2RevoluteJoint::GetLowerLimit "Get the lower joint limit in radians."; %feature("docstring") b2RevoluteJoint::GetUpperLimit "Get the upper joint limit in radians."; %feature("docstring") b2RevoluteJoint::SetLimits "Set the joint limits in radians."; %feature("docstring") b2RevoluteJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2RevoluteJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2RevoluteJoint::SetMotorSpeed "Set the motor speed in radians per second."; %feature("docstring") b2RevoluteJoint::GetMotorSpeed "Get the motor speed in radians per second."; %feature("docstring") b2RevoluteJoint::SetMaxMotorTorque "Set the maximum motor torque, usually in N-m."; %feature("docstring") b2RevoluteJoint::GetReactionForce "Get the reaction force given the inverse time step. Unit is N."; %feature("docstring") b2RevoluteJoint::GetReactionTorque "Get the reaction torque due to the joint limit given the inverse time step. Unit is N*m."; %feature("docstring") b2RevoluteJoint::GetMotorTorque "Get the current motor torque given the inverse time step. Unit is N*m."; %feature("docstring") b2RevoluteJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2RevoluteJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2RevoluteJoint::GetJointAngle "Get the current joint angle in radians."; %feature("docstring") b2RevoluteJoint::GetJointSpeed "Get the current joint angle speed in radians per second."; %feature("docstring") b2RevoluteJoint::IsLimitEnabled "Is the joint limit enabled?"; %feature("docstring") b2RevoluteJoint::EnableLimit "Enable/disable the joint limit."; %feature("docstring") b2RevoluteJoint::GetLowerLimit "Get the lower joint limit in radians."; %feature("docstring") b2RevoluteJoint::GetUpperLimit "Get the upper joint limit in radians."; %feature("docstring") b2RevoluteJoint::SetLimits "Set the joint limits in radians."; %feature("docstring") b2RevoluteJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2RevoluteJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2RevoluteJoint::SetMotorSpeed "Set the motor speed in radians per second."; %feature("docstring") b2RevoluteJoint::GetMotorSpeed "Get the motor speed in radians per second."; %feature("docstring") b2RevoluteJoint::SetMaxMotorTorque "Set the maximum motor torque, usually in N-m."; %feature("docstring") b2RevoluteJoint::GetReactionForce "Get the reaction force given the inverse time step. Unit is N."; %feature("docstring") b2RevoluteJoint::GetReactionTorque "Get the reaction torque due to the joint limit given the inverse time step. Unit is N*m."; %feature("docstring") b2RevoluteJoint::GetMotorTorque "Get the current motor torque given the inverse time step. Unit is N*m."; // File: structb2_revolute_joint_def.xml %feature("docstring") b2RevoluteJointDef "Revolute joint definition. This requires defining an anchor point where the bodies are joined. The definition uses local anchor points so that the initial configuration can violate the constraint slightly. You also need to specify the initial relative angle for joint limits. This helps when saving and loading a game. The local anchor points are measured from the body's origin rather than the center of mass because: 1. you might not know where the center of mass will be. 2. if you add/remove shapes from a body and recompute the mass, the joints will be broken."; %feature("docstring") b2RevoluteJointDef::Initialize "Initialize the bodies, anchors, and reference angle using a world anchor point."; %feature("docstring") b2RevoluteJointDef::Initialize "Initialize the bodies, anchors, and reference angle using a world anchor point."; // File: classb2_rope_joint.xml %feature("docstring") b2RopeJoint "A rope joint enforces a maximum distance between two points on two bodies. It has no other effect. Warning: if you attempt to change the maximum length during the simulation you will get some non-physical behavior. A model that would allow you to dynamically modify the length would have some sponginess, so I chose not to implement it that way. See b2DistanceJointif you want to dynamically control length."; %feature("docstring") b2RopeJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2RopeJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2RopeJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2RopeJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2RopeJoint::GetMaxLength "Get the maximum length of the rope."; %feature("docstring") b2RopeJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2RopeJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2RopeJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2RopeJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2RopeJoint::GetMaxLength "Get the maximum length of the rope."; // File: structb2_rope_joint_def.xml %feature("docstring") b2RopeJointDef "Rope joint definition. This requires two body anchor points and a maximum lengths. Note: by default the connected objects will not collide. see collideConnected in b2JointDef."; // File: classb2_shape.xml %feature("docstring") b2Shape "A shape is used for collision detection. You can create a shape however you like. Shapes used for simulation in b2Worldare created automatically when a b2Fixtureis created. Shapes may encapsulate a one or more child shapes."; %feature("docstring") b2Shape::Clone "Clone the concrete shape using the provided allocator."; %feature("docstring") b2Shape::GetType "Get the type of this shape. You can use this to down cast to the concrete shape. the shape type."; %feature("docstring") b2Shape::GetChildCount "Get the number of child primitives."; %feature("docstring") b2Shape::TestPoint "Test a point for containment in this shape. This only works for convex shapes. Parameters: ----------- xf: the shape world transform. p: a point in world coordinates."; %feature("docstring") b2Shape::RayCast "Cast a ray against a child shape. Parameters: ----------- output: the ray-cast results. input: the ray-cast input parameters. transform: the transform to be applied to the shape. childIndex: the child shape index"; %feature("docstring") b2Shape::ComputeAABB "Given a transform, compute the associated axis aligned bounding box for a child shape. Parameters: ----------- aabb: returns the axis aligned box. xf: the world transform of the shape. childIndex: the child shape"; %feature("docstring") b2Shape::ComputeMass "Compute the mass properties of this shape using its dimensions and density. The inertia tensor is computed about the local origin. Parameters: ----------- massData: returns the mass data for this shape. density: the density in kilograms per meter squared."; %feature("docstring") b2Shape::Clone "Clone the concrete shape using the provided allocator."; %feature("docstring") b2Shape::GetType "Get the type of this shape. You can use this to down cast to the concrete shape. the shape type."; %feature("docstring") b2Shape::GetChildCount "Get the number of child primitives."; %feature("docstring") b2Shape::TestPoint "Test a point for containment in this shape. This only works for convex shapes. Parameters: ----------- xf: the shape world transform. p: a point in world coordinates."; %feature("docstring") b2Shape::RayCast "Cast a ray against a child shape. Parameters: ----------- output: the ray-cast results. input: the ray-cast input parameters. transform: the transform to be applied to the shape. childIndex: the child shape index"; %feature("docstring") b2Shape::ComputeAABB "Given a transform, compute the associated axis aligned bounding box for a child shape. Parameters: ----------- aabb: returns the axis aligned box. xf: the world transform of the shape. childIndex: the child shape"; %feature("docstring") b2Shape::ComputeMass "Compute the mass properties of this shape using its dimensions and density. The inertia tensor is computed about the local origin. Parameters: ----------- massData: returns the mass data for this shape. density: the density in kilograms per meter squared."; // File: structb2_simplex_cache.xml %feature("docstring") b2SimplexCache "Used to warm start b2Distance. Set count to zero on first call."; // File: structb2_sweep.xml %feature("docstring") b2Sweep "This describes the motion of a body/shape for TOI computation. Shapes are defined with respect to the body origin, which may no coincide with the center of mass. However, to support dynamics we must interpolate the center of mass position."; %feature("docstring") b2Sweep::GetTransform "Get the interpolated transform at a specific time. Parameters: ----------- beta: is a factor in [0,1], where 0 indicates alpha0."; %feature("docstring") b2Sweep::Advance "Advance the sweep forward, yielding a new initial state. Parameters: ----------- alpha: the new initial time."; %feature("docstring") b2Sweep::Normalize "Normalize the angles. Normalize an angle in radians to be between -pi and pi."; %feature("docstring") b2Sweep::GetTransform "Get the interpolated transform at a specific time. Parameters: ----------- beta: is a factor in [0,1], where 0 indicates alpha0."; %feature("docstring") b2Sweep::Advance "Advance the sweep forward, yielding a new initial state. Parameters: ----------- alpha: the new initial time."; %feature("docstring") b2Sweep::Normalize "Normalize the angles."; // File: structb2_time_step.xml %feature("docstring") b2TimeStep "This is an internal structure."; // File: structb2_t_o_i_input.xml %feature("docstring") b2TOIInput "Input parameters for b2TimeOfImpact."; // File: structb2_transform.xml %feature("docstring") b2Transform "A transform contains translation and rotation. It is used to represent the position and orientation of rigid frames."; %feature("docstring") b2Transform::b2Transform "The default constructor does nothing (for performance)."; %feature("docstring") b2Transform::b2Transform "Initialize using a position vector and a rotation matrix."; %feature("docstring") b2Transform::SetIdentity "Set this to the identity transform."; %feature("docstring") b2Transform::Set "Set this based on the position and angle."; %feature("docstring") b2Transform::GetAngle "Calculate the angle that the rotation matrix represents."; %feature("docstring") b2Transform::b2Transform "The default constructor does nothing (for performance)."; %feature("docstring") b2Transform::b2Transform "Initialize using a position vector and a rotation matrix."; %feature("docstring") b2Transform::SetIdentity "Set this to the identity transform."; %feature("docstring") b2Transform::Set "Set this based on the position and angle."; %feature("docstring") b2Transform::GetAngle "Calculate the angle that the rotation matrix represents."; // File: structb2_vec2.xml %feature("docstring") b2Vec2 "A 2D column vector."; %feature("docstring") b2Vec2::b2Vec2 "Default constructor does nothing (for performance)."; %feature("docstring") b2Vec2::b2Vec2 "Construct using coordinates."; %feature("docstring") b2Vec2::SetZero "Set this vector to all zeros."; %feature("docstring") b2Vec2::Set "Set this vector to some specified coordinates."; %feature("docstring") b2Vec2::Length "Get the length of this vector (the norm)."; %feature("docstring") b2Vec2::LengthSquared "Get the length squared. For performance, use this instead of b2Vec2::Length(if possible)."; %feature("docstring") b2Vec2::Normalize "Convert this vector into a unit vector. Returns the length."; %feature("docstring") b2Vec2::IsValid "Does this vector contain finite coordinates?"; %feature("docstring") b2Vec2::Skew "Get the skew vector such that dot(skew_vec, other) == cross(vec, other)"; %feature("docstring") b2Vec2::b2Vec2 "Default constructor does nothing (for performance)."; %feature("docstring") b2Vec2::b2Vec2 "Construct using coordinates."; %feature("docstring") b2Vec2::SetZero "Set this vector to all zeros."; %feature("docstring") b2Vec2::Set "Set this vector to some specified coordinates."; %feature("docstring") b2Vec2::Length "Get the length of this vector (the norm)."; %feature("docstring") b2Vec2::LengthSquared "Get the length squared. For performance, use this instead of b2Vec2::Length(if possible)."; %feature("docstring") b2Vec2::Normalize "Convert this vector into a unit vector. Returns the length."; %feature("docstring") b2Vec2::IsValid "Does this vector contain finite coordinates?"; %feature("docstring") b2Vec2::Skew "Get the skew vector such that dot(skew_vec, other) == cross(vec, other)"; // File: structb2_vec3.xml %feature("docstring") b2Vec3 "A 2D column vector with 3 elements."; %feature("docstring") b2Vec3::b2Vec3 "Default constructor does nothing (for performance)."; %feature("docstring") b2Vec3::b2Vec3 "Construct using coordinates."; %feature("docstring") b2Vec3::SetZero "Set this vector to all zeros."; %feature("docstring") b2Vec3::Set "Set this vector to some specified coordinates."; %feature("docstring") b2Vec3::b2Vec3 "Default constructor does nothing (for performance)."; %feature("docstring") b2Vec3::b2Vec3 "Construct using coordinates."; %feature("docstring") b2Vec3::SetZero "Set this vector to all zeros."; %feature("docstring") b2Vec3::Set "Set this vector to some specified coordinates."; // File: structb2_velocity.xml %feature("docstring") b2Velocity "This is an internal structure."; // File: structb2_version.xml %feature("docstring") b2Version "Version numbering scheme. See http://en.wikipedia.org/wiki/Software_versioning"; // File: classb2_weld_joint.xml %feature("docstring") b2WeldJoint "A weld joint essentially glues two bodies together. A weld joint may distort somewhat because the island constraint solver is approximate."; %feature("docstring") b2WeldJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2WeldJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2WeldJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2WeldJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; %feature("docstring") b2WeldJoint::GetAnchorA "Get the anchor point on bodyA in world coordinates."; %feature("docstring") b2WeldJoint::GetAnchorB "Get the anchor point on bodyB in world coordinates."; %feature("docstring") b2WeldJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor in Newtons."; %feature("docstring") b2WeldJoint::GetReactionTorque "Get the reaction torque on body2 in N*m."; // File: structb2_weld_joint_def.xml %feature("docstring") b2WeldJointDef "Weld joint definition. You need to specify local anchor points where they are attached and the relative body angle. The position of the anchor points is important for computing the reaction torque."; %feature("docstring") b2WeldJointDef::Initialize "Initialize the bodies, anchors, and reference angle using a world anchor point."; %feature("docstring") b2WeldJointDef::Initialize "Initialize the bodies, anchors, and reference angle using a world anchor point."; // File: classb2_world.xml %feature("docstring") b2World "The world class manages all physics entities, dynamic simulation, and asynchronous queries. The world also contains efficient memory management facilities."; %feature("docstring") b2World::b2World "Construct a world object. Parameters: ----------- gravity: the world gravity vector. doSleep: improve performance by not simulating inactive bodies."; %feature("docstring") b2World::~b2World "Destruct the world. All physics entities are destroyed and all heap memory is released."; %feature("docstring") b2World::SetDestructionListener "Register a destruction listener. The listener is owned by you and must remain in scope."; %feature("docstring") b2World::SetContactFilter "Register a contact filter to provide specific control over collision. Otherwise the default filter is used (b2_defaultFilter). The listener is owned by you and must remain in scope."; %feature("docstring") b2World::SetContactListener "Register a contact event listener. The listener is owned by you and must remain in scope."; %feature("docstring") b2World::SetDebugDraw "Register a routine for debug drawing. The debug draw functions are called inside with b2World::DrawDebugDatamethod. The debug draw object is owned by you and must remain in scope."; %feature("docstring") b2World::CreateBody "Create a rigid body given a definition. No reference to the definition is retained. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::DestroyBody "Destroy a rigid body given a definition. No reference to the definition is retained. This function is locked during callbacks. WARNING: This automatically deletes all associated shapes and joints. This function is locked during callbacks."; %feature("docstring") b2World::CreateJoint "Create a joint to constrain bodies together. No reference to the definition is retained. This may cause the connected bodies to cease colliding. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::DestroyJoint "Destroy a joint. This may cause the connected bodies to begin colliding. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::Step "Take a time step. This performs collision detection, integration, and constraint solution. Parameters: ----------- timeStep: the amount of time to simulate, this should not vary. velocityIterations: for the velocity constraint solver. positionIterations: for the position constraint solver."; %feature("docstring") b2World::ClearForces "Manually clear the force buffer on all bodies. By default, forces are cleared automatically after each call to Step. The default behavior is modified by calling SetAutoClearForces. The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain a fixed sized time step under a variable frame-rate. When you perform sub-stepping you will disable auto clearing of forces and instead call ClearForces after all sub-steps are complete in one pass of your game loop. See: SetAutoClearForces"; %feature("docstring") b2World::DrawDebugData "Call this to draw shapes and other debug draw data."; %feature("docstring") b2World::QueryAABB "Query the world for all fixtures that potentially overlap the provided AABB. Parameters: ----------- callback: a user implemented callback class. aabb: the query box."; %feature("docstring") b2World::RayCast "Ray-cast the world for all fixtures in the path of the ray. Your callback controls whether you get the closest point, any point, or n-points. The ray-cast ignores shapes that contain the starting point. Parameters: ----------- callback: a user implemented callback class. point1: the ray starting point point2: the ray ending point"; %feature("docstring") b2World::GetBodyList "Get the world body list. With the returned body, use b2Body::GetNextto get the next body in the world list. A NULL body indicates the end of the list. the head of the world body list."; %feature("docstring") b2World::GetJointList "Get the world joint list. With the returned joint, use b2Joint::GetNextto get the next joint in the world list. A NULL joint indicates the end of the list. the head of the world joint list."; %feature("docstring") b2World::GetContactList "Get the world contact list. With the returned contact, use b2Contact::GetNextto get the next contact in the world list. A NULL contact indicates the end of the list. the head of the world contact list. WARNING: contacts are"; %feature("docstring") b2World::SetWarmStarting "Enable/disable warm starting. For testing."; %feature("docstring") b2World::SetContinuousPhysics "Enable/disable continuous physics. For testing."; %feature("docstring") b2World::SetSubStepping "Enable/disable single stepped continuous physics. For testing."; %feature("docstring") b2World::GetProxyCount "Get the number of broad-phase proxies."; %feature("docstring") b2World::GetBodyCount "Get the number of bodies."; %feature("docstring") b2World::GetJointCount "Get the number of joints."; %feature("docstring") b2World::GetContactCount "Get the number of contacts (each may have 0 or more contact points)."; %feature("docstring") b2World::SetGravity "Change the global gravity vector."; %feature("docstring") b2World::GetGravity "Get the global gravity vector."; %feature("docstring") b2World::IsLocked "Is the world locked (in the middle of a time step)."; %feature("docstring") b2World::SetAutoClearForces "Set flag to control automatic clearing of forces after each time step."; %feature("docstring") b2World::GetAutoClearForces "Get the flag that controls automatic clearing of forces after each time step."; %feature("docstring") b2World::GetContactManager "Get the contact manager for testing."; %feature("docstring") b2World::b2World "Construct a world object. Parameters: ----------- gravity: the world gravity vector. doSleep: improve performance by not simulating inactive bodies."; %feature("docstring") b2World::~b2World "Destruct the world. All physics entities are destroyed and all heap memory is released."; %feature("docstring") b2World::SetDestructionListener "Register a destruction listener. The listener is owned by you and must remain in scope."; %feature("docstring") b2World::SetContactFilter "Register a contact filter to provide specific control over collision. Otherwise the default filter is used (b2_defaultFilter). The listener is owned by you and must remain in scope."; %feature("docstring") b2World::SetContactListener "Register a contact event listener. The listener is owned by you and must remain in scope."; %feature("docstring") b2World::SetDebugDraw "Register a routine for debug drawing. The debug draw functions are called inside with b2World::DrawDebugDatamethod. The debug draw object is owned by you and must remain in scope."; %feature("docstring") b2World::CreateBody "Create a rigid body given a definition. No reference to the definition is retained. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::DestroyBody "Destroy a rigid body given a definition. No reference to the definition is retained. This function is locked during callbacks. WARNING: This automatically deletes all associated shapes and joints. This function is locked during callbacks."; %feature("docstring") b2World::CreateJoint "Create a joint to constrain bodies together. No reference to the definition is retained. This may cause the connected bodies to cease colliding. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::DestroyJoint "Destroy a joint. This may cause the connected bodies to begin colliding. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::Step "Take a time step. This performs collision detection, integration, and constraint solution. Parameters: ----------- timeStep: the amount of time to simulate, this should not vary. velocityIterations: for the velocity constraint solver. positionIterations: for the position constraint solver."; %feature("docstring") b2World::ClearForces "Manually clear the force buffer on all bodies. By default, forces are cleared automatically after each call to Step. The default behavior is modified by calling SetAutoClearForces. The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain a fixed sized time step under a variable frame-rate. When you perform sub-stepping you will disable auto clearing of forces and instead call ClearForces after all sub-steps are complete in one pass of your game loop. See: SetAutoClearForces"; %feature("docstring") b2World::DrawDebugData "Call this to draw shapes and other debug draw data."; %feature("docstring") b2World::QueryAABB "Query the world for all fixtures that potentially overlap the provided AABB. Parameters: ----------- callback: a user implemented callback class. aabb: the query box."; %feature("docstring") b2World::RayCast "Ray-cast the world for all fixtures in the path of the ray. Your callback controls whether you get the closest point, any point, or n-points. The ray-cast ignores shapes that contain the starting point. Parameters: ----------- callback: a user implemented callback class. point1: the ray starting point point2: the ray ending point"; %feature("docstring") b2World::GetBodyList "Get the world body list. With the returned body, use b2Body::GetNextto get the next body in the world list. A NULL body indicates the end of the list. the head of the world body list."; %feature("docstring") b2World::GetJointList "Get the world joint list. With the returned joint, use b2Joint::GetNextto get the next joint in the world list. A NULL joint indicates the end of the list. the head of the world joint list."; %feature("docstring") b2World::GetContactList "Get the world contact list. With the returned contact, use b2Contact::GetNextto get the next contact in the world list. A NULL contact indicates the end of the list. the head of the world contact list. WARNING: contacts are"; %feature("docstring") b2World::SetWarmStarting "Enable/disable warm starting. For testing."; %feature("docstring") b2World::SetContinuousPhysics "Enable/disable continuous physics. For testing."; %feature("docstring") b2World::SetSubStepping "Enable/disable single stepped continuous physics. For testing."; %feature("docstring") b2World::GetProxyCount "Get the number of broad-phase proxies."; %feature("docstring") b2World::GetBodyCount "Get the number of bodies."; %feature("docstring") b2World::GetJointCount "Get the number of joints."; %feature("docstring") b2World::GetContactCount "Get the number of contacts (each may have 0 or more contact points)."; %feature("docstring") b2World::SetGravity "Change the global gravity vector."; %feature("docstring") b2World::GetGravity "Get the global gravity vector."; %feature("docstring") b2World::IsLocked "Is the world locked (in the middle of a time step)."; %feature("docstring") b2World::SetAutoClearForces "Set flag to control automatic clearing of forces after each time step."; %feature("docstring") b2World::GetAutoClearForces "Get the flag that controls automatic clearing of forces after each time step."; %feature("docstring") b2World::GetContactManager "Get the contact manager for testing."; // File: structb2_world_manifold.xml %feature("docstring") b2WorldManifold "This is used to compute the current state of a contact manifold."; %feature("docstring") b2WorldManifold::Initialize "Evaluate the manifold with supplied transforms. This assumes modest motion from the original state. This does not change the point count, impulses, etc. The radii must come from the shapes that generated the manifold."; %feature("docstring") b2WorldManifold::Initialize "Evaluate the manifold with supplied transforms. This assumes modest motion from the original state. This does not change the point count, impulses, etc. The radii must come from the shapes that generated the manifold."; // File: ___box2_d_2_collision_2b2_broad_phase_8h.xml %feature("docstring") b2PairLessThan "This is used to sort pairs."; // File: _collision_2b2_broad_phase_8h.xml %feature("docstring") b2PairLessThan "This is used to sort pairs."; // File: ___box2_d_2_collision_2b2_collide_circle_8cpp.xml %feature("docstring") b2CollideCircles "Compute the collision manifold between two circles."; %feature("docstring") b2CollidePolygonAndCircle "Compute the collision manifold between a polygon and a circle."; // File: _collision_2b2_collide_circle_8cpp.xml %feature("docstring") b2CollideCircles "Compute the collision manifold between two circles."; %feature("docstring") b2CollidePolygonAndCircle "Compute the collision manifold between a polygon and a circle."; // File: ___box2_d_2_collision_2b2_collide_edge_8cpp.xml %feature("docstring") b2CollideEdgeAndCircle "Compute the collision manifold between an edge and a circle."; %feature("docstring") b2CollideEdgeAndPolygon "Compute the collision manifold between an edge and a circle."; // File: _collision_2b2_collide_edge_8cpp.xml %feature("docstring") b2CollideEdgeAndCircle "Compute the collision manifold between an edge and a circle."; %feature("docstring") b2CollideEdgeAndPolygon "Compute the collision manifold between an edge and a circle."; // File: ___box2_d_2_collision_2b2_collide_polygon_8cpp.xml %feature("docstring") b2CollidePolygons "Compute the collision manifold between two polygons."; // File: _collision_2b2_collide_polygon_8cpp.xml %feature("docstring") b2CollidePolygons "Compute the collision manifold between two polygons."; // File: ___box2_d_2_collision_2b2_collision_8cpp.xml %feature("docstring") b2GetPointStates "Compute the point states given two manifolds. The states pertain to the transition from manifold1 to manifold2. So state1 is either persist or remove while state2 is either add or persist."; %feature("docstring") b2ClipSegmentToLine "Clipping for contact manifolds."; %feature("docstring") b2TestOverlap "Determine if two generic shapes overlap."; // File: _collision_2b2_collision_8cpp.xml %feature("docstring") b2GetPointStates "Compute the point states given two manifolds. The states pertain to the transition from manifold1 to manifold2. So state1 is either persist or remove while state2 is either add or persist."; %feature("docstring") b2ClipSegmentToLine "Clipping for contact manifolds."; %feature("docstring") b2TestOverlap "Determine if two generic shapes overlap."; // File: ___box2_d_2_collision_2b2_collision_8h.xml %feature("docstring") b2GetPointStates "Compute the point states given two manifolds. The states pertain to the transition from manifold1 to manifold2. So state1 is either persist or remove while state2 is either add or persist."; %feature("docstring") b2CollideCircles "Compute the collision manifold between two circles."; %feature("docstring") b2CollidePolygonAndCircle "Compute the collision manifold between a polygon and a circle."; %feature("docstring") b2CollidePolygons "Compute the collision manifold between two polygons."; %feature("docstring") b2CollideEdgeAndCircle "Compute the collision manifold between an edge and a circle."; %feature("docstring") b2CollideEdgeAndPolygon "Compute the collision manifold between an edge and a circle."; %feature("docstring") b2ClipSegmentToLine "Clipping for contact manifolds."; %feature("docstring") b2TestOverlap "Determine if two generic shapes overlap."; // File: _collision_2b2_collision_8h.xml %feature("docstring") b2GetPointStates "Compute the point states given two manifolds. The states pertain to the transition from manifold1 to manifold2. So state1 is either persist or remove while state2 is either add or persist."; %feature("docstring") b2CollideCircles "Compute the collision manifold between two circles."; %feature("docstring") b2CollidePolygonAndCircle "Compute the collision manifold between a polygon and a circle."; %feature("docstring") b2CollidePolygons "Compute the collision manifold between two polygons."; %feature("docstring") b2CollideEdgeAndCircle "Compute the collision manifold between an edge and a circle."; %feature("docstring") b2CollideEdgeAndPolygon "Compute the collision manifold between an edge and a circle."; %feature("docstring") b2ClipSegmentToLine "Clipping for contact manifolds."; %feature("docstring") b2TestOverlap "Determine if two generic shapes overlap."; // File: ___box2_d_2_collision_2b2_distance_8cpp.xml %feature("docstring") b2Distance "Compute the closest points between two shapes. Supports any combination of: b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. On the first call set b2SimplexCache.count to zero."; // File: _collision_2b2_distance_8cpp.xml %feature("docstring") b2Distance "Compute the closest points between two shapes. Supports any combination of: b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. On the first call set b2SimplexCache.count to zero."; // File: ___box2_d_2_collision_2b2_distance_8h.xml %feature("docstring") b2Distance "Compute the closest points between two shapes. Supports any combination of: b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. On the first call set b2SimplexCache.count to zero."; // File: _collision_2b2_distance_8h.xml %feature("docstring") b2Distance "Compute the closest points between two shapes. Supports any combination of: b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. On the first call set b2SimplexCache.count to zero."; // File: ___box2_d_2_collision_2b2_time_of_impact_8cpp.xml %feature("docstring") b2TimeOfImpact "Compute the upper bound on time before two shapes penetrate. Time is represented as a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, non-tunneling collision. If you change the time interval, you should call this function again. Note: use b2Distance to compute the contact point and normal at the time of impact."; // File: _collision_2b2_time_of_impact_8cpp.xml %feature("docstring") b2TimeOfImpact "Compute the upper bound on time before two shapes penetrate. Time is represented as a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, non-tunneling collision. If you change the time interval, you should call this function again. Note: use b2Distance to compute the contact point and normal at the time of impact."; // File: ___box2_d_2_collision_2b2_time_of_impact_8h.xml %feature("docstring") b2TimeOfImpact "Compute the upper bound on time before two shapes penetrate. Time is represented as a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, non-tunneling collision. If you change the time interval, you should call this function again. Note: use b2Distance to compute the contact point and normal at the time of impact."; // File: _collision_2b2_time_of_impact_8h.xml %feature("docstring") b2TimeOfImpact "Compute the upper bound on time before two shapes penetrate. Time is represented as a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, non-tunneling collision. If you change the time interval, you should call this function again. Note: use b2Distance to compute the contact point and normal at the time of impact."; // File: ___box2_d_2_common_2b2_math_8h.xml %feature("docstring") b2IsValid "This function is used to ensure that a floating point number is not a NaN or infinity."; %feature("docstring") b2InvSqrt "This is a approximate yet fast inverse square-root."; %feature("docstring") b2Dot "Perform the dot product on two vectors."; %feature("docstring") b2Cross "Perform the cross product on two vectors. In 2D this produces a scalar."; %feature("docstring") b2Cross "Perform the cross product on a vector and a scalar. In 2D this produces a vector."; %feature("docstring") b2Cross "Perform the cross product on a scalar and a vector. In 2D this produces a vector."; %feature("docstring") b2Mul "Multiply a matrix times a vector. If a rotation matrix is provided, then this transforms the vector from one frame to another."; %feature("docstring") b2MulT "Multiply a matrix transpose times a vector. If a rotation matrix is provided, then this transforms the vector from one frame to another (inverse transform)."; %feature("docstring") b2Dot "Perform the dot product on two vectors."; %feature("docstring") b2Cross "Perform the cross product on two vectors."; %feature("docstring") b2Mul "Multiply a matrix times a vector."; %feature("docstring") b2NextPowerOfTwo "\"Next Largest Power of 2 Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm that recursively \"folds\" the upper bits into the lower bits. This process yields a bit vector with the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next largest power of 2. For a 32-bit value:\""; // File: _common_2b2_math_8h.xml %feature("docstring") b2IsValid "This function is used to ensure that a floating point number is not a NaN or infinity."; %feature("docstring") b2InvSqrt "This is a approximate yet fast inverse square-root."; %feature("docstring") b2Dot "Perform the dot product on two vectors."; %feature("docstring") b2Cross "Perform the cross product on two vectors. In 2D this produces a scalar."; %feature("docstring") b2Cross "Perform the cross product on a vector and a scalar. In 2D this produces a vector."; %feature("docstring") b2Cross "Perform the cross product on a scalar and a vector. In 2D this produces a vector."; %feature("docstring") b2Mul "Multiply a matrix times a vector. If a rotation matrix is provided, then this transforms the vector from one frame to another."; %feature("docstring") b2MulT "Multiply a matrix transpose times a vector. If a rotation matrix is provided, then this transforms the vector from one frame to another (inverse transform)."; %feature("docstring") b2Dot "Perform the dot product on two vectors."; %feature("docstring") b2Cross "Perform the cross product on two vectors."; %feature("docstring") b2Mul "Multiply a matrix times a vector."; %feature("docstring") b2NextPowerOfTwo "\"Next Largest Power of 2 Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm that recursively \"folds\" the upper bits into the lower bits. This process yields a bit vector with the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next largest power of 2. For a 32-bit value:\""; // File: ___box2_d_2_common_2b2_settings_8cpp.xml %feature("docstring") b2Alloc "Implement this function to use your own memory allocator."; %feature("docstring") b2Free "If you implement b2Alloc, you should also implement this function."; // File: _common_2b2_settings_8cpp.xml %feature("docstring") b2Alloc "Implement this function to use your own memory allocator."; %feature("docstring") b2Free "If you implement b2Alloc, you should also implement this function."; // File: ___box2_d_2_common_2b2_settings_8h.xml %feature("docstring") b2Alloc "Implement this function to use your own memory allocator."; %feature("docstring") b2Free "If you implement b2Alloc, you should also implement this function."; %feature("docstring") b2MixFriction "Friction mixing law. Feel free to customize this."; %feature("docstring") b2MixRestitution "Restitution mixing law. Feel free to customize this."; // File: _common_2b2_settings_8h.xml %feature("docstring") b2Alloc "Implement this function to use your own memory allocator."; %feature("docstring") b2Free "If you implement b2Alloc, you should also implement this function."; %feature("docstring") b2MixFriction "Friction mixing law. Feel free to customize this."; %feature("docstring") b2MixRestitution "Restitution mixing law. Feel free to customize this."; pybox2d-2.3.2/Box2D/Box2D_inline.i000066400000000000000000000212451276457661000164730ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %typemap(out) bool b2CheckPolygon(b2PolygonShape*) { if (!$1) SWIG_fail; else $result = SWIG_From_bool(static_cast< bool >($1)); } %inline %{ // Wrap toi settings extern int32 b2_toiMaxIters, b2_toiMaxRootIters; // Add support for == and != in Python for shapes, joints, and bodies. bool __jointeq(b2Joint* a, b2Joint* b) { return a==b; } bool __bodyeq(b2Body* a, b2Body* b) { return a==b; } bool __shapeeq(b2Shape* a, b2Shape* b) { return a==b; } bool __fixtureeq(b2Fixture* a, b2Fixture* b) { return a==b; } // Modified from the b2PolygonShape constructor // Should be as accurate as the original version b2Vec2 __b2ComputeCentroid(const b2Vec2* vs, int32 count) { b2Vec2 c; c.Set(0.0f, 0.0f); if (count < 3 || count > b2_maxPolygonVertices) { PyErr_SetString(PyExc_ValueError, "Vertex count must be >= 3 and <= b2_maxPolygonVertices"); return c; } float32 area = 0.0f; // pRef is the reference point for forming triangles. // It's location doesn't change the result (except for rounding error). b2Vec2 pRef(0.0f, 0.0f); const float32 inv3 = 1.0f / 3.0f; for (int32 i = 0; i < count; ++i) { // Triangle vertices. b2Vec2 p1 = pRef; b2Vec2 p2 = vs[i]; b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; b2Vec2 e1 = p2 - p1; b2Vec2 e2 = p3 - p1; float32 D = b2Cross(e1, e2); float32 triangleArea = 0.5f * D; area += triangleArea; // Area weighted centroid c += triangleArea * inv3 * (p1 + p2 + p3); } // Centroid if (area <= b2_epsilon) { PyErr_SetString(PyExc_ValueError, "ComputeCentroid: area <= FLT_EPSILON"); return c; } c *= 1.0f / area; return c; } bool b2CheckVertices(b2Vec2* vertices, int32 count, bool additional_checks=true) { // Get the vertices transformed into the body frame. if (count < 2 || count > b2_maxPolygonVertices) { PyErr_SetString(PyExc_ValueError, "Vertex count must be >= 2 and <= b2_maxPolygonVertices"); return false; } // Compute normals. Ensure the edges have non-zero length. b2Vec2 m_normals[b2_maxPolygonVertices]; for (int32 i = 0; i < count; ++i) { int32 i1 = i; int32 i2 = i + 1 < count ? i + 1 : 0; b2Vec2 edge = vertices[i2] - vertices[i1]; if (edge.LengthSquared() <= b2_epsilon * b2_epsilon) { PyErr_SetString(PyExc_ValueError, "edge.LengthSquared < FLT_EPSILON**2"); return false; } m_normals[i] = b2Cross(edge, 1.0f); m_normals[i].Normalize(); } // Compute the polygon centroid. b2Vec2 m_centroid = __b2ComputeCentroid(vertices, count); if (!additional_checks) return true; // Ensure the polygon is convex and the interior // is to the left of each edge. for (int32 i = 0; i < count; ++i) { int32 i1 = i; int32 i2 = i + 1 < count ? i + 1 : 0; b2Vec2 edge = vertices[i2] - vertices[i1]; for (int32 j = 0; j < count; ++j) { // Don not check vertices on the current edge. if (j == i1 || j == i2) { continue; } b2Vec2 r = vertices[j] - vertices[i1]; // Your polygon is non-convex (it has an indentation) or // has colinear edges. float32 s = b2Cross(edge, r); if (s <= 0.0f) { PyErr_SetString(PyExc_ValueError, "Your polygon is non-convex (it has an indentation) or has colinear edges."); return false; } } } return true; } bool b2CheckPolygon(b2PolygonShape *shape, bool additional_checks=true) { if (!shape) return false; return b2CheckVertices(shape->m_vertices, shape->m_count, additional_checks); } /* As of Box2D SVN r191, these functions are no longer in b2Math.h, so re-add them here for backwards compatibility */ #define RAND_LIMIT 32767 // Random number in range [-1,1] float32 b2Random() { float32 r = (float32)(rand() & (RAND_LIMIT)); r /= RAND_LIMIT; r = 2.0f * r - 1.0f; return r; } /// Random floating point number in range [lo, hi] float32 b2Random(float32 lo, float32 hi) { float32 r = (float32)(rand() & (RAND_LIMIT)); r /= RAND_LIMIT; r = (hi - lo) * r + lo; return r; } %} /* Additional supporting Python code */ %pythoncode %{ b2_epsilon = 1.192092896e-07 class _indexable_generator(list): def __init__(self, iter): list.__init__(self) self.iter=iter self.__full=False def __len__(self): self.__fill_list__() return super(_indexable_generator, self).__len__() def __iter__(self): for item in self.iter: self.append(item) yield item self.__full=True def __fill_list__(self): for item in self.iter: self.append(item) self.__full=True def __getitem__(self, i): """Support indexing positive/negative elements of the generator, but no slices. If you want those, use list(generator)""" if not self.__full: if i < 0: self.__fill_list__() elif i >= list.__len__(self): diff=i-list.__len__(self)+1 for j in range(diff): value = next(self.iter) self.append(value) return super(_indexable_generator, self).__getitem__(i) def _generator_from_linked_list(first): if first: one = first while one: yield one one = one.next def _list_from_linked_list(first): if not first: return [] one = first lst = [] while one: lst.append(one) one = one.next # linked lists are stored in reverse order from creation order lst.reverse() return lst # Support using == on bodies, joints, and shapes def b2ShapeCompare(a, b): if not isinstance(a, b2Shape) or not isinstance(b, b2Shape): return False return __shapeeq(a, b) def b2BodyCompare(a, b): if not isinstance(a, b2Body) or not isinstance(b, b2Body): return False return __bodyeq(a, b) def b2JointCompare(a, b): if not isinstance(a, b2Joint) or not isinstance(b, b2Joint): return False return __jointeq(a, b) def b2FixtureCompare(a, b): if not isinstance(a, b2Fixture) or not isinstance(b, b2Fixture): return False return __fixtureeq(a, b) %} %feature("docstring") b2CheckPolygon " Checks the Polygon definition to see if upon creation it will cause an assertion. Raises ValueError if an assertion would be raised. b2PolygonDef* poly - the polygon definition bool additional_checks - whether or not to run additional checks Additional checking: usually only in DEBUG mode on the C++ code. While shapes that pass this test can be created without assertions, they will ultimately create unexpected behavior. It's recommended to _not_ use any polygon that fails this test. "; %feature("docstring") b2AABBOverlaps "Checks if two AABBs overlap, or if a point lies in an AABB b2AABBOverlaps(AABB1, [AABB2/point]) "; pybox2d-2.3.2/Box2D/Box2D_joints.i000066400000000000000000000654611276457661000165330ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /**** JointDef ****/ %extend b2JointDef { public: %pythoncode %{ def to_kwargs(self): """ Returns a dictionary representing this joint definition """ def is_prop(attr): try: is_property = isinstance(getattr(cls, attr), property) except AttributeError: return False return is_property and attr not in skip_props skip_props = ['anchor', 'anchorA', 'anchorB', 'axis'] cls = type(self) return {attr: getattr(self, attr) for attr in dir(self) if is_prop(attr) } %} } /**** Joint ****/ %extend b2Joint { public: %pythoncode %{ __eq__ = b2JointCompare __ne__ = lambda self,other: not b2JointCompare(self,other) # Read-only next = property(__GetNext, None) bodyA = property(__GetBodyA, None) bodyB = property(__GetBodyB, None) type = property(__GetType, None) active = property(__IsActive, None) anchorB = property(__GetAnchorB, None) anchorA = property(__GetAnchorA, None) collideConnected = property(__GetCollideConnected, None) def getAsType(self): """ Backward compatibility """ return self %} } %rename(__GetNext) b2Joint::GetNext; %rename(__GetBodyA) b2Joint::GetBodyA; %rename(__GetBodyB) b2Joint::GetBodyB; %rename(__GetType) b2Joint::GetType; %rename(__IsActive) b2Joint::IsActive; %rename(__GetAnchorA) b2Joint::GetAnchorA; %rename(__GetAnchorB) b2Joint::GetAnchorB; %rename(__GetCollideConnected) b2Joint::GetCollideConnected; /**** RevoluteJoint ****/ %extend b2RevoluteJoint { public: %pythoncode %{ # Read-write properties motorSpeed = property(__GetMotorSpeed, __SetMotorSpeed) upperLimit = property(__GetUpperLimit, lambda self, v: self.SetLimits(self.lowerLimit, v)) lowerLimit = property(__GetLowerLimit, lambda self, v: self.SetLimits(v, self.upperLimit)) limits = property(lambda self: (self.lowerLimit, self.upperLimit), lambda self, v: self.SetLimits(*v) ) motorEnabled = property(__IsMotorEnabled, __EnableMotor) limitEnabled = property(__IsLimitEnabled, __EnableLimit) # Read-only angle = property(__GetJointAngle, None) speed = property(__GetJointSpeed, None) # Write-only maxMotorTorque = property(None, __SetMaxMotorTorque) %} } %rename(__IsMotorEnabled) b2RevoluteJoint::IsMotorEnabled; %rename(__GetUpperLimit) b2RevoluteJoint::GetUpperLimit; %rename(__GetLowerLimit) b2RevoluteJoint::GetLowerLimit; %rename(__GetJointAngle) b2RevoluteJoint::GetJointAngle; %rename(__GetMotorSpeed) b2RevoluteJoint::GetMotorSpeed; %rename(__GetJointSpeed) b2RevoluteJoint::GetJointSpeed; %rename(__IsLimitEnabled) b2RevoluteJoint::IsLimitEnabled; %rename(__SetMotorSpeed) b2RevoluteJoint::SetMotorSpeed; %rename(__EnableLimit) b2RevoluteJoint::EnableLimit; %rename(__SetMaxMotorTorque) b2RevoluteJoint::SetMaxMotorTorque; %rename(__EnableMotor) b2RevoluteJoint::EnableMotor; /**** WheelJoint ****/ %extend b2WheelJoint { public: %pythoncode %{ # Read-write properties motorSpeed = property(__GetMotorSpeed, __SetMotorSpeed) motorEnabled = property(__IsMotorEnabled, __EnableMotor) maxMotorTorque = property(__GetMaxMotorTorque, __SetMaxMotorTorque) springFrequencyHz = property(__GetSpringFrequencyHz , __SetSpringFrequencyHz) springDampingRatio = property(__GetSpringDampingRatio , __SetSpringDampingRatio) # Read-only speed = property(__GetJointSpeed, None) translation = property(__GetJointTranslation, None) %} } %rename(__IsMotorEnabled) b2WheelJoint::IsMotorEnabled; %rename(__GetMotorSpeed) b2WheelJoint::GetMotorSpeed; %rename(__GetJointSpeed) b2WheelJoint::GetJointSpeed; %rename(__GetJointTranslation) b2WheelJoint::GetJointTranslation; %rename(__IsLimitEnabled) b2WheelJoint::IsLimitEnabled; %rename(__SetMotorSpeed) b2WheelJoint::SetMotorSpeed; %rename(__GetSpringFrequencyHz) b2WheelJoint::GetSpringFrequencyHz; %rename(__SetSpringFrequencyHz) b2WheelJoint::SetSpringFrequencyHz; %rename(__GetSpringDampingRatio) b2WheelJoint::GetSpringDampingRatio; %rename(__SetSpringDampingRatio) b2WheelJoint::SetSpringDampingRatio; %rename(__GetMaxMotorTorque) b2WheelJoint::GetMaxMotorTorque; %rename(__SetMaxMotorTorque) b2WheelJoint::SetMaxMotorTorque; %rename(__EnableMotor) b2WheelJoint::EnableMotor; /**** PrismaticJoint ****/ %extend b2PrismaticJoint { public: %pythoncode %{ # Read-write properties motorSpeed = property(__GetMotorSpeed, __SetMotorSpeed) motorEnabled = property(__IsMotorEnabled, __EnableMotor) limitEnabled = property(__IsLimitEnabled, __EnableLimit) upperLimit = property(__GetUpperLimit, lambda self, v: self.SetLimits(self.lowerLimit, v)) lowerLimit = property(__GetLowerLimit, lambda self, v: self.SetLimits(v, self.upperLimit)) limits = property(lambda self: (self.lowerLimit, self.upperLimit), lambda self, v: self.SetLimits(*v) ) maxMotorForce = property(__GetMaxMotorForce, __SetMaxMotorForce) # Read-only translation = property(__GetJointTranslation, None) speed = property(__GetJointSpeed, None) %} } %rename(__IsMotorEnabled) b2PrismaticJoint::IsMotorEnabled; %rename(__GetMotorSpeed) b2PrismaticJoint::GetMotorSpeed; %rename(__GetJointTranslation) b2PrismaticJoint::GetJointTranslation; %rename(__GetUpperLimit) b2PrismaticJoint::GetUpperLimit; %rename(__GetJointSpeed) b2PrismaticJoint::GetJointSpeed; %rename(__IsLimitEnabled) b2PrismaticJoint::IsLimitEnabled; %rename(__GetLowerLimit) b2PrismaticJoint::GetLowerLimit; %rename(__SetMotorSpeed) b2PrismaticJoint::SetMotorSpeed; %rename(__EnableLimit) b2PrismaticJoint::EnableLimit; %rename(__SetMaxMotorForce) b2PrismaticJoint::SetMaxMotorForce; %rename(__GetMaxMotorForce) b2PrismaticJoint::GetMaxMotorForce; %rename(__EnableMotor) b2PrismaticJoint::EnableMotor; /**** DistanceJoint ****/ %extend b2DistanceJoint { public: %pythoncode %{ # Read-write properties length = property(__GetLength, __SetLength) frequency = property(__GetFrequency, __SetFrequency) dampingRatio = property(__GetDampingRatio, __SetDampingRatio) %} } %rename(__GetLength) b2DistanceJoint::GetLength; %rename(__GetFrequency) b2DistanceJoint::GetFrequency; %rename(__GetDampingRatio) b2DistanceJoint::GetDampingRatio; %rename(__SetDampingRatio) b2DistanceJoint::SetDampingRatio; %rename(__SetLength) b2DistanceJoint::SetLength; %rename(__SetFrequency) b2DistanceJoint::SetFrequency; /**** RopeJoint ****/ %extend b2RopeJoint { public: %pythoncode %{ # Read-only properties maxLength = property(__GetMaxLength, None) limitState = property(__GetLimitState, None) # Read-write properties %} } %rename(__GetLimitState) b2RopeJoint::GetLimitState; %rename(__GetMaxLength) b2RopeJoint::GetMaxLength; /**** PulleyJoint ****/ %extend b2PulleyJoint { public: %pythoncode %{ # Read-only groundAnchorB = property(__GetGroundAnchorB, None) groundAnchorA = property(__GetGroundAnchorA, None) ratio = property(__GetRatio, None) lengthB = length2 = property(__GetLengthB, None) lengthA = length1 = property(__GetLengthA, None) %} } %rename(__GetGroundAnchorB) b2PulleyJoint::GetGroundAnchorB; %rename(__GetGroundAnchorA) b2PulleyJoint::GetGroundAnchorA; %rename(__GetLengthB) b2PulleyJoint::GetLengthB; %rename(__GetLengthA) b2PulleyJoint::GetLengthA; %rename(__GetRatio) b2PulleyJoint::GetRatio; /**** MouseJoint ****/ %extend b2MouseJoint { public: %pythoncode %{ # Read-write properties maxForce = property(__GetMaxForce, __SetMaxForce) frequency = property(__GetFrequency, __SetFrequency) dampingRatio = property(__GetDampingRatio, __SetDampingRatio) target = property(__GetTarget, __SetTarget) %} } %rename(__GetMaxForce) b2MouseJoint::GetMaxForce; %rename(__GetFrequency) b2MouseJoint::GetFrequency; %rename(__GetDampingRatio) b2MouseJoint::GetDampingRatio; %rename(__GetTarget) b2MouseJoint::GetTarget; %rename(__SetDampingRatio) b2MouseJoint::SetDampingRatio; %rename(__SetTarget) b2MouseJoint::SetTarget; %rename(__SetMaxForce) b2MouseJoint::SetMaxForce; %rename(__SetFrequency) b2MouseJoint::SetFrequency; /**** GearJoint ****/ %extend b2GearJoint { public: %pythoncode %{ # Read-write properties ratio = property(__GetRatio, __SetRatio) %} } %rename(__GetRatio) b2GearJoint::GetRatio; %rename(__SetRatio) b2GearJoint::SetRatio; /**** WeldJoint ****/ %extend b2WeldJoint { } /**** FrictionJoint ****/ %extend b2FrictionJoint { public: %pythoncode %{ # Read-write properties maxForce = property(__GetMaxForce, __SetMaxForce) maxTorque = property(__GetMaxTorque, __SetMaxTorque) %} } %rename(__GetMaxForce) b2FrictionJoint::GetMaxForce; %rename(__GetMaxTorque) b2FrictionJoint::GetMaxTorque; %rename(__SetMaxTorque) b2FrictionJoint::SetMaxTorque; %rename(__SetMaxForce) b2FrictionJoint::SetMaxForce; /**** Add some of the functionality that Initialize() offers for joint definitions ****/ /**** DistanceJointDef ****/ %extend b2DistanceJointDef { %pythoncode %{ def __update_length(self): if self.bodyA and self.bodyB: d = self.anchorB - self.anchorA self.length = d.length def __set_anchorA(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.__update_length() def __set_anchorB(self, value): if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorB=self.bodyB.GetLocalPoint(value) self.__update_length() def __get_anchorA(self): if not self.bodyA: raise ValueError('bodyA not set.') return self.bodyA.GetWorldPoint(self.localAnchorA) def __get_anchorB(self): if not self.bodyB: raise ValueError('bodyB not set.') return self.bodyB.GetWorldPoint(self.localAnchorB) anchorA = property(__get_anchorA, __set_anchorA, doc="""Body A's anchor in world coordinates. Getting the property depends on both bodyA and localAnchorA. Setting the property requires that bodyA be set.""") anchorB = property(__get_anchorB, __set_anchorB, doc="""Body B's anchor in world coordinates. Getting the property depends on both bodyB and localAnchorB. Setting the property requires that bodyB be set.""") %} } %feature("shadow") b2DistanceJointDef::b2DistanceJointDef() %{ def __init__(self, **kwargs): _Box2D.b2DistanceJointDef_swiginit(self,_Box2D.new_b2DistanceJointDef()) _init_jointdef_kwargs(self, **kwargs) if 'localAnchorA' in kwargs and 'localAnchorB' in kwargs and 'length' not in kwargs: self.__update_length() %} /**** FrictionJointDef ****/ %extend b2FrictionJointDef { %pythoncode %{ def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") %} } %feature("shadow") b2FrictionJointDef::b2FrictionJointDef() %{ def __init__(self, **kwargs): _Box2D.b2FrictionJointDef_swiginit(self,_Box2D.new_b2FrictionJointDef()) _init_jointdef_kwargs(self, **kwargs) %} /**** WheelJointDef ****/ %extend b2WheelJointDef { %pythoncode %{ def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') def __set_axis(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAxisA=self.bodyA.GetLocalVector(value) def __get_axis(self): if self.bodyA: return self.bodyA.GetWorldVector(self.localAxisA) raise ValueError('Body A unset; unable to get world vector.') anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") axis = property(__get_axis, __set_axis, doc="""The world translation axis on bodyA. Getting the property depends on bodyA and localAxisA. Setting the property requires that bodyA be set.""") %} } %feature("shadow") b2WheelJointDef::b2WheelJointDef() %{ def __init__(self, **kwargs): _Box2D.b2WheelJointDef_swiginit(self,_Box2D.new_b2WheelJointDef()) _init_jointdef_kwargs(self, **kwargs) %} /**** PrismaticJointDef ****/ %extend b2PrismaticJointDef { %pythoncode %{ def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') def __set_axis(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAxisA=self.bodyA.GetLocalVector(value) def __get_axis(self): if not self.bodyA: raise ValueError('Body A unset; unable to get world vector.') return self.bodyA.GetWorldVector(self.localAxisA) anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") axis = property(__get_axis, __set_axis, doc="""The world translation axis on bodyA. Getting the property depends on bodyA and localAxisA. Setting the property requires that bodyA be set.""") %} } %feature("shadow") b2PrismaticJointDef::b2PrismaticJointDef() %{ def __init__(self, **kwargs): _Box2D.b2PrismaticJointDef_swiginit(self,_Box2D.new_b2PrismaticJointDef()) _init_jointdef_kwargs(self, **kwargs) if self.bodyA and self.bodyB and 'referenceAngle' not in kwargs: self.referenceAngle = self.bodyB.angle - self.bodyA.angle %} /**** PulleyJointDef ****/ %extend b2PulleyJointDef { %pythoncode %{ def __update_length(self): if self.bodyA: d1 = self.anchorA - self.groundAnchorA self.lengthA = d1.length if self.bodyB: d1 = self.anchorB - self.groundAnchorB self.lengthB = d1.length def __set_anchorA(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.__update_length() def __set_anchorB(self, value): if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorB=self.bodyB.GetLocalPoint(value) self.__update_length() def __get_anchorA(self): if not self.bodyA: raise ValueError('bodyA not set.') return self.bodyA.GetWorldPoint(self.localAnchorA) def __get_anchorB(self): if not self.bodyB: raise ValueError('bodyB not set.') return self.bodyB.GetWorldPoint(self.localAnchorB) anchorA = property(__get_anchorA, __set_anchorA, doc="""Body A's anchor in world coordinates. Getting the property depends on both bodyA and localAnchorA. Setting the property requires that bodyA be set.""") anchorB = property(__get_anchorB, __set_anchorB, doc="""Body B's anchor in world coordinates. Getting the property depends on both bodyB and localAnchorB. Setting the property requires that bodyB be set.""") %} } %feature("shadow") b2PulleyJointDef::b2PulleyJointDef() %{ def __init__(self, **kwargs): _Box2D.b2PulleyJointDef_swiginit(self,_Box2D.new_b2PulleyJointDef()) _init_jointdef_kwargs(self, **kwargs) self.__init_pulley__(**kwargs) def __init_pulley__(self, anchorA=None, anchorB=None, lengthA=None, lengthB=None, groundAnchorA=None, groundAnchorB=None, maxLengthA=None, maxLengthB=None, ratio=None, **kwargs): lengthA_set, lengthB_set = False, False if anchorA is not None or anchorB is not None: # Some undoing -- if the user specified the length, we might # have overwritten it, so reset it. if lengthA is not None: self.lengthA = lengthA lengthA_set = True if lengthB is not None: self.lengthB = lengthB lengthB_set = True if anchorA is not None and groundAnchorA is not None and lengthA is None: d1 = self.anchorA - self.groundAnchorA self.lengthA = d1.length lengthA_set = True if anchorB is not None and groundAnchorB is not None and lengthB is None: d2 = self.anchorB - self.groundAnchorB self.lengthB = d2.length lengthB_set=True if ratio is not None: # Ratio too small? assert(self.ratio > globals()['b2_epsilon']) if lengthA_set and lengthB_set and maxLengthA is None and maxLengthB is None: C = self.lengthA + self.ratio * self.lengthB self.maxLengthA = C - self.ratio * b2_minPulleyLength self.maxLengthB = (C - b2_minPulleyLength) / self.ratio %} /* TODO: Note on the above: assert(self.ratio > globals()['b2_epsilon']) # Ratio too small Should really just be: assert(self.ratio > b2_epsilon) # Ratio too small But somehow SWIG is renaming b2_epsilon to FLT_EPSILON after it sees the #define, but does not export the FLT_EPSILON symbol to Python. It then crashes once it reaches this point. So, figure out a way around this, somehow. */ /**** RevoluteJointDef ****/ %extend b2RevoluteJointDef { %pythoncode %{ def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") %} } %feature("shadow") b2RevoluteJointDef::b2RevoluteJointDef() %{ def __init__(self, **kwargs): _Box2D.b2RevoluteJointDef_swiginit(self,_Box2D.new_b2RevoluteJointDef()) _init_jointdef_kwargs(self, **kwargs) if self.bodyA and self.bodyB and 'referenceAngle' not in kwargs: self.referenceAngle = self.bodyB.angle - self.bodyA.angle %} /**** WeldJointDef ****/ %extend b2WeldJointDef { %pythoncode %{ def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") %} } %feature("shadow") b2WeldJointDef::b2WeldJointDef() %{ def __init__(self, **kwargs): _Box2D.b2WeldJointDef_swiginit(self,_Box2D.new_b2WeldJointDef()) _init_jointdef_kwargs(self, **kwargs) if self.bodyA and self.bodyB and 'referenceAngle' not in kwargs: self.referenceAngle = self.bodyB.angle - self.bodyA.angle %} /**** Add some of the functionality that Initialize() offers for joint definitions ****/ /**** RopeJointDef ****/ %extend b2RopeJointDef { %pythoncode %{ def __set_anchorA(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) def __set_anchorB(self, value): if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchorA(self): if not self.bodyA: raise ValueError('bodyA not set.') return self.bodyA.GetWorldPoint(self.localAnchorA) def __get_anchorB(self): if not self.bodyB: raise ValueError('bodyB not set.') return self.bodyB.GetWorldPoint(self.localAnchorB) anchorA = property(__get_anchorA, __set_anchorA, doc="""Body A's anchor in world coordinates. Getting the property depends on both bodyA and localAnchorA. Setting the property requires that bodyA be set.""") anchorB = property(__get_anchorB, __set_anchorB, doc="""Body B's anchor in world coordinates. Getting the property depends on both bodyB and localAnchorB. Setting the property requires that bodyB be set.""") %} } %feature("shadow") b2RopeJointDef::b2RopeJointDef() %{ def __init__(self, **kwargs): _Box2D.b2RopeJointDef_swiginit(self,_Box2D.new_b2RopeJointDef()) _init_jointdef_kwargs(self, **kwargs) %} /**** Add some of the functionality that Initialize() offers for joint definitions ****/ /**** MotorJointDef ****/ %extend b2MotorJointDef { %pythoncode %{ %} } %feature("shadow") b2MotorJointDef::b2MotorJointDef() %{ def __init__(self, bodyA=None, bodyB=None, **kwargs): _Box2D.b2MotorJointDef_swiginit(self,_Box2D.new_b2MotorJointDef()) _init_jointdef_kwargs(self, bodyA=bodyA, bodyB=bodyB, **kwargs) if bodyA is not None and bodyB is not None: if not kwargs: self.Initialize(bodyA, bodyB) %} %extend b2MotorJoint { public: %pythoncode %{ # Read-write properties maxForce = property(__GetMaxForce, __SetMaxForce) maxTorque = property(__GetMaxTorque, __SetMaxTorque) linearOffset = property(__GetLinearOffset, __SetLinearOffset) angularOffset = property(__GetAngularOffset, __SetAngularOffset) %} } %rename(__GetMaxForce) b2MotorJoint::GetMaxForce; %rename(__SetMaxForce) b2MotorJoint::SetMaxForce; %rename(__GetMaxTorque) b2MotorJoint::GetMaxTorque; %rename(__SetMaxTorque) b2MotorJoint::SetMaxTorque; %rename(__GetLinearOffset) b2MotorJoint::GetLinearOffset; %rename(__SetLinearOffset) b2MotorJoint::SetLinearOffset; %rename(__GetAngularOffset) b2MotorJoint::GetAngularOffset; %rename(__SetAngularOffset) b2MotorJoint::SetAngularOffset; /**** Hide the now useless enums ****/ %ignore e_atLowerLimit; %ignore e_atUpperLimit; %ignore e_distanceJoint; %ignore e_equalLimits; %ignore e_frictionJoint; %ignore e_gearJoint; %ignore e_inactiveLimit; %ignore e_lineJoint; %ignore e_mouseJoint; %ignore e_prismaticJoint; %ignore e_pulleyJoint; %ignore e_revoluteJoint; %ignore e_unknownJoint; %ignore e_weldJoint; %ignore e_motorJoint;; pybox2d-2.3.2/Box2D/Box2D_kwargs.i000066400000000000000000000312471276457661000165160ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %pythoncode %{ def _init_kwargs(self, **kwargs): cls = self.__class__ for key, value in kwargs.items(): try: getattr(cls, key) except AttributeError: raise AttributeError('Invalid keyword argument "%s" for %s' % (key, cls)) try: setattr(self, key, value) except Exception as ex: raise ex.__class__('Failed on kwargs for %s.%s: %s' \ % (self.__class__.__name__, key, ex)) def _init_jointdef_kwargs(self, bodyA=None, bodyB=None, **kwargs): if bodyA is not None or bodyB is not None: # Make sure that bodyA and bodyB are defined before the rest _init_kwargs(self, bodyA=bodyA, bodyB=bodyB) _init_kwargs(self, **kwargs) %} // Generic kwarg initialization: %feature("shadow") b2ContactFilter::b2ContactFilter() { def __init__(self, **kwargs): if self.__class__ == b2ContactFilter: _self = None else: _self = self _Box2D.b2ContactFilter_swiginit(self,_Box2D.new_b2ContactFilter(_self, )) _init_kwargs(self, **kwargs) } %feature("shadow") b2ContactListener::b2ContactListener() { def __init__(self, **kwargs): if self.__class__ == b2ContactListener: _self = None else: _self = self _Box2D.b2ContactListener_swiginit(self,_Box2D.new_b2ContactListener(_self, )) _init_kwargs(self, **kwargs) } %feature("shadow") b2QueryCallback::b2QueryCallback() { def __init__(self, **kwargs): if self.__class__ == b2QueryCallback: _self = None else: _self = self _Box2D.b2QueryCallback_swiginit(self,_Box2D.new_b2QueryCallback(_self, )) _init_kwargs(self, **kwargs) } %feature("shadow") b2Draw::b2Draw() { def __init__(self, **kwargs): if self.__class__ == b2Draw: _self = None else: _self = self _Box2D.b2Draw_swiginit(self,_Box2D.new_b2Draw(_self, )) _init_kwargs(self, **kwargs) } %feature("shadow") b2DrawExtended::b2DrawExtended() { def __init__(self, **kwargs): if self.__class__ == b2DrawExtended: _self = None else: _self = self _Box2D.b2DrawExtended_swiginit(self,_Box2D.new_b2DrawExtended(_self, )) _init_kwargs(self, **kwargs) } %feature("shadow") b2DestructionListener::b2DestructionListener() { def __init__(self, **kwargs): if self.__class__ == b2DestructionListener: _self = None else: _self = self _Box2D.b2DestructionListener_swiginit(self,_Box2D.new_b2DestructionListener(_self, )) _init_kwargs(self, **kwargs) } %feature("shadow") b2AABB::b2AABB() { def __init__(self, **kwargs): _Box2D.b2AABB_swiginit(self,_Box2D.new_b2AABB()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Body::b2Body() { def __init__(self, **kwargs): _Box2D.b2Body_swiginit(self,_Box2D.new_b2Body()) _init_kwargs(self, **kwargs) } %feature("shadow") b2BodyDef::b2BodyDef() { def __init__(self, **kwargs): _Box2D.b2BodyDef_swiginit(self,_Box2D.new_b2BodyDef()) _init_kwargs(self, **kwargs) } %feature("shadow") b2CircleShape::b2CircleShape() { def __init__(self, **kwargs): _Box2D.b2CircleShape_swiginit(self,_Box2D.new_b2CircleShape()) _init_kwargs(self, **kwargs) } %feature("shadow") b2ClipVertex::b2ClipVertex() { def __init__(self, **kwargs): _Box2D.b2ClipVertex_swiginit(self,_Box2D.new_b2ClipVertex()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Color::b2Color() { def __init__(self, **kwargs): _Box2D.b2Color_swiginit(self,_Box2D.new_b2Color()) _init_kwargs(self, **kwargs) } %feature("shadow") b2ContactPoint::b2ContactPoint() { def __init__(self, **kwargs): _Box2D.b2ContactPoint_swiginit(self,_Box2D.new_b2ContactPoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2ContactEdge::b2ContactEdge() { def __init__(self, **kwargs): _Box2D.b2ContactEdge_swiginit(self,_Box2D.new_b2ContactEdge()) _init_kwargs(self, **kwargs) } %feature("shadow") b2ContactID::b2ContactID() { def __init__(self, **kwargs): _Box2D.b2ContactID_swiginit(self,_Box2D.new_b2ContactID()) _init_kwargs(self, **kwargs) } %feature("shadow") b2ContactImpulse::b2ContactImpulse() { def __init__(self, **kwargs): _Box2D.b2ContactImpulse_swiginit(self,_Box2D.new_b2ContactImpulse()) _init_kwargs(self, **kwargs) } %feature("shadow") b2DistanceInput::b2DistanceInput() { def __init__(self, **kwargs): _Box2D.b2DistanceInput_swiginit(self,_Box2D.new_b2DistanceInput()) _init_kwargs(self, **kwargs) } %feature("shadow") b2DistanceJoint::b2DistanceJoint() { def __init__(self, **kwargs): _Box2D.b2DistanceJoint_swiginit(self,_Box2D.new_b2DistanceJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2DistanceOutput::b2DistanceOutput() { def __init__(self, **kwargs): _Box2D.b2DistanceOutput_swiginit(self,_Box2D.new_b2DistanceOutput()) _init_kwargs(self, **kwargs) } %feature("shadow") b2EdgeShape::b2EdgeShape() { def __init__(self, **kwargs): _Box2D.b2EdgeShape_swiginit(self,_Box2D.new_b2EdgeShape()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Filter::b2Filter() { def __init__(self, **kwargs): _Box2D.b2Filter_swiginit(self,_Box2D.new_b2Filter()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Fixture::b2Fixture() { def __init__(self, **kwargs): _Box2D.b2Fixture_swiginit(self,_Box2D.new_b2Fixture()) _init_kwargs(self, **kwargs) } %feature("shadow") b2FixtureDef::b2FixtureDef() { def __init__(self, **kwargs): _Box2D.b2FixtureDef_swiginit(self,_Box2D.new_b2FixtureDef()) _init_kwargs(self, **kwargs) } %feature("shadow") b2FrictionJoint::b2FrictionJoint() { def __init__(self, **kwargs): _Box2D.b2FrictionJoint_swiginit(self,_Box2D.new_b2FrictionJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2GearJoint::b2GearJoint() { def __init__(self, **kwargs): _Box2D.b2GearJoint_swiginit(self,_Box2D.new_b2GearJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2GearJointDef::b2GearJointDef() { def __init__(self, **kwargs): _Box2D.b2GearJointDef_swiginit(self,_Box2D.new_b2GearJointDef()) _init_kwargs(self, **kwargs) } %feature("shadow") b2RopeJoint::b2RopeJoint() { def __init__(self, **kwargs): _Box2D.b2RopeJoint_swiginit(self,_Box2D.new_b2RopeJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2RopeJointDef::b2RopeJointDef() { def __init__(self, **kwargs): _Box2D.b2RopeJointDef_swiginit(self,_Box2D.new_b2RopeJointDef()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Jacobian::b2Jacobian() { def __init__(self, **kwargs): _Box2D.b2Jacobian_swiginit(self,_Box2D.new_b2Jacobian()) _init_kwargs(self, **kwargs) } %feature("shadow") b2JointDef::b2JointDef() { def __init__(self, **kwargs): _Box2D.b2JointDef_swiginit(self,_Box2D.new_b2JointDef()) _init_kwargs(self, **kwargs) } %feature("shadow") b2JointEdge::b2JointEdge() { def __init__(self, **kwargs): _Box2D.b2JointEdge_swiginit(self,_Box2D.new_b2JointEdge()) _init_kwargs(self, **kwargs) } %feature("shadow") b2WheelJoint::b2WheelJoint() { def __init__(self, **kwargs): _Box2D.b2WheelJoint_swiginit(self,_Box2D.new_b2WheelJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2MotorJoint::b2MotorJoint() { def __init__(self, **kwargs): _Box2D.b2MotorJoint_swiginit(self,_Box2D.new_b2MotorJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2ChainShape::b2ChainShape() { def __init__(self, **kwargs): _Box2D.b2ChainShape_swiginit(self,_Box2D.new_b2ChainShape()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Manifold::b2Manifold() { def __init__(self, **kwargs): _Box2D.b2Manifold_swiginit(self,_Box2D.new_b2Manifold()) _init_kwargs(self, **kwargs) } %feature("shadow") b2ManifoldPoint::b2ManifoldPoint() { def __init__(self, **kwargs): _Box2D.b2ManifoldPoint_swiginit(self,_Box2D.new_b2ManifoldPoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2MassData::b2MassData() { def __init__(self, **kwargs): _Box2D.b2MassData_swiginit(self,_Box2D.new_b2MassData()) _init_kwargs(self, **kwargs) } %feature("shadow") b2MouseJoint::b2MouseJoint() { def __init__(self, **kwargs): _Box2D.b2MouseJoint_swiginit(self,_Box2D.new_b2MouseJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2MouseJointDef::b2MouseJointDef() { def __init__(self, **kwargs): _Box2D.b2MouseJointDef_swiginit(self,_Box2D.new_b2MouseJointDef()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Pair::b2Pair() { def __init__(self, **kwargs): _Box2D.b2Pair_swiginit(self,_Box2D.new_b2Pair()) _init_kwargs(self, **kwargs) } %feature("shadow") b2PolygonShape::b2PolygonShape() { def __init__(self, **kwargs): _Box2D.b2PolygonShape_swiginit(self,_Box2D.new_b2PolygonShape()) _init_kwargs(self, **kwargs) } %feature("shadow") b2PrismaticJoint::b2PrismaticJoint() { def __init__(self, **kwargs): _Box2D.b2PrismaticJoint_swiginit(self,_Box2D.new_b2PrismaticJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2PulleyJoint::b2PulleyJoint() { def __init__(self, **kwargs): _Box2D.b2PulleyJoint_swiginit(self,_Box2D.new_b2PulleyJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2RayCastInput::b2RayCastInput() { def __init__(self, **kwargs): _Box2D.b2RayCastInput_swiginit(self,_Box2D.new_b2RayCastInput()) _init_kwargs(self, **kwargs) } %feature("shadow") b2RayCastOutput::b2RayCastOutput() { def __init__(self, **kwargs): _Box2D.b2RayCastOutput_swiginit(self,_Box2D.new_b2RayCastOutput()) _init_kwargs(self, **kwargs) } %feature("shadow") b2RevoluteJoint::b2RevoluteJoint() { def __init__(self, **kwargs): _Box2D.b2RevoluteJoint_swiginit(self,_Box2D.new_b2RevoluteJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Segment::b2Segment() { def __init__(self, **kwargs): _Box2D.b2Segment_swiginit(self,_Box2D.new_b2Segment()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Sweep::b2Sweep() { def __init__(self, **kwargs): _Box2D.b2Sweep_swiginit(self,_Box2D.new_b2Sweep()) _init_kwargs(self, **kwargs) } %feature("shadow") b2TOIInput::b2TOIInput() { def __init__(self, **kwargs): _Box2D.b2TOIInput_swiginit(self,_Box2D.new_b2TOIInput()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Transform::b2Transform() { def __init__(self, **kwargs): _Box2D.b2Transform_swiginit(self,_Box2D.new_b2Transform()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Version::b2Version() { def __init__(self, **kwargs): _Box2D.b2Version_swiginit(self,_Box2D.new_b2Version()) _init_kwargs(self, **kwargs) } %feature("shadow") b2WeldJoint::b2WeldJoint() { def __init__(self, **kwargs): _Box2D.b2WeldJoint_swiginit(self,_Box2D.new_b2WeldJoint()) _init_kwargs(self, **kwargs) } %feature("shadow") b2WorldManifold::b2WorldManifold() { def __init__(self, **kwargs): _Box2D.b2WorldManifold_swiginit(self,_Box2D.new_b2WorldManifold()) _init_kwargs(self, **kwargs) } %feature("shadow") b2Rot::b2Rot() { def __init__(self, **kwargs): _Box2D.b2Rot_swiginit(self,_Box2D.new_b2Rot()) _init_kwargs(self, **kwargs) } pybox2d-2.3.2/Box2D/Box2D_math.i000066400000000000000000000355661276457661000161610ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ //These operators do not work unless explicitly defined like this %ignore operator + (const b2Vec2& a, const b2Vec2& b); %ignore operator + (const b2Mat22& A, const b2Mat22& B); %ignore operator - (const b2Vec2& a, const b2Vec2& b); %ignore operator * (float32 s, const b2Vec2& a); %ignore operator == (const b2Vec2& a, const b2Vec2& b); %ignore operator * (float32 s, const b2Vec3& a); %ignore operator + (const b2Vec3& a, const b2Vec3& b); %ignore operator - (const b2Vec3& a, const b2Vec3& b); //Since Python (apparently) requires __imul__ to return self, //these void operators will not do. So, rename them, then call them //with Python code, and return self. (see further down in b2Vec2) %rename(__add_vector) b2Vec2::operator += (const b2Vec2& v); %rename(__sub_vector) b2Vec2::operator -= (const b2Vec2& v); %rename(__mul_float ) b2Vec2::operator *= (float32 a); %rename(__add_vector) b2Vec3::operator += (const b2Vec3& v); %rename(__sub_vector) b2Vec3::operator -= (const b2Vec3& v); %rename(__mul_float ) b2Vec3::operator *= (float32 a); /**** Vector classes ****/ %extend b2Vec2 { public: b2Vec2() { return new b2Vec2(0.0f, 0.0f); } b2Vec2(b2Vec2& other) { return new b2Vec2(other.x, other.y); } %pythoncode %{ __iter__ = lambda self: iter( (self.x, self.y) ) __eq__ = lambda self, other: self.__equ(other) __ne__ = lambda self,other: not self.__equ(other) def __repr__(self): return "b2Vec2(%g,%g)" % (self.x, self.y) def __len__(self): return 2 def __neg__(self): return b2Vec2(-self.x, -self.y) def copy(self): """ Return a copy of the vector. Remember that the following: a = b2Vec2() b = a Does not copy the vector itself, but b now refers to a. """ return b2Vec2(self.x, self.y) __copy__ = copy def __iadd__(self, other): self.__add_vector(other) return self def __isub__(self, other): self.__sub_vector(other) return self def __imul__(self, a): self.__mul_float(a) return self def __itruediv__(self, a): self.__div_float(a) return self def __idiv__(self, a): self.__div_float(a) return self def __set(self, x, y): self.x = x self.y = y def __nonzero__(self): return self.x!=0.0 or self.y!=0.0 tuple = property(lambda self: (self.x, self.y), lambda self, value: self.__set(*value)) length = property(__Length, None) lengthSquared = property(__LengthSquared, None) valid = property(__IsValid, None) skew = property(__Skew, None) %} float32 cross(b2Vec2& other) { return $self->x * other.y - $self->y * other.x; } b2Vec2 cross(float32 s) { return b2Vec2(s * $self->y, -s * $self->x); } float32 __getitem__(int i) { if (i==0) return $self->x; else if (i==1) return $self->y; PyErr_SetString(PyExc_IndexError, "Index must be in (0,1)"); return 0.0f; } void __setitem__(int i, float32 value) { if (i==0) $self->x=value; else if (i==1) $self->y=value; else PyErr_SetString(PyExc_IndexError, "Index must be in (0,1)"); } bool __equ(b2Vec2& other) { return ($self->x == other.x && $self->y == other.y); } float32 dot(b2Vec2& other) { return $self->x * other.x + $self->y * other.y; } b2Vec2 __truediv__(float32 a) { //python 3k return b2Vec2($self->x / a, $self->y / a); } b2Vec2 __div__(float32 a) { return b2Vec2($self->x / a, $self->y / a); } b2Vec2 __mul__(float32 a) { return b2Vec2($self->x * a, $self->y * a); } b2Vec2 __add__(b2Vec2* other) { return b2Vec2($self->x + other->x, $self->y + other->y); } b2Vec2 __sub__(b2Vec2* other) { return b2Vec2($self->x - other->x, $self->y - other->y); } b2Vec2 __rmul__(float32 a) { return b2Vec2($self->x * a, $self->y * a); } b2Vec2 __rdiv__(float32 a) { return b2Vec2($self->x / a, $self->y / a); } void __div_float(float32 a) { $self->x /= a; $self->y /= a; } } %rename (__Length) b2Vec2::Length; %rename (__LengthSquared) b2Vec2::LengthSquared; %rename (__IsValid) b2Vec2::IsValid; %rename (__Skew) b2Vec2::Skew; %extend b2Vec3 { public: b2Vec3() { return new b2Vec3(0.0f, 0.0f, 0.0f); } b2Vec3(b2Vec3& other) { return new b2Vec3(other.x, other.y, other.z); } b2Vec3(b2Vec2& other) { return new b2Vec3(other.x, other.y, 0.0f); } %pythoncode %{ __iter__ = lambda self: iter( (self.x, self.y, self.z) ) __eq__ = lambda self, other: (self.x == other.x and self.y == other.y and self.z == other.z) __ne__ = lambda self, other: (self.x != other.x or self.y != other.y or self.z != other.z) def __repr__(self): return "b2Vec3(%g,%g,%g)" % (self.x, self.y, self.z) def __len__(self): return 3 def __neg__(self): return b2Vec3(-self.x, -self.y, -self.z) def copy(self): """ Return a copy of the vector. Remember that the following: a = b2Vec3() b = a Does not copy the vector itself, but b now refers to a. """ return b2Vec3(self.x, self.y, self.z) __copy__ = copy def __iadd__(self, other): self.__add_vector(other) return self def __isub__(self, other): self.__sub_vector(other) return self def __imul__(self, a): self.__mul_float(a) return self def __itruediv__(self, a): self.__div_float(a) return self def __idiv__(self, a): self.__div_float(a) return self def dot(self, v): """ Dot product with v (list/tuple or b2Vec3) """ if isinstance(v, (list, tuple)): return self.x*v[0] + self.y*v[1] + self.z*v[2] else: return self.x*v.x + self.y*v.y + self.z*v.z def __set(self, x, y, z): self.x = x self.y = y self.z = z def __nonzero__(self): return self.x!=0.0 or self.y!=0.0 or self.z!=0.0 tuple = property(lambda self: (self.x, self.y, self.z), lambda self, value: self.__set(*value)) length = property(_Box2D.b2Vec3___Length, None) lengthSquared = property(_Box2D.b2Vec3___LengthSquared, None) valid = property(_Box2D.b2Vec3___IsValid, None) %} b2Vec3 cross(b2Vec3& b) { return b2Vec3($self->y * b.z - $self->z * b.y, $self->z * b.x - $self->x * b.z, $self->x * b.y - $self->y * b.x); } float32 __getitem__(int i) { if (i==0) return $self->x; else if (i==1) return $self->y; else if (i==2) return $self->z; PyErr_SetString(PyExc_IndexError, "Index must be in (0,1,2)"); return 0.0f; } void __setitem__(int i, float32 value) { if (i==0) $self->x=value; else if (i==1) $self->y=value; else if (i==2) $self->z=value; else PyErr_SetString(PyExc_IndexError, "Index must be in (0,1,2)"); } bool __IsValid() { return b2IsValid($self->x) && b2IsValid($self->y) && b2IsValid($self->z); } float32 __Length() { return b2Sqrt($self->x * $self->x + $self->y * $self->y + $self->z * $self->z); } float32 __LengthSquared() { return ($self->x * $self->x + $self->y * $self->y + $self->z * $self->z); } b2Vec3 __truediv__(float32 a) { return b2Vec3($self->x / a, $self->y / a, $self->z / a); } b2Vec3 __div__(float32 a) { return b2Vec3($self->x / a, $self->y / a, $self->z / a); } b2Vec3 __mul__(float32 a) { return b2Vec3($self->x * a, $self->y * a, $self->z * a); } b2Vec3 __add__(b2Vec3* other) { return b2Vec3($self->x + other->x, $self->y + other->y, $self->z + other->z); } b2Vec3 __sub__(b2Vec3* other) { return b2Vec3($self->x - other->x, $self->y - other->y, $self->z - other->z); } b2Vec3 __rmul__(float32 a) { return b2Vec3($self->x * a, $self->y * a, $self->z * a); } b2Vec3 __rdiv__(float32 a) { return b2Vec3($self->x / a, $self->y / a, self->z / a); } void __div_float(float32 a) { $self->x /= a; $self->y /= a; $self->z /= a; } } /**** Mat22 ****/ %extend b2Mat22 { public: b2Mat22() { return new b2Mat22(b2Vec2(1.0f, 0.0f), b2Vec2(0.0f, 1.0f)); } // backward-compatibility float32 __GetAngle() const { return b2Atan2($self->ex.y, $self->ex.x); } void __SetAngle(float32 angle) { float32 c = cosf(angle), s = sinf(angle); $self->ex.x = c; $self->ey.x = -s; $self->ex.y = s; $self->ey.y = c; } %pythoncode %{ # Read-only inverse = property(__GetInverse, None) angle = property(__GetAngle, __SetAngle) ex = property(lambda self: self.col1, lambda self, v: setattr(self, 'col1', v)) ey = property(lambda self: self.col2, lambda self, v: setattr(self, 'col2', v)) set = __SetAngle %} b2Vec2 __mul__(b2Vec2* v) { return b2Vec2($self->ex.x * v->x + $self->ey.x * v->y, $self->ex.y * v->x + $self->ey.y * v->y); } b2Mat22 __mul__(b2Mat22* m) { return b2Mat22(b2Mul(*($self), m->ex), b2Mul(*($self), m->ey)); } b2Mat22 __add__(b2Mat22* m) { return b2Mat22($self->ex + m->ex, $self->ey + m->ey); } b2Mat22 __sub__(b2Mat22* m) { return b2Mat22($self->ex - m->ex, $self->ey - m->ey); } void __iadd(b2Mat22* m) { $self->ex += m->ex; $self->ey += m->ey; } void __isub(b2Mat22* m) { $self->ex -= m->ex; $self->ey -= m->ey; } } %rename(__SetAngle) b2Mat22::Set; %rename(__GetInverse) b2Mat22::GetInverse; %rename(col1) b2Mat22::ex; %rename(col2) b2Mat22::ey; %feature("shadow") b2Mat22::__iadd__ { def __iadd__(self, other): self.__iadd(other) return self } %feature("shadow") b2Mat22::__isub__ { def __iadd__(self, other): self.__iadd(other) return self } /**** Mat33 ****/ %extend b2Mat33 { public: b2Mat33() { return new b2Mat33(b2Vec3(1.0f, 0.0f, 0.0f), b2Vec3(0.0f, 1.0f, 0.0f), b2Vec3(0.0f, 0.0f, 1.0f)); } %pythoncode %{ ex = property(lambda self: self.col1, lambda self, v: setattr(self, 'col1', v)) ey = property(lambda self: self.col2, lambda self, v: setattr(self, 'col2', v)) ez = property(lambda self: self.col3, lambda self, v: setattr(self, 'col3', v)) %} b2Vec3 __mul__(b2Vec3& v) { return v.x * $self->ex + v.y * $self->ey + v.z * $self->ez; } b2Mat33 __add__(b2Mat33* other) { return b2Mat33($self->ex + other->ex, $self->ey + other->ey, $self->ez + other->ez); } b2Mat33 __sub__(b2Mat33* other) { return b2Mat33($self->ex - other->ex, $self->ey - other->ey, $self->ez - other->ez); } void __iadd(b2Mat33* other) { $self->ex += other->ex; $self->ey += other->ey; $self->ez += other->ez; } void __isub(b2Mat33* other) { $self->ex -= other->ex; $self->ey -= other->ey; $self->ez -= other->ez; } } %feature("shadow") b2Mat33::__iadd__ { def __iadd__(self, other): self.__iadd(other) return self } %feature("shadow") b2Mat33::__isub__ { def __isub__(self, other): self.__isub(other) return self } %rename(set) b2Mat33::Set; %rename(col1) b2Mat33::ex; %rename(col2) b2Mat33::ey; %rename(col3) b2Mat33::ez; /**** Transform ****/ %extend b2Transform { public: b2Rot __get_rotation_matrix() { return $self->q; } %pythoncode %{ def __get_angle(self): return self.q.angle def __set_angle(self, angle): self.q.angle = angle def __set_rotation_matrix(self, rot_matrix): self.q.angle = rot_matrix.angle angle = property(__get_angle, __set_angle) R = property(__get_rotation_matrix, __set_rotation_matrix) %} b2Vec2 __mul__(b2Vec2& v) { float32 x = ($self->q.c * v.x - $self->q.s * v.y) + $self->p.x; float32 y = ($self->q.s * v.x + $self->q.c * v.y) + $self->p.y; return b2Vec2(x, y); } } %rename(position) b2Transform::p; /**** Rot ****/ %extend b2Rot { public: %pythoncode %{ angle = property(__GetAngle, __SetAngle) x_axis = property(GetXAxis, None) y_axis = property(GetYAxis, None) %} b2Vec2 __mul__(b2Vec2& v) { return b2Mul(*($self), v); } } %rename(__SetAngle) b2Rot::Set; %rename(__GetAngle) b2Rot::GetAngle; /**** AABB ****/ %rename(__contains__) b2AABB::Contains; %rename(__IsValid) b2AABB::IsValid; %rename(__GetExtents) b2AABB::GetExtents; %rename(__GetCenter) b2AABB::GetCenter; %rename(__GetPerimeter) b2AABB::GetPerimeter; %include "Box2D/Collision/b2Collision.h" %extend b2AABB { public: %pythoncode %{ # Read-only valid = property(__IsValid, None) extents = property(__GetExtents, None) center = property(__GetCenter, None) perimeter = property(__GetPerimeter, None) %} bool __contains__(const b2Vec2& point) { //If point is in aabb (including a small buffer around it), return true. if (point.x < ($self->upperBound.x + b2_epsilon) && point.x > ($self->lowerBound.x - b2_epsilon) && point.y < ($self->upperBound.y + b2_epsilon) && point.y > ($self->lowerBound.y - b2_epsilon)) return true; return false; } bool overlaps(const b2AABB& aabb2) { //If aabb and aabb2 overlap, return true. (modified from b2BroadPhase::InRange) b2Vec2 d = b2Max($self->lowerBound - aabb2.upperBound, aabb2.lowerBound - $self->upperBound); return b2Max(d.x, d.y) < 0.0f; } } pybox2d-2.3.2/Box2D/Box2D_misc.i000066400000000000000000000220001276457661000161360ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /* ---- miscellaneous classes ---- */ /**** Color ****/ %extend b2Color { public: b2Color(b2Color& other) { return new b2Color(other.r, other.g, other.b); } PyObject* __get_bytes() { PyObject* ret=PyList_New(3); PyList_SetItem(ret, 0, SWIG_From_int((int)(255*$self->r))); PyList_SetItem(ret, 1, SWIG_From_int((int)(255*$self->g))); PyList_SetItem(ret, 2, SWIG_From_int((int)(255*$self->b))); return ret; } %pythoncode %{ __iter__ = lambda self: iter((self.r, self.g, self.b)) __eq__ = lambda self, other: self.__equ(other) __ne__ = lambda self,other: not self.__equ(other) def __repr__(self): return "b2Color(%g,%g,%g)" % (self.r, self.g, self.b) def __len__(self): return 3 def __copy__(self): return b2Color(self.r, self.g, self.b) def copy(self): return b2Color(self.r, self.g, self.b) def __set_bytes(self, value): if len(value) != 3: raise ValueError('Expected length 3 list') self.r, self.g, self.b = value[0]/255, value[1]/255, value[2]/255 def __set_tuple(self, value): if len(value) != 3: raise ValueError('Expected length 3 list') self.r, self.g, self.b = value[0], value[1], value[2] def __nonzero__(self): return self.r!=0.0 or self.g!=0.0 or self.b!=0.0 list = property(lambda self: list(self), __set_tuple) bytes = property(__get_bytes, __set_bytes) %} float32 __getitem__(int i) { if (i==0) return $self->r; else if (i==1) return $self->g; else if (i==2) return $self->b; PyErr_SetString(PyExc_IndexError, "Index must be in (0,1,2)"); return 0.0f; } void __setitem__(int i, float32 value) { if (i==0) $self->r=value; else if (i==1) $self->g=value; else if (i==2) $self->b=value; else PyErr_SetString(PyExc_IndexError, "Index must be in (0,1,2)"); } b2Color __truediv__(float32 a) { return b2Color($self->r / a, $self->g / a, $self->b / a); } b2Color __add__(b2Color& o) { return b2Color($self->r + o.r, $self->g + o.g, $self->b + o.b); } b2Color __sub__(b2Color& o) { return b2Color($self->r - o.r, $self->g - o.g, $self->b - o.b); } b2Color __div__(float32 a) { return b2Color($self->r / a, $self->g / a, $self->b / a); } b2Color __rmul__(float32 a) { return b2Color($self->r * a, $self->g * a, $self->b * a); } b2Color __mul__(float32 a) { return b2Color($self->r * a, $self->g * a, $self->b * a); } void __isub(b2Color& o) { $self->r -= o.r; $self->g -= o.g; $self->b -= o.b; } void __itruediv(b2Color& o) { $self->r /= o.r; $self->g /= o.g; $self->b /= o.b; } void __idiv(b2Color& o) { $self->r /= o.r; $self->g /= o.g; $self->b /= o.b; } void __imul(b2Color& o) { $self->r *= o.r; $self->g *= o.g; $self->b *= o.b; } void __iadd(b2Color& o) { $self->r += o.r; $self->g += o.g; $self->b += o.b; } bool __equ(b2Color& b) { return ($self->r == b.r && $self->g==b.g && $self->b==b.b); } } %feature("shadow") b2Color::__iadd { def __iadd__(self, other): self.__iadd(other) return self } %feature("shadow") b2Color::__isub { def __isub__(self, other): self.__isub(other) return self } %feature("shadow") b2Color::__imul { def __imul__(self, other): self.__imul(other) return self } %feature("shadow") b2Color::__idiv { def __idiv__(self, other): self.__idiv(other) return self } %feature("shadow") b2Color::__itruediv { def __itruediv__(self, other): self.__itruediv(other) return self } /**** DistanceProxy ****/ %extend b2DistanceProxy { public: %pythoncode %{ def __get_vertices(self): """Returns all of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" return [ (self.__get_vertex(i).x, self.__get_vertex(i).y ) for i in range(0, self.__get_vertex_count())] vertices = property(__get_vertices, None) %} } %feature("shadow") b2DistanceProxy::b2DistanceProxy() { def __init__(self, shape, index=0): _Box2D.b2DistanceProxy_swiginit(self,_Box2D.new_b2DistanceProxy()) self.Set(shape, index) } /* Shouldn't need access to these, only by setting the shape. */ %rename (__get_vertex) b2DistanceProxy::GetVertex; %rename (__get_vertex_count) b2DistanceProxy::GetVertexCount; %ignore b2DistanceProxy::m_count; %ignore b2DistanceProxy::m_vertices; %ignore b2DistanceProxy::m_radius; /**** Version ****/ %extend b2Version { public: %pythoncode %{ def __repr__(self): return "b2Version(%s.%s.%s)" % (self.major, self.minor, self.revision) %} } /*** Replace b2Distance ***/ %inline %{ b2DistanceOutput* _b2Distance(b2Shape* shapeA, int idxA, b2Shape* shapeB, int idxB, b2Transform& transformA, b2Transform& transformB, bool useRadii=true) { if (!shapeA || !shapeB) return NULL; b2DistanceInput input; b2DistanceOutput* out=new b2DistanceOutput; b2SimplexCache cache; input.proxyA.Set(shapeA, idxA); input.proxyB.Set(shapeB, idxB); input.transformA = transformA; input.transformB = transformB; input.useRadii = useRadii; cache.count=0; b2Distance(out, &cache, &input); return out; } b2DistanceOutput* _b2Distance(b2DistanceInput* input) { if (!input) return NULL; b2DistanceOutput* out=new b2DistanceOutput; b2SimplexCache cache; cache.count=0; b2Distance(out, &cache, input); return out; } %} %pythoncode %{ import collections b2DistanceResult = collections.namedtuple('b2DistanceResult', 'pointA pointB distance iterations') def b2Distance(shapeA=None, idxA=0, shapeB=None, idxB=0, transformA=None, transformB=None, useRadii=True): """ Compute the closest points between two shapes. Can be called one of two ways: + b2Distance(b2DistanceInput) This uses the b2DistanceInput structure, where you define your own distance proxies Or more conveniently using kwargs: + b2Distance(shapeA=.., idxA=0, shapeB=.., idxB=0, transformA=.., transformB=.., useRadii=True) Returns a namedtuple in the form: b2DistanceResult(pointA=(ax, ay), pointB=(bx, by), distance, iterations) """ if isinstance(shapeA, b2DistanceInput): out = _b2Distance(shapeA) else: out = _b2Distance(shapeA, idxA, shapeB, idxB, transformA, transformB, useRadii) return b2DistanceResult(pointA=tuple(out.pointA), pointB=tuple(out.pointB), distance=out.distance, iterations=out.iterations) %} %newobject _b2Distance; %ignore b2Distance; /**** Sweep ****/ %extend b2Sweep { public: b2Transform* GetTransform(float32 alpha) { b2Transform* out=new b2Transform; $self->GetTransform(out, alpha); return out; } } %newobject b2Sweep::GetTransform; /**** BroadPhase ****/ //TODO: this needs to be fixed up %extend b2BroadPhase { public: %pythoncode %{ proxyCount=property(__GetProxyCount, None) treeHeight=property(__GetTreeHeight, None) treeBalance=property(__GetTreeBalance, None) treeQuality=property(__GetTreeQuality, None) %} } %rename (__GetProxyCount) b2BroadPhase::GetProxyCount; %rename (__GetTreeHeight) b2BroadPhase::GetTreeHeight; %rename (__GetTreeBalance) b2BroadPhase::GetTreeBalance; %rename (__GetTreeQuality) b2BroadPhase::GetTreeQuality; %ignore b2BroadPhase::GetUserData; %ignore b2BroadPhase::CreateProxy; %ignore b2BroadPhase::DestroyProxy; pybox2d-2.3.2/Box2D/Box2D_printing.i000066400000000000000000000404531276457661000170510ustar00rootroot00000000000000//!/usr/bin/python // // C++ version copyright 2010 Erin Catto http://www.gphysics.com // Python version copyright 2010 Ken Lauer / sirkne at gmail dot com // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. // %pythoncode %{ _repr_attrs = {'b2AABB': ['center', 'extents', 'lowerBound', 'perimeter', 'upperBound', 'valid', ], 'b2Body': ['active', 'angle', 'angularDamping', 'angularVelocity', 'awake', 'bullet', 'contacts', 'fixedRotation', 'fixtures', 'inertia', 'joints', 'linearDamping', 'linearVelocity', 'localCenter', 'mass', 'massData', 'position', 'sleepingAllowed', 'transform', 'type', 'userData', 'worldCenter', ], 'b2BodyDef': ['active', 'allowSleep', 'angle', 'angularDamping', 'angularVelocity', 'awake', 'bullet', 'fixedRotation', 'fixtures', 'inertiaScale', 'linearDamping', 'linearVelocity', 'position', 'shapeFixture', 'shapes', 'type', 'userData', ], 'b2BroadPhase': ['proxyCount', ], 'b2CircleShape': ['childCount', 'pos', 'radius', 'type', ], 'b2ClipVertex': ['id', 'v', ], 'b2Color': ['b', 'bytes', 'g', 'list', 'r', ], 'b2Contact': ['childIndexA', 'childIndexB', 'enabled', 'fixtureA', 'fixtureB', 'manifold', 'touching', 'worldManifold', ], 'b2ContactEdge': ['contact', 'other', ], 'b2ContactFeature': ['indexA', 'indexB', 'typeA', 'typeB', ], 'b2ContactID': ['cf', 'key', ], 'b2ContactImpulse': ['normalImpulses', 'tangentImpulses', ], 'b2ContactManager': ['allocator', 'broadPhase', 'contactCount', 'contactFilter', 'contactList', 'contactListener', ], 'b2ContactPoint': ['fixtureA', 'fixtureB', 'normal', 'position', 'state', ], 'b2DistanceInput': ['proxyA', 'proxyB', 'transformA', 'transformB', 'useRadii', ], 'b2DistanceJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'dampingRatio', 'frequency', 'length', 'type', 'userData', ], 'b2DistanceJointDef': ['anchorA', 'anchorB', 'bodyA', 'bodyB', 'collideConnected', 'dampingRatio', 'frequencyHz', 'length', 'localAnchorA', 'localAnchorB', 'type', 'userData', ], 'b2DistanceOutput': ['distance', 'iterations', 'pointA', 'pointB', ], 'b2DistanceProxy': ['m_buffer', 'shape', 'vertices', ], 'b2Draw': ['flags', ], 'b2DrawExtended': ['center', 'convertVertices', 'flags', 'flipX', 'flipY', 'offset', 'screenSize', 'zoom', ], 'b2EdgeShape': ['all_vertices', 'childCount', 'hasVertex0', 'hasVertex3', 'radius', 'type', 'vertex0', 'vertex1', 'vertex2', 'vertex3', 'vertexCount', 'vertices', ], 'b2Filter': ['categoryBits', 'groupIndex', 'maskBits', ], 'b2Fixture': ['body', 'density', 'filterData', 'friction', 'massData', 'restitution', 'sensor', 'shape', 'type', 'userData', ], 'b2FixtureDef': ['categoryBits', 'density', 'filter', 'friction', 'groupIndex', 'isSensor', 'maskBits', 'restitution', 'shape', 'userData', ], 'b2FixtureProxy': ['aabb', 'childIndex', 'fixture', 'proxyId', ], 'b2FrictionJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'maxForce', 'maxTorque', 'type', 'userData', ], 'b2FrictionJointDef': ['anchor', 'bodyA', 'bodyB', 'collideConnected', 'localAnchorA', 'localAnchorB', 'maxForce', 'maxTorque', 'type', 'userData', ], 'b2GearJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'ratio', 'type', 'userData', ], 'b2GearJointDef': ['bodyA', 'bodyB', 'collideConnected', 'joint1', 'joint2', 'ratio', 'type', 'userData', ], 'b2Jacobian': ['angularA', 'angularB', 'linearA', 'linearB', ], 'b2Joint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'type', 'userData', ], 'b2JointDef': ['bodyA', 'bodyB', 'collideConnected', 'type', 'userData', ], 'b2JointEdge': ['joint', 'other', ], 'b2WheelJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'maxMotorTorque', 'motorEnabled', 'motorSpeed', 'speed', 'springDampingRatio', 'springFrequencyHz', 'translation', 'type', 'userData', ], 'b2WheelJointDef': ['anchor', 'axis', 'bodyA', 'bodyB', 'collideConnected', 'dampingRatio', 'enableMotor', 'frequencyHz', 'localAnchorA', 'localAnchorB', 'localAxisA', 'maxMotorTorque', 'motorSpeed', 'type', 'userData', ], 'b2ChainShape': ['childCount', 'edges', 'radius', 'type', 'vertexCount', 'vertices', ], 'b2Manifold': ['localNormal', 'localPoint', 'pointCount', 'points', 'type_', ], 'b2ManifoldPoint': ['id', 'isNew', 'localPoint', 'normalImpulse', 'tangentImpulse', ], 'b2MassData': ['I', 'center', 'mass', ], 'b2Mat22': ['angle', 'col1', 'col2', 'inverse', ], 'b2Mat33': ['col1', 'col2', 'col3', ], 'b2MouseJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'dampingRatio', 'frequency', 'maxForce', 'target', 'type', 'userData', ], 'b2MouseJointDef': ['bodyA', 'bodyB', 'collideConnected', 'dampingRatio', 'frequencyHz', 'maxForce', 'target', 'type', 'userData', ], 'b2Pair': ['proxyIdA', 'proxyIdB', ], 'b2PolygonShape': ['box', 'centroid', 'childCount', 'normals', 'radius', 'type', 'valid', 'vertexCount', 'vertices', ], 'b2PrismaticJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'limitEnabled', 'limits', 'lowerLimit', 'maxMotorForce', 'motorEnabled', 'motorSpeed', 'speed', 'translation', 'type', 'upperLimit', 'userData', ], 'b2PrismaticJointDef': ['anchor', 'axis', 'bodyA', 'bodyB', 'collideConnected', 'enableLimit', 'enableMotor', 'localAnchorA', 'localAnchorB', 'localAxis1', 'lowerTranslation', 'maxMotorForce', 'motorSpeed', 'referenceAngle', 'type', 'upperTranslation', 'userData', ], 'b2PulleyJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'groundAnchorA', 'groundAnchorB', 'length1', 'length2', 'ratio', 'type', 'userData', ], 'b2PulleyJointDef': ['anchorA', 'anchorB', 'bodyA', 'bodyB', 'collideConnected', 'groundAnchorA', 'groundAnchorB', 'lengthA', 'lengthB', 'localAnchorA', 'localAnchorB', 'maxLengthA', 'maxLengthB', 'ratio', 'type', 'userData', ], 'b2RayCastInput': ['maxFraction', 'p1', 'p2', ], 'b2RayCastOutput': ['fraction', 'normal', ], 'b2RevoluteJoint': ['active', 'anchorA', 'anchorB', 'angle', 'bodyA', 'bodyB', 'limitEnabled', 'limits', 'lowerLimit', 'maxMotorTorque', 'motorEnabled', 'motorSpeed', 'speed', 'type', 'upperLimit', 'userData', ], 'b2RevoluteJointDef': ['anchor', 'bodyA', 'bodyB', 'collideConnected', 'enableLimit', 'enableMotor', 'localAnchorA', 'localAnchorB', 'lowerAngle', 'maxMotorTorque', 'motorSpeed', 'referenceAngle', 'type', 'upperAngle', 'userData', ], 'b2RopeJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'limitState', 'maxLength', 'type', 'userData', ], 'b2RopeJointDef': ['anchorA', 'anchorB', 'bodyA', 'bodyB', 'collideConnected', 'localAnchorA', 'localAnchorB', 'maxLength', 'type', 'userData', ], 'b2Shape': ['childCount', 'radius', 'type', ], 'b2Sweep': ['a', 'a0', 'alpha0', 'c', 'c0', 'localCenter', ], 'b2TOIInput': ['proxyA', 'proxyB', 'sweepA', 'sweepB', 'tMax', ], 'b2TOIOutput': ['state', 't', ], 'b2Transform': ['R', 'angle', 'position', ], 'b2Vec2': ['length', 'lengthSquared', 'skew', 'tuple', 'valid', 'x', 'y', ], 'b2Vec3': ['length', 'lengthSquared', 'tuple', 'valid', 'x', 'y', 'z', ], 'b2Version': ['major', 'minor', 'revision', ], 'b2WeldJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'type', 'userData', ], 'b2WeldJointDef': ['anchor', 'bodyA', 'bodyB', 'collideConnected', 'localAnchorA', 'localAnchorB', 'referenceAngle', 'type', 'userData', ], 'b2World': ['autoClearForces', 'bodies', 'bodyCount', 'contactCount', 'contactFilter', 'contactListener', 'contactManager', 'contacts', 'continuousPhysics', 'destructionListener', 'gravity', 'jointCount', 'joints', 'locked', 'proxyCount', 'renderer', 'subStepping', 'warmStarting', ], 'b2WorldManifold': ['normal', 'points', ], } MAX_REPR_DEPTH = 4 MAX_REPR_STR_LEN = 250 MAX_REPR_SUB_LINES = 10 REPR_INDENT = 4 _repr_state = {} def _format_repr(obj): """ Dynamically creates the object representation string for `obj`. Attributes found in _repr_attrs[class_name] will be included. """ global _repr_state if 'spaces' not in _repr_state: _repr_state['spaces'] = 0 if 'depth' not in _repr_state: _repr_state['depth'] = 1 else: _repr_state['depth'] += 1 if _repr_state['depth'] > MAX_REPR_DEPTH: _repr_state['depth'] -= 1 return '%s(max recursion depth hit)' % (' ' * _repr_state['spaces']) class_line = '%s(' % (obj.__class__.__name__, ) orig_spaces = _repr_state['spaces'] ret = [] props = _repr_attrs.get(obj.__class__.__name__, []) try: prop_spacing = _repr_state['spaces'] + len(class_line.lstrip()) separator = '\n' + ' ' * prop_spacing for prop in props: _repr_state['spaces'] = len(prop) + 1 try: s = repr(getattr(obj, prop)) except Exception as ex: s = '(repr: %s)' % ex lines = s.split('\n') if len(lines) > MAX_REPR_SUB_LINES: length_ = 0 for i, line_ in enumerate(lines[:MAX_REPR_SUB_LINES]): length_ += len(line_) if length_ > MAX_REPR_STR_LEN: ending_delim = [] for j in s[::-1]: if j in ')]}': ending_delim.insert(0, j) else: break ret[-1] = '%s... %s' % (ret[-1], ''.join(ending_delim)) break if i == 0: ret.append('%s=%s' % (prop, line_)) else: ret.append(line_) else: ret.append('%s=%s' % (prop, lines[0].lstrip())) if len(lines) > 1: ret.extend(lines[1:]) ret[-1] += ',' finally: _repr_state['depth'] -= 1 _repr_state['spaces'] = orig_spaces if 1<= len(ret) <= 3: # Closing parenthesis on same line ret[-1] += ')' return ''.join(ret) else: # Closing parenthesis on next line ret.append(')') return '%s%s' % (class_line, separator.join(ret)) %} %define REPREXTEND(classname) %extend classname { public: long __hash__() { return (long)self; } %pythoncode %{ def __repr__(self): return _format_repr(self) %} } %enddef REPREXTEND(b2AABB); REPREXTEND(b2AssertException); REPREXTEND(b2Body); REPREXTEND(b2BodyDef); REPREXTEND(b2BroadPhase); REPREXTEND(b2ChainShape); REPREXTEND(b2CircleShape); REPREXTEND(b2ClipVertex); REPREXTEND(b2Color); REPREXTEND(b2Contact); REPREXTEND(b2ContactEdge); REPREXTEND(b2ContactFeature); REPREXTEND(b2ContactFilter); REPREXTEND(b2ContactID); REPREXTEND(b2ContactImpulse); REPREXTEND(b2ContactListener); REPREXTEND(b2ContactManager); REPREXTEND(b2ContactPoint); REPREXTEND(b2DestructionListener); REPREXTEND(b2DistanceInput); REPREXTEND(b2DistanceJoint); REPREXTEND(b2DistanceJointDef); REPREXTEND(b2DistanceOutput); REPREXTEND(b2DistanceProxy); REPREXTEND(b2Draw); REPREXTEND(b2DrawExtended); REPREXTEND(b2EdgeShape); REPREXTEND(b2Filter); REPREXTEND(b2Fixture); REPREXTEND(b2FixtureDef); REPREXTEND(b2FixtureProxy); REPREXTEND(b2FrictionJoint); REPREXTEND(b2FrictionJointDef); REPREXTEND(b2GearJoint); REPREXTEND(b2GearJointDef); REPREXTEND(b2Jacobian); REPREXTEND(b2Joint); REPREXTEND(b2JointDef); REPREXTEND(b2JointEdge); REPREXTEND(b2WheelJoint); REPREXTEND(b2WheelJointDef); REPREXTEND(b2Manifold); REPREXTEND(b2ManifoldPoint); REPREXTEND(b2MassData); REPREXTEND(b2Mat22); REPREXTEND(b2Mat33); REPREXTEND(b2MouseJoint); REPREXTEND(b2MouseJointDef); REPREXTEND(b2Pair); REPREXTEND(b2PolygonShape); REPREXTEND(b2PrismaticJoint); REPREXTEND(b2PrismaticJointDef); REPREXTEND(b2PulleyJoint); REPREXTEND(b2PulleyJointDef); REPREXTEND(b2QueryCallback); REPREXTEND(b2RayCastCallback); REPREXTEND(b2RayCastInput); REPREXTEND(b2RayCastOutput); REPREXTEND(b2RevoluteJoint); REPREXTEND(b2RevoluteJointDef); REPREXTEND(b2RopeJoint); REPREXTEND(b2RopeJointDef); REPREXTEND(b2Shape); REPREXTEND(b2Sweep); REPREXTEND(b2TOIInput); REPREXTEND(b2TOIOutput); REPREXTEND(b2Transform); REPREXTEND(b2Vec2); REPREXTEND(b2Vec3); REPREXTEND(b2Version); REPREXTEND(b2WeldJoint); REPREXTEND(b2WeldJointDef); REPREXTEND(b2World); REPREXTEND(b2WorldManifold); pybox2d-2.3.2/Box2D/Box2D_shapes.i000066400000000000000000000306021276457661000164750ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /**** Shape ****/ %extend b2Shape { public: %pythoncode %{ __eq__ = b2ShapeCompare __ne__ = lambda self,other: not b2ShapeCompare(self,other) # Read-only type = property(__GetType, None) def getAsType(self): return self @property def childCount(self): """ Get the number of child primitives. """ return self.__GetChildCount() def getAABB(self, transform, childIndex): """ Given a transform, compute the associated axis aligned bounding box for a child shape. """ if childIndex >= self.childCount: raise ValueError('Child index should be at most childCount=%d' % self.childCount) aabb=b2AABB() self.__ComputeAABB(aabb, transform, childIndex) return aabb def getMass(self, density): """ Compute the mass properties of this shape using its dimensions and density. The inertia tensor is computed about the local origin. """ m=b2MassData() self.__ComputeMass(m, density) return m %} } %ignore b2Shape::m_type; %ignore b2Shape::Clone; %rename(radius) b2Shape::m_radius; %rename(__GetChildCount) b2Shape::GetChildCount; %rename(__GetType) b2Shape::GetType; %rename(__ComputeAABB) b2Shape::ComputeAABB; %rename(__ComputeMass) b2Shape::ComputeMass; /**** CircleShape ****/ %extend b2CircleShape { public: %pythoncode %{ %} } %rename (pos) b2CircleShape::m_p; %ignore b2CircleShape::GetVertexCount; %ignore b2CircleShape::GetVertex; %ignore b2CircleShape::GetSupport; %ignore b2CircleShape::GetSupportVertex; /**** PolygonShape ****/ %extend b2PolygonShape { public: PyObject* __get_vertices() { PyObject* ret=PyList_New($self->m_count); PyObject* vertex; for (int i=0; i < $self->m_count; i++) { vertex = PyTuple_New(2); PyTuple_SetItem(vertex, 0, SWIG_From_double((float32)$self->m_vertices[i].x)); PyTuple_SetItem(vertex, 1, SWIG_From_double((float32)$self->m_vertices[i].y)); PyList_SetItem(ret, i, vertex); } return ret; } PyObject* __get_normals() { PyObject* ret=PyList_New($self->m_count); PyObject* vertex; for (int i=0; i < $self->m_count; i++) { vertex = PyTuple_New(2); PyTuple_SetItem(vertex, 0, SWIG_From_double((float32)$self->m_normals[i].x)); PyTuple_SetItem(vertex, 1, SWIG_From_double((float32)$self->m_normals[i].y)); PyList_SetItem(ret, i, vertex); } return ret; } %pythoncode %{ def __repr__(self): return "b2PolygonShape(vertices: %s)" % (self.vertices) def __clear_vertices(self): self.vertexCount=0 for i in range(0, b2_maxPolygonVertices): self.set_vertex(i, 0, 0) def __set_vertices(self, values): if not values: self.__clear_vertices() else: if len(values) < 2 or len(values) > b2_maxPolygonVertices: raise ValueError('Expected tuple or list of length >= 2 and less than b2_maxPolygonVertices=%d, got length %d.' % (b2_maxPolygonVertices, len(values))) for i,value in enumerate(values): if isinstance(value, (tuple, list, b2Vec2)): if len(value) != 2: raise ValueError('Expected tuple or list of length 2, got length %d' % len(value)) self.set_vertex(i, *value) else: raise ValueError('Expected tuple, list, or b2Vec2, got %s' % type(value)) self.vertexCount=i+1 # follow along in case of an exception to indicate valid number set self.__set_vertices_internal() # calculates normals, centroid, etc. def __iter__(self): """ Iterates over the vertices in the polygon """ for v in self.vertices: yield v def __IsValid(self): return b2CheckPolygon(self) valid = property(__IsValid, None, doc="Checks the polygon to see if it can be properly created. Raises ValueError for invalid shapes.") vertices = property(__get_vertices, __set_vertices, doc="All of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]") normals = property(__get_normals, None, doc="All of the normals as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]") box = property(None, lambda self, value: self.SetAsBox(*value), doc="Property replacement for running SetAsBox (Write-only)") %} const b2Vec2* __get_vertex(uint16 vnum) { if (vnum >= b2_maxPolygonVertices) return NULL; return &( $self->m_vertices[vnum] ); } const b2Vec2* __get_normal(uint16 vnum) { if (vnum >= b2_maxPolygonVertices) return NULL; return &( $self->m_normals[vnum] ); } void set_vertex(uint16 vnum, b2Vec2& value) { if (vnum < b2_maxPolygonVertices) $self->m_vertices[vnum].Set(value.x, value.y); } void set_vertex(uint16 vnum, float32 x, float32 y) { if (vnum < b2_maxPolygonVertices) $self->m_vertices[vnum].Set(x, y); } void __set_vertices_internal() { $self->Set($self->m_vertices, $self->m_count); } } %rename (centroid) b2PolygonShape::m_centroid; %rename (vertexCount) b2PolygonShape::m_count; %rename (__set_vertices_internal) b2PolygonShape::Set; %ignore b2PolygonShape::m_normals; %ignore b2PolygonShape::m_vertices; %ignore b2PolygonShape::GetVertex; %ignore b2PolygonShape::GetVertexCount; %ignore b2PolygonShape::vertices; %ignore b2PolygonShape::GetVertices; %ignore b2PolygonShape::GetNormals; /**** ChainShape ****/ %include "carrays.i" %array_class(b2Vec2, _b2Vec2Array); %extend b2ChainShape { public: PyObject* __get_vertices() { if (!$self->m_vertices) { Py_INCREF(Py_None); return Py_None; } PyObject* ret=PyList_New($self->m_count); PyObject* vertex; for (int i=0; i < $self->m_count; i++) { vertex = PyTuple_New(2); PyTuple_SetItem(vertex, 0, SWIG_From_double((float32)$self->m_vertices[i].x)); PyTuple_SetItem(vertex, 1, SWIG_From_double((float32)$self->m_vertices[i].y)); PyList_SetItem(ret, i, vertex); } return ret; } %pythoncode %{ def __repr__(self): return "b2ChainShape(vertices: %s)" % (self.vertices) def getChildEdge(self, index): if childIndex >= self.childCount: raise ValueError('Child index should be at most childCount=%d' % self.childCount) edge=b2EdgeShape() self.__GetChildEdge(edge, index) return edge @property def edges(self): return [self.getChildEdge(i) for i in range(self.childCount)] @property def vertexCount(self): return self.__get_count() def __get_vertices(self): """Returns all of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" return [ (self.__get_vertex(i).x, self.__get_vertex(i).y ) for i in range(0, self.vertexCount)] def __iter__(self): """ Iterates over the vertices in the Chain """ for v in self.vertices: yield v def __set_vertices(self, values, loop=True): if not values or not isinstance(values, (list, tuple)) or (len(values) < 2): raise ValueError('Expected tuple or list of length >= 2.') for i,value in enumerate(values): if isinstance(value, (tuple, list)): if len(value) != 2: raise ValueError('Expected tuple or list of length 2, got length %d' % len(value)) for j in value: if not isinstance(j, (int, float)): raise ValueError('Expected int or float values, got %s' % (type(j))) elif isinstance(value, b2Vec2): pass else: raise ValueError('Expected tuple, list, or b2Vec2, got %s' % type(value)) vecs=_b2Vec2Array(len(values)) for i, value in enumerate(values): if isinstance(value, b2Vec2): vecs[i]=value else: vecs[i]=b2Vec2(value) self.__create(vecs, len(values), loop) vertices = property(__get_vertices, __set_vertices) vertices_chain = property(__get_vertices, lambda self, v : self.__set_vertices(v, loop=False)) vertices_loop = vertices %} void __create(_b2Vec2Array* v, int c, bool loop) { if (v) { if (loop) $self->CreateLoop(v, c); else $self->CreateChain(v, c); } } const b2Vec2* __get_vertex(uint16 vnum) { if (vnum >= $self->m_count) return NULL; return &($self->m_vertices[vnum]); } int32 __get_count() { return $self->m_count; } } %rename (__GetVertices) b2ChainShape::GetVertices; %rename (__GetChildEdge) b2ChainShape::GetChildEdge; %ignore b2ChainShape::m_vertices; %ignore b2ChainShape::m_count; %ignore b2ChainShape::Create; /**** EdgeShape ****/ %extend b2EdgeShape { public: %pythoncode %{ def __repr__(self): return "b2EdgeShape(vertices: %s)" % (self.vertices) @property def all_vertices(self): """Returns all of the vertices as a list of tuples [ (x0,y0), (x1,y1), (x2,y2) (x3,y3) ] Note that the validity of vertices 0 and 4 depend on whether or not hasVertex0 and hasVertex3 are set. """ return [tuple(self.vertex0), tuple(self.vertex1), tuple(self.vertex2), tuple(self.vertex3)] def __get_vertices(self): """Returns the basic vertices as a list of tuples [ (x1,y1), (x2,y2) ] To include the supporting vertices, see 'all_vertices' If you want to set vertex3 but not vertex0, pass in None for vertex0. """ return [tuple(self.vertex1), tuple(self.vertex2)] def __set_vertices(self, vertices): if len(vertices)==2: self.vertex1, self.vertex2=vertices self.hasVertex0=False self.hasVertex3=False elif len(vertices)==3: self.vertex0, self.vertex1, self.vertex2=vertices self.hasVertex0=(vertices[0] != None) self.hasVertex3=False elif len(vertices)==4: self.vertex0, self.vertex1, self.vertex2, self.vertex3=vertices self.hasVertex0=(vertices[0] != None) self.hasVertex3=True else: raise ValueError('Expected from 2 to 4 vertices.') @property def vertexCount(self): """ Returns the number of valid vertices (as in, it counts whether or not hasVertex0 or hasVertex3 are set) """ if self.hasVertex0 and self.hasVertex3: return 4 elif self.hasVertex0 or self.hasVertex3: return 3 else: return 2 def __iter__(self): """ Iterates over the vertices in the Edge """ for v in self.vertices: yield v vertices=property(__get_vertices, __set_vertices) %} } %rename(radius) b2EdgeShape::m_radius; %rename(vertex0) b2EdgeShape::m_vertex0; %rename(vertex1) b2EdgeShape::m_vertex1; %rename(vertex2) b2EdgeShape::m_vertex2; %rename(vertex3) b2EdgeShape::m_vertex3; %rename(hasVertex0) b2EdgeShape::m_hasVertex0; %rename(hasVertex3) b2EdgeShape::m_hasVertex3; %rename(__Set) b2EdgeShape::Set; pybox2d-2.3.2/Box2D/Box2D_typemaps.i000066400000000000000000000341341276457661000170600ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %inline %{ #define pybox2d_float_from_sequence(_sequence, _num, _dest, _err_msg) \ { \ PyObject* item=PySequence_GetItem(_sequence, _num); \ int res=SWIG_AsVal_float(item, _dest); \ Py_XDECREF(item); \ if (!SWIG_IsOK(res)) { \ PyErr_SetString(PyExc_TypeError,_err_msg); \ SWIG_fail; \ } \ } %} //input - $input -> ($1_type) $1 $1_descriptor %typemap(in) b2Vec2* self { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $descriptor(b2Vec2*), 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); } } %typemap(in) b2Vec3* self { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $descriptor(b2Vec3*), 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); } } %typemap(in) b2Color* self { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $descriptor(b2Color*), 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); } } //Resolve ambiguities in overloaded functions when you pass a tuple or list when //SWIG expects a b2Vec2 (b2Vec3, b2Color) %typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER) b2Vec2*,b2Vec2& { $1 = (PySequence_Check($input) || SWIG_CheckState(SWIG_ConvertPtr($input, 0, $descriptor(b2Vec2*), 0)) ) ? 1 : 0; } %typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER) b2Vec3*,b2Vec3& { $1 = (PySequence_Check($input) || SWIG_CheckState(SWIG_ConvertPtr($input, 0, $descriptor(b2Vec3*), 0)) ) ? 1 : 0; } %typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER) b2Color*,b2Color& { $1 = (PySequence_Check($input) || SWIG_CheckState(SWIG_ConvertPtr($input, 0, $descriptor(b2Color*), 0)) ) ? 1 : 0; } // Allow b2Vec2* arguments be passed in as tuples or lists %typemap(in) b2Vec2* (b2Vec2 temp) { if (PySequence_Check($input)) { if (PySequence_Size($input) != 2) { PyErr_Format(PyExc_TypeError, "Expected tuple or list of length 2, got length %ld", (long) PySequence_Size($input)); SWIG_fail; } pybox2d_float_from_sequence($input, 0, &temp.x, "Converting from sequence to b2Vec2, expected int/float arguments index 0"); pybox2d_float_from_sequence($input, 1, &temp.y, "Converting from sequence to b2Vec2, expected int/float arguments index 1"); } else if ($input==Py_None) { temp.Set(0.0f,0.0f); } else { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $1_descriptor, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); SWIG_fail; } temp =(b2Vec2&) *$1; } $1 = &temp; } // Allow b2Color* arguments be passed in as tuples or lists %typemap(in) b2Color* (b2Color temp) { //input - $input -> ($1_type) $1 $1_descriptor if (PySequence_Check($input)) { if (PySequence_Size($input) != 3) { PyErr_Format(PyExc_TypeError, "Expected tuple or list of length 3, got length %ld", (long) PySequence_Size($input)); SWIG_fail; } pybox2d_float_from_sequence($input, 0, &temp.r, "Converting from sequence to b2Color, expected int/float arguments index 0"); pybox2d_float_from_sequence($input, 1, &temp.g, "Converting from sequence to b2Color, expected int/float arguments index 1"); pybox2d_float_from_sequence($input, 2, &temp.b, "Converting from sequence to b2Color, expected int/float arguments index 2"); } else if ($input==Py_None) { temp.Set(0.0f,0.0f,0.0f); } else { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $1_descriptor, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); SWIG_fail; } temp =(b2Color&) *$1; } $1 = &temp; } // Allow b2Vec3* arguments be passed in as tuples or lists %typemap(in) b2Vec3* (b2Vec3 temp) { //input - $input -> ($1_type) $1 $1_descriptor if (PySequence_Check($input)) { if (PySequence_Size($input) != 3) { PyErr_Format(PyExc_TypeError, "Expected tuple or list of length 3, got length %ld", (long) PySequence_Size($input)); SWIG_fail; } pybox2d_float_from_sequence($input, 0, &temp.x, "Converting from sequence to b2Vec3, expected int/float arguments index 0"); pybox2d_float_from_sequence($input, 1, &temp.y, "Converting from sequence to b2Vec3, expected int/float arguments index 1"); pybox2d_float_from_sequence($input, 2, &temp.z, "Converting from sequence to b2Vec3, expected int/float arguments index 2"); } else if ($input==Py_None) { temp.Set(0.0f,0.0f,0.0f); } else { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $1_descriptor, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); SWIG_fail; } temp =(b2Vec3&) *$1; } $1 = &temp; } // Allow b2Vec2& arguments be passed in as tuples or lists %typemap(in) b2Vec2& (b2Vec2 temp) { //input - $input -> ($1_type) $1 $1_descriptor if (PySequence_Check($input)) { if (PySequence_Size($input) != 2) { PyErr_Format(PyExc_TypeError, "Expected tuple or list of length 2, got length %ld", (long) PySequence_Size($input)); SWIG_fail; } pybox2d_float_from_sequence($input, 0, &temp.x, "Converting from sequence to b2Vec2, expected int/float arguments index 0"); pybox2d_float_from_sequence($input, 1, &temp.y, "Converting from sequence to b2Vec2, expected int/float arguments index 1"); } else if ($input == Py_None) { temp.Set(0.0f,0.0f); } else { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $1_descriptor, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); } temp =(b2Vec2&) *$1; } $1 = &temp; } // Allow b2Color& arguments be passed in as tuples or lists %typemap(in) b2Color& (b2Color temp) { //input - $input -> ($1_type) $1 $1_descriptor if (PySequence_Check($input)) { if (PySequence_Size($input) != 3) { PyErr_Format(PyExc_TypeError, "Expected tuple or list of length 3, got length %ld", (long) PySequence_Size($input)); SWIG_fail; } pybox2d_float_from_sequence($input, 0, &temp.r, "Converting from sequence to b2Color, expected int/float arguments index 0"); pybox2d_float_from_sequence($input, 1, &temp.g, "Converting from sequence to b2Color, expected int/float arguments index 1"); pybox2d_float_from_sequence($input, 2, &temp.b, "Converting from sequence to b2Color, expected int/float arguments index 2"); } else if ($input==Py_None) { temp.Set(0.0f,0.0f,0.0f); } else { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $1_descriptor, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); SWIG_fail; } temp =(b2Color&) *$1; } $1 = &temp; } // Allow b2Vec3& arguments be passed in as tuples or lists %typemap(in) b2Vec3& (b2Vec3 temp) { //input - $input -> ($1_type) $1 $1_descriptor if (PySequence_Check($input)) { if (PySequence_Size($input) != 3) { PyErr_Format(PyExc_TypeError, "Expected tuple or list of length 3, got length %ld", (long) PySequence_Size($input)); SWIG_fail; } pybox2d_float_from_sequence($input, 0, &temp.x, "Converting from sequence to b2Vec3, expected int/float arguments index 0"); pybox2d_float_from_sequence($input, 1, &temp.y, "Converting from sequence to b2Vec3, expected int/float arguments index 1"); pybox2d_float_from_sequence($input, 2, &temp.z, "Converting from sequence to b2Vec3, expected int/float arguments index 2"); } else if ($input==Py_None) { temp.Set(0.0f,0.0f,0.0f); } else { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $1_descriptor, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); SWIG_fail; } temp =(b2Vec3&) *$1; } $1 = &temp; } //Allow access to void* types %typemap(in) void* { $1 = $input; Py_INCREF((PyObject*)$1); } %typemap(out) void* { if (!$1) $result=Py_None; else $result=(PyObject*)$1; Py_INCREF($result); } %typemap(in) b2Manifold* oldManifold{ void* argp=NULL; int res3 = SWIG_ConvertPtr($input, &argp, $descriptor(b2Manifold *), 0); Swig::Director *director = SWIG_DIRECTOR_CAST(arg1); #ifdef _SWIG_KWARGS bool upcall_ = (director && (director->swig_get_self()==obj0)); #else bool upcall_ = (director && (director->swig_get_self()==swig_obj[0])); #endif if (upcall_) { /* This conversion fails on py3k when attempting to call the b2_defaultListener.PreSolve() and I cannot quite figure out why. I think it has something to do with the fact that the default implementation is in C++, the director method gets called, then it attempts to call a nonexistent Python function, ... or something like that. In any case, the base b2ContactListener does nothing, so whatever args we pass it, that's fine. TODO */ } else if (!SWIG_IsOK(res3)) { SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); } $1 = reinterpret_cast(argp); } %typemap(directorin) (const b2Vec2* vertices, int32 vertexCount) { $input = PyTuple_New(vertexCount); PyObject* vertex; for (int i=0; i < vertexCount; i++) { vertex = PyTuple_New(2); PyTuple_SetItem(vertex, 0, SWIG_From_double((float32)vertices[i].x)); PyTuple_SetItem(vertex, 1, SWIG_From_double((float32)vertices[i].y)); PyTuple_SetItem($input, i, vertex); } } %typemap(directorin) b2Vec2& { $input = PyTuple_New(2); PyTuple_SetItem( $input, 0, SWIG_From_double((float32)$1_name.x)); PyTuple_SetItem( $input, 1, SWIG_From_double((float32)$1_name.y)); } /* Properly downcast joints for all return values using b2Joint */ %typemap(out) b2Joint* { if ($1) { switch (($1)->GetType()) { case e_revoluteJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2RevoluteJoint*), 0); break; case e_prismaticJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2PrismaticJoint*), 0); break; case e_distanceJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2DistanceJoint*), 0); break; case e_pulleyJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2PulleyJoint*), 0); break; case e_mouseJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2MouseJoint*), 0); break; case e_gearJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2GearJoint*), 0); break; case e_wheelJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2WheelJoint*), 0); break; case e_weldJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2WeldJoint*), 0); break; case e_frictionJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2FrictionJoint*), 0); break; case e_ropeJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2RopeJoint*), 0); break; case e_motorJoint: $result=SWIG_NewPointerObj($1, $descriptor(b2MotorJoint*), 0); break; case e_unknownJoint: default: $result=SWIG_NewPointerObj($1, $descriptor(b2Joint*), 0); break; break; } } else { $result=Py_None; Py_INCREF($result); } } /* Properly downcast shapes for all return values using b2Shape */ %typemap(out) b2Shape* { if ($1) { switch (($1)->GetType()) { case b2Shape::e_circle: $result=SWIG_NewPointerObj($1, $descriptor(b2CircleShape*), 0); break; case b2Shape::e_polygon: $result=SWIG_NewPointerObj($1, $descriptor(b2PolygonShape*), 0); break; case b2Shape::e_edge: $result=SWIG_NewPointerObj($1, $descriptor(b2EdgeShape*), 0); break; case b2Shape::e_chain: $result=SWIG_NewPointerObj($1, $descriptor(b2ChainShape*), 0); break; default: $result=SWIG_NewPointerObj($1, $descriptor(b2Shape*), 0); break; } } else { $result=Py_None; Py_INCREF($result); } } pybox2d-2.3.2/Box2D/Box2D_userdata.i000066400000000000000000000150001276457661000170150ustar00rootroot00000000000000/* * Python SWIG interface file for Box2D (www.box2d.org) * * Copyright (c) 2008 kne / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /* Note: Given that we have a definition (b2BodyDef) that takes the userData, then passes it onto the factory output (b2Body) upon creation, it's necessary to intercept the CreateBody/Joint/Shape functions to increase the refcount for each of those functions. And upon being destroyed, the userData refcount must be decreased. */ %extend b2World { public: b2Body* __CreateBody(b2BodyDef* defn) { b2Body* ret; if (defn) Py_XINCREF((PyObject*)defn->userData); ret=self->CreateBody(defn); return ret; } b2Joint* __CreateJoint(b2JointDef* defn) { if (defn) Py_XINCREF((PyObject*)defn->userData); return self->CreateJoint(defn); } void DestroyBody(b2Body* body) { Py_XDECREF((PyObject*)body->GetUserData()); self->DestroyBody(body); } void DestroyJoint(b2Joint* joint) { Py_XDECREF((PyObject*)joint->GetUserData()); self->DestroyJoint(joint); } } %extend b2Body { public: void DestroyFixture(b2Fixture* fixture) { Py_XDECREF((PyObject*)fixture->GetUserData()); self->DestroyFixture(fixture); } b2Fixture* __CreateFixture(b2FixtureDef* defn) { b2Fixture* ret; if (defn) Py_XINCREF((PyObject*)defn->userData); ret=self->CreateFixture(defn); return ret; } PyObject* __GetUserData() { PyObject* ret=(PyObject*)self->GetUserData(); if (!ret) ret=Py_None; Py_XINCREF(ret); return ret; } void __SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->GetUserData()); Py_INCREF(data); self->SetUserData(data); } void ClearUserData() { Py_XDECREF((PyObject*)self->GetUserData()); self->SetUserData(NULL); } %pythoncode %{ userData = property(__GetUserData, __SetUserData) %} } %extend b2Joint { public: PyObject* __GetUserData() { PyObject* ret=(PyObject*)self->GetUserData(); if (!ret) ret=Py_None; Py_XINCREF(ret); return ret; } void __SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->GetUserData()); Py_INCREF(data); self->SetUserData(data); } void ClearUserData() { Py_XDECREF((PyObject*)self->GetUserData()); self->SetUserData(NULL); } %pythoncode %{ userData = property(__GetUserData, __SetUserData) %} } %extend b2Fixture { public: PyObject* __GetUserData() { PyObject* ret=(PyObject*)self->GetUserData(); if (!ret) ret=Py_None; Py_XINCREF(ret); return ret; } void __SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->GetUserData()); Py_INCREF(data); self->SetUserData(data); } void ClearUserData() { Py_XDECREF((PyObject*)self->GetUserData()); self->SetUserData(NULL); } %pythoncode %{ userData = property(__GetUserData, __SetUserData) %} } //Allow access to userData in definitions, with proper destruction %extend b2JointDef { public: PyObject* __GetUserData() { PyObject* ret; if (!self->userData) ret=Py_None; else ret=(PyObject*)self->userData; Py_INCREF((PyObject*)ret); return ret; } void __SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->userData); Py_INCREF(data); self->userData=(void*)data; } void ClearUserData() { Py_XDECREF((PyObject*)self->userData); self->userData=NULL; } %pythoncode %{ userData = property(__GetUserData, __SetUserData) def __del__(self): self.ClearUserData() %} } %extend b2BodyDef { public: PyObject* __GetUserData() { PyObject* ret; if (!self->userData) ret=Py_None; else ret=(PyObject*)self->userData; Py_INCREF((PyObject*)ret); return ret; } void __SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->userData); Py_INCREF(data); self->userData=(void*)data; } void ClearUserData() { Py_XDECREF((PyObject*)self->userData); self->userData=NULL; } %pythoncode %{ userData = property(__GetUserData, __SetUserData) def __del__(self): self.ClearUserData() %} } %extend b2FixtureDef { public: PyObject* __GetUserData() { PyObject* ret; if (!self->userData) ret=Py_None; else ret=(PyObject*)self->userData; Py_INCREF((PyObject*)ret); return ret; } void __SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->userData); Py_INCREF(data); self->userData=(void*)data; } void ClearUserData() { Py_XDECREF((PyObject*)self->userData); self->userData=NULL; } %pythoncode %{ userData = property(__GetUserData, __SetUserData) def __del__(self): self.ClearUserData() %} } // These renames are intentionally below the above CreateBody, as they will rename the // original C++ versions and not the ones I have written. %ignore SetUserData; %ignore GetUserData; %ignore userData; %newobject b2World::__CreateBody; %newobject b2World::__CreateJoint; %newobject b2Body::__CreateFixture; %rename (__CreateFixture) b2Body::CreateFixture(const b2Shape* shape, float32 density); %ignore b2World::CreateBody; %ignore b2World::CreateJoint; %ignore b2Body::CreateFixture; %ignore b2World::DestroyBody; %ignore b2World::DestroyJoint; %ignore b2Body::DestroyFixture; pybox2d-2.3.2/Box2D/Box2D_world.i000066400000000000000000000416051276457661000163460ustar00rootroot00000000000000/* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ // i /really/ did not understand kwargs, apparently... %feature("shadow") b2World::b2World(const b2Vec2& gravity) { def __init__(self, gravity=(0, -10), doSleep=True, **kwargs): """__init__(self, gravity=(0, -10), doSleep=True, **kwargs) -> b2World Additional kwargs like contactListener will be passed after the world is created. Examples: b2World(gravity=(0,-10), doSleep=True) b2World(contactListener=myListener) """ _Box2D.b2World_swiginit(self,_Box2D.new_b2World(gravity)) self.allowSleeping = doSleep for key, value in kwargs.items(): try: setattr(self, key, value) except Exception as ex: raise ex.__class__('Failed on kwargs, class="%s" key="%s": %s' \ % (self.__class__.__name__, key, ex)) } %extend b2World { public: %pythoncode %{ def __iter__(self): """ Iterates over the bodies in the world """ for body in self.bodies: yield body def CreateDynamicBody(self, **kwargs): """ Create a single dynamic body in the world. Accepts only kwargs to a b2BodyDef. For more information, see CreateBody and b2BodyDef. """ kwargs['type'] = b2_dynamicBody return self.CreateBody(**kwargs) def CreateKinematicBody(self, **kwargs): """ Create a single kinematic body in the world. Accepts only kwargs to a b2BodyDef. For more information, see CreateBody and b2BodyDef. """ kwargs['type'] = b2_kinematicBody return self.CreateBody(**kwargs) def CreateStaticBody(self, **kwargs): """ Create a single static body in the world. Accepts only kwargs to a b2BodyDef. For more information, see CreateBody and b2BodyDef. """ kwargs['type'] = b2_staticBody return self.CreateBody(**kwargs) def CreateBody(self, defn=None, **kwargs): """ Create a body in the world. Takes a single b2BodyDef argument, or kwargs to pass to a temporary b2BodyDef. world.CreateBody(position=(1,2), angle=1) is short for: world.CreateBody(b2BodyDef(position=(1,2), angle=1)) If the definition (or kwargs) sets 'fixtures', they will be created on the newly created body. A single fixture is also accepted. CreateBody(..., fixtures=[]) This is short for: body = CreateBody(...) for fixture in []: body.CreateFixture(fixture) 'shapes' and 'shapeFixture' are also accepted: CreateBody(..., shapes=[], shapeFixture=b2FixtureDef()) This is short for: body = CreateBody(...) body.CreateFixturesFromShapes(shapes=[], shapeFixture=b2FixtureDef()) """ if defn is not None: if not isinstance(defn, b2BodyDef): raise TypeError('Expected b2BodyDef') else: defn = b2BodyDef(**kwargs) body=self.__CreateBody(defn) if defn.fixtures: if isinstance(defn.fixtures, (list, tuple)): for fixture in defn.fixtures: body.CreateFixture(fixture) else: body.CreateFixture(defn.fixtures) if defn.shapes: body.CreateFixturesFromShapes(shapes=defn.shapes, shapeFixture=defn.shapeFixture) if 'massData' in kwargs: body.massData=kwargs['massData'] if 'localCenter' in kwargs: body.localCenter=kwargs['localCenter'] if 'inertia' in kwargs: body.inertia=kwargs['inertia'] if 'mass' in kwargs: body.mass=kwargs['mass'] return body def CreateDistanceJoint(self, **kwargs): """ Create a single b2DistanceJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2DistanceJointDef(**kwargs)) def CreateRopeJoint(self, **kwargs): """ Create a single b2RopeJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2RopeJointDef(**kwargs)) def CreateFrictionJoint(self, **kwargs): """ Create a single b2FrictionJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2FrictionJointDef(**kwargs)) def CreateGearJoint(self, **kwargs): """ Create a single b2GearJoint. Only accepts kwargs to the joint definition. Raises ValueError if either joint1 or joint2 is left unset. """ if 'joint1' not in kwargs or 'joint2' not in kwargs: raise ValueError('Gear joint requires that both joint1 and joint2 be set') return self.__CreateJoint(b2GearJointDef(**kwargs)) def CreateWheelJoint(self, **kwargs): """ Create a single b2WheelJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2WheelJointDef(**kwargs)) def CreateMouseJoint(self, **kwargs): """ Create a single b2MouseJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2MouseJointDef(**kwargs)) def CreatePrismaticJoint(self, **kwargs): """ Create a single b2PrismaticJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2PrismaticJointDef(**kwargs)) def CreatePulleyJoint(self, **kwargs): """ Create a single b2PulleyJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2PulleyJointDef(**kwargs)) def CreateRevoluteJoint(self, **kwargs): """ Create a single b2RevoluteJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2RevoluteJointDef(**kwargs)) def CreateWeldJoint(self, **kwargs): """ Create a single b2WeldJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2WeldJointDef(**kwargs)) def CreateMotorJoint(self, **kwargs): """ Create a single b2MotorJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2MotorJointDef(**kwargs)) def CreateJoint(self, defn=None, type=None, **kwargs): """ Create a joint in the world. Takes a single b2JointDef argument, or kwargs to pass to a temporary b2JointDef. All of these are exactly equivalent: world.CreateJoint(type=b2RevoluteJoint, bodyA=body, bodyB=body2) world.CreateJoint(type=b2RevoluteJointDef, bodyA=body, bodyB=body2) world.CreateJoint(b2RevoluteJointDef(bodyA=body, bodyB=body2)) """ if defn is not None: if not isinstance(defn, b2JointDef): raise TypeError('Expected b2JointDef') if defn.bodyA is None or defn.bodyB is None: raise ValueError('bodyA and bodyB must be set') else: if type is not None: if issubclass(type, b2JointDef): class_type = type elif issubclass(type, b2Joint): # a b2Joint passed in, so get the b2JointDef class_type = globals()[type.__name__ + 'Def'] else: raise TypeError('Expected "type" to be a b2Joint or b2JointDef') else: raise TypeError('Expected "type" to be a b2Joint or b2JointDef') defn = class_type(**kwargs) if isinstance(defn, b2GearJointDef): if not defn.joint1 or not defn.joint2: raise ValueError('Gear joint requires that both joint1 and joint2 be set') else: if not defn.bodyA or not defn.bodyB: raise ValueError('Body or bodies not set (bodyA, bodyB)') return self.__CreateJoint(defn) # The logic behind these functions is that they increase the refcount # of the listeners as you set them, so it is no longer necessary to keep # a copy on your own. Upon destruction of the object, it should be cleared # also clearing the refcount of the function. # Now using it also to buffer previously write-only values in the shadowed # class to make them read-write. def __GetData(self, name): if name in list(self.__data.keys()): return self.__data[name] else: return None def __SetData(self, name, value, fcn): self.__data[name] = value fcn(value) # Read-write properties gravity = property(__GetGravity, __SetGravity) autoClearForces = property(__GetAutoClearForces, __SetAutoClearForces) __data = {} # holds the listeners so they can be properly destroyed, and buffer other data destructionListener = property(lambda self: self.__GetData('destruction'), lambda self, fcn: self.__SetData('destruction', fcn, self.__SetDestructionListener_internal)) contactListener= property(lambda self: self.__GetData('contact'), lambda self, fcn: self.__SetData('contact', fcn, self.__SetContactListener_internal)) contactFilter= property(lambda self: self.__GetData('contactfilter'), lambda self, fcn: self.__SetData('contactfilter', fcn, self.__SetContactFilter_internal)) renderer= property(lambda self: self.__GetData('renderer'), lambda self, fcn: self.__SetData('renderer', fcn, self.__SetDebugDraw_internal)) continuousPhysics = property(__GetContinuousPhysics, __SetContinuousPhysics) warmStarting = property(__GetWarmStarting, __SetWarmStarting) subStepping = property(__GetSubStepping, __SetSubStepping) # Read-only contactManager= property(__GetContactManager, None) contactCount = property(__GetContactCount, None) bodyCount = property(__GetBodyCount, None) jointCount = property(__GetJointCount, None) proxyCount = property(__GetProxyCount, None) joints = property(lambda self: _list_from_linked_list(self.__GetJointList_internal()), None, doc="""All joints in the world. NOTE: This re-creates the list on every call. See also joints_gen.""") bodies = property(lambda self: _list_from_linked_list(self.__GetBodyList_internal()), None, doc="""All bodies in the world. NOTE: This re-creates the list on every call. See also bodies_gen.""") contacts= property(lambda self: _list_from_linked_list(self.__GetContactList_internal()), None, doc="""All contacts in the world. NOTE: This re-creates the list on every call. See also contacts_gen.""") joints_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetJointList_internal())), None, doc="""Indexable generator of the connected joints to this body. NOTE: When not using the whole list, this may be preferable to using 'joints'.""") bodies_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetBodyList_internal())), None, doc="""Indexable generator of all bodies. NOTE: When not using the whole list, this may be preferable to using 'bodies'.""") contacts_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetContactList_internal())), None, doc="""Indexable generator of all contacts. NOTE: When not using the whole list, this may be preferable to using 'contacts'.""") locked = property(__IsLocked, None) %} } %rename (__GetGravity) b2World::GetGravity; %rename (__SetGravity) b2World::SetGravity; %rename (__GetJointList_internal) b2World::GetJointList; %rename (__GetJointCount) b2World::GetJointCount; %rename (__GetBodyList_internal) b2World::GetBodyList; %rename (__GetContactList_internal) b2World::GetContactList; %rename (__SetDestructionListener_internal) b2World::SetDestructionListener; %rename (__SetContactFilter_internal) b2World::SetContactFilter; %rename (__SetContactListener_internal) b2World::SetContactListener; %rename (__SetDebugDraw_internal) b2World::SetDebugDraw; %rename (__GetContactCount) b2World::GetContactCount; %rename (__GetProxyCount) b2World::GetProxyCount; %rename (__GetBodyCount) b2World::GetBodyCount; %rename (__IsLocked) b2World::IsLocked; %rename (__SetContinuousPhysics_internal) b2World::SetContinuousPhysics; %rename (__SetWarmStarting_internal) b2World::SetWarmStarting; %rename (__SetSubStepping_internal) b2World::SetSubStepping; %rename (__SetAutoClearForces) b2World::SetAutoClearForces; %rename (__GetAutoClearForces) b2World::GetAutoClearForces; %rename (__GetContactManager) b2World::GetContactManager; %rename (__GetContinuousPhysics) b2World::GetContinuousPhysics; %rename (__SetContinuousPhysics) b2World::SetContinuousPhysics; %rename (__GetWarmStarting) b2World::GetWarmStarting; %rename (__SetWarmStarting) b2World::SetWarmStarting; %rename (__GetSubStepping) b2World::GetSubStepping; %rename (__SetSubStepping) b2World::SetSubStepping; pybox2d-2.3.2/Box2D/Collision/000077500000000000000000000000001276457661000157745ustar00rootroot00000000000000pybox2d-2.3.2/Box2D/Collision/Shapes/000077500000000000000000000000001276457661000172175ustar00rootroot00000000000000pybox2d-2.3.2/Box2D/Collision/Shapes/b2ChainShape.cpp000066400000000000000000000113701276457661000221540ustar00rootroot00000000000000/* * Copyright (c) 2006-2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include using namespace std; b2ChainShape::~b2ChainShape() { b2Free(m_vertices); m_vertices = NULL; m_count = 0; } void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count) { b2Assert(m_vertices == NULL && m_count == 0); b2Assert(count >= 3); for (int32 i = 1; i < count; ++i) { b2Vec2 v1 = vertices[i-1]; b2Vec2 v2 = vertices[i]; // If the code crashes here, it means your vertices are too close together. b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop); } m_count = count + 1; m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2)); memcpy(m_vertices, vertices, count * sizeof(b2Vec2)); m_vertices[count] = m_vertices[0]; m_prevVertex = m_vertices[m_count - 2]; m_nextVertex = m_vertices[1]; m_hasPrevVertex = true; m_hasNextVertex = true; } void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count) { b2Assert(m_vertices == NULL && m_count == 0); b2Assert(count >= 2); for (int32 i = 1; i < count; ++i) { b2Vec2 v1 = vertices[i-1]; b2Vec2 v2 = vertices[i]; // If the code crashes here, it means your vertices are too close together. b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop); } m_count = count; m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2)); memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2)); m_hasPrevVertex = false; m_hasNextVertex = false; } void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex) { m_prevVertex = prevVertex; m_hasPrevVertex = true; } void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex) { m_nextVertex = nextVertex; m_hasNextVertex = true; } b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const { void* mem = allocator->Allocate(sizeof(b2ChainShape)); b2ChainShape* clone = new (mem) b2ChainShape; clone->CreateChain(m_vertices, m_count); clone->m_prevVertex = m_prevVertex; clone->m_nextVertex = m_nextVertex; clone->m_hasPrevVertex = m_hasPrevVertex; clone->m_hasNextVertex = m_hasNextVertex; return clone; } int32 b2ChainShape::GetChildCount() const { // edge count = vertex count - 1 return m_count - 1; } void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const { b2Assert(0 <= index && index < m_count - 1); edge->m_type = b2Shape::e_edge; edge->m_radius = m_radius; edge->m_vertex1 = m_vertices[index + 0]; edge->m_vertex2 = m_vertices[index + 1]; if (index > 0) { edge->m_vertex0 = m_vertices[index - 1]; edge->m_hasVertex0 = true; } else { edge->m_vertex0 = m_prevVertex; edge->m_hasVertex0 = m_hasPrevVertex; } if (index < m_count - 2) { edge->m_vertex3 = m_vertices[index + 2]; edge->m_hasVertex3 = true; } else { edge->m_vertex3 = m_nextVertex; edge->m_hasVertex3 = m_hasNextVertex; } } bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const { B2_NOT_USED(xf); B2_NOT_USED(p); return false; } bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& xf, int32 childIndex) const { b2Assert(childIndex < m_count); b2EdgeShape edgeShape; int32 i1 = childIndex; int32 i2 = childIndex + 1; if (i2 == m_count) { i2 = 0; } edgeShape.m_vertex1 = m_vertices[i1]; edgeShape.m_vertex2 = m_vertices[i2]; return edgeShape.RayCast(output, input, xf, 0); } void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const { b2Assert(childIndex < m_count); int32 i1 = childIndex; int32 i2 = childIndex + 1; if (i2 == m_count) { i2 = 0; } b2Vec2 v1 = b2Mul(xf, m_vertices[i1]); b2Vec2 v2 = b2Mul(xf, m_vertices[i2]); aabb->lowerBound = b2Min(v1, v2); aabb->upperBound = b2Max(v1, v2); } void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const { B2_NOT_USED(density); massData->mass = 0.0f; massData->center.SetZero(); massData->I = 0.0f; } pybox2d-2.3.2/Box2D/Collision/Shapes/b2ChainShape.h000066400000000000000000000065401276457661000216240ustar00rootroot00000000000000/* * Copyright (c) 2006-2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CHAIN_SHAPE_H #define B2_CHAIN_SHAPE_H #include class b2EdgeShape; /// A chain shape is a free form sequence of line segments. /// The chain has two-sided collision, so you can use inside and outside collision. /// Therefore, you may use any winding order. /// Since there may be many vertices, they are allocated using b2Alloc. /// Connectivity information is used to create smooth collisions. /// WARNING: The chain will not collide properly if there are self-intersections. class b2ChainShape : public b2Shape { public: b2ChainShape(); /// The destructor frees the vertices using b2Free. ~b2ChainShape(); /// Create a loop. This automatically adjusts connectivity. /// @param vertices an array of vertices, these are copied /// @param count the vertex count void CreateLoop(const b2Vec2* vertices, int32 count); /// Create a chain with isolated end vertices. /// @param vertices an array of vertices, these are copied /// @param count the vertex count void CreateChain(const b2Vec2* vertices, int32 count); /// Establish connectivity to a vertex that precedes the first vertex. /// Don't call this for loops. void SetPrevVertex(const b2Vec2& prevVertex); /// Establish connectivity to a vertex that follows the last vertex. /// Don't call this for loops. void SetNextVertex(const b2Vec2& nextVertex); /// Implement b2Shape. Vertices are cloned using b2Alloc. b2Shape* Clone(b2BlockAllocator* allocator) const; /// @see b2Shape::GetChildCount int32 GetChildCount() const; /// Get a child edge. void GetChildEdge(b2EdgeShape* edge, int32 index) const; /// This always return false. /// @see b2Shape::TestPoint bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; /// Implement b2Shape. bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform, int32 childIndex) const; /// @see b2Shape::ComputeAABB void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; /// Chains have zero mass. /// @see b2Shape::ComputeMass void ComputeMass(b2MassData* massData, float32 density) const; /// The vertices. Owned by this class. b2Vec2* m_vertices; /// The vertex count. int32 m_count; b2Vec2 m_prevVertex, m_nextVertex; bool m_hasPrevVertex, m_hasNextVertex; }; inline b2ChainShape::b2ChainShape() { m_type = e_chain; m_radius = b2_polygonRadius; m_vertices = NULL; m_count = 0; m_hasPrevVertex = false; m_hasNextVertex = false; } #endif pybox2d-2.3.2/Box2D/Collision/Shapes/b2CircleShape.cpp000066400000000000000000000060071276457661000223340ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include using namespace std; b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const { void* mem = allocator->Allocate(sizeof(b2CircleShape)); b2CircleShape* clone = new (mem) b2CircleShape; *clone = *this; return clone; } int32 b2CircleShape::GetChildCount() const { return 1; } bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const { b2Vec2 center = transform.p + b2Mul(transform.q, m_p); b2Vec2 d = p - center; return b2Dot(d, d) <= m_radius * m_radius; } // Collision Detection in Interactive 3D Environments by Gino van den Bergen // From Section 3.1.2 // x = s + a * r // norm(x) = radius bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform, int32 childIndex) const { B2_NOT_USED(childIndex); b2Vec2 position = transform.p + b2Mul(transform.q, m_p); b2Vec2 s = input.p1 - position; float32 b = b2Dot(s, s) - m_radius * m_radius; // Solve quadratic equation. b2Vec2 r = input.p2 - input.p1; float32 c = b2Dot(s, r); float32 rr = b2Dot(r, r); float32 sigma = c * c - rr * b; // Check for negative discriminant and short segment. if (sigma < 0.0f || rr < b2_epsilon) { return false; } // Find the point of intersection of the line with the circle. float32 a = -(c + b2Sqrt(sigma)); // Is the intersection point on the segment? if (0.0f <= a && a <= input.maxFraction * rr) { a /= rr; output->fraction = a; output->normal = s + a * r; output->normal.Normalize(); return true; } return false; } void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const { B2_NOT_USED(childIndex); b2Vec2 p = transform.p + b2Mul(transform.q, m_p); aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius); aabb->upperBound.Set(p.x + m_radius, p.y + m_radius); } void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const { massData->mass = density * b2_pi * m_radius * m_radius; massData->center = m_p; // inertia about the local origin massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p)); } pybox2d-2.3.2/Box2D/Collision/Shapes/b2CircleShape.h000066400000000000000000000047471276457661000220120ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CIRCLE_SHAPE_H #define B2_CIRCLE_SHAPE_H #include /// A circle shape. class b2CircleShape : public b2Shape { public: b2CircleShape(); /// Implement b2Shape. b2Shape* Clone(b2BlockAllocator* allocator) const; /// @see b2Shape::GetChildCount int32 GetChildCount() const; /// Implement b2Shape. bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; /// Implement b2Shape. bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform, int32 childIndex) const; /// @see b2Shape::ComputeAABB void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; /// @see b2Shape::ComputeMass void ComputeMass(b2MassData* massData, float32 density) const; /// Get the supporting vertex index in the given direction. int32 GetSupport(const b2Vec2& d) const; /// Get the supporting vertex in the given direction. const b2Vec2& GetSupportVertex(const b2Vec2& d) const; /// Get the vertex count. int32 GetVertexCount() const { return 1; } /// Get a vertex by index. Used by b2Distance. const b2Vec2& GetVertex(int32 index) const; /// Position b2Vec2 m_p; }; inline b2CircleShape::b2CircleShape() { m_type = e_circle; m_radius = 0.0f; m_p.SetZero(); } inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const { B2_NOT_USED(d); return 0; } inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const { B2_NOT_USED(d); return m_p; } inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const { B2_NOT_USED(index); b2Assert(index == 0); return m_p; } #endif pybox2d-2.3.2/Box2D/Collision/Shapes/b2EdgeShape.cpp000066400000000000000000000063661276457661000220070ustar00rootroot00000000000000/* * Copyright (c) 2006-2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include using namespace std; void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2) { m_vertex1 = v1; m_vertex2 = v2; m_hasVertex0 = false; m_hasVertex3 = false; } b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const { void* mem = allocator->Allocate(sizeof(b2EdgeShape)); b2EdgeShape* clone = new (mem) b2EdgeShape; *clone = *this; return clone; } int32 b2EdgeShape::GetChildCount() const { return 1; } bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const { B2_NOT_USED(xf); B2_NOT_USED(p); return false; } // p = p1 + t * d // v = v1 + s * e // p1 + t * d = v1 + s * e // s * e - t * d = p1 - v1 bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& xf, int32 childIndex) const { B2_NOT_USED(childIndex); // Put the ray into the edge's frame of reference. b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); b2Vec2 d = p2 - p1; b2Vec2 v1 = m_vertex1; b2Vec2 v2 = m_vertex2; b2Vec2 e = v2 - v1; b2Vec2 normal(e.y, -e.x); normal.Normalize(); // q = p1 + t * d // dot(normal, q - v1) = 0 // dot(normal, p1 - v1) + t * dot(normal, d) = 0 float32 numerator = b2Dot(normal, v1 - p1); float32 denominator = b2Dot(normal, d); if (denominator == 0.0f) { return false; } float32 t = numerator / denominator; if (t < 0.0f || input.maxFraction < t) { return false; } b2Vec2 q = p1 + t * d; // q = v1 + s * r // s = dot(q - v1, r) / dot(r, r) b2Vec2 r = v2 - v1; float32 rr = b2Dot(r, r); if (rr == 0.0f) { return false; } float32 s = b2Dot(q - v1, r) / rr; if (s < 0.0f || 1.0f < s) { return false; } output->fraction = t; if (numerator > 0.0f) { output->normal = -normal; } else { output->normal = normal; } return true; } void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const { B2_NOT_USED(childIndex); b2Vec2 v1 = b2Mul(xf, m_vertex1); b2Vec2 v2 = b2Mul(xf, m_vertex2); b2Vec2 lower = b2Min(v1, v2); b2Vec2 upper = b2Max(v1, v2); b2Vec2 r(m_radius, m_radius); aabb->lowerBound = lower - r; aabb->upperBound = upper + r; } void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const { B2_NOT_USED(density); massData->mass = 0.0f; massData->center = 0.5f * (m_vertex1 + m_vertex2); massData->I = 0.0f; } pybox2d-2.3.2/Box2D/Collision/Shapes/b2EdgeShape.h000066400000000000000000000044551276457661000214510ustar00rootroot00000000000000/* * Copyright (c) 2006-2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_EDGE_SHAPE_H #define B2_EDGE_SHAPE_H #include /// A line segment (edge) shape. These can be connected in chains or loops /// to other edge shapes. The connectivity information is used to ensure /// correct contact normals. class b2EdgeShape : public b2Shape { public: b2EdgeShape(); /// Set this as an isolated edge. void Set(const b2Vec2& v1, const b2Vec2& v2); /// Implement b2Shape. b2Shape* Clone(b2BlockAllocator* allocator) const; /// @see b2Shape::GetChildCount int32 GetChildCount() const; /// @see b2Shape::TestPoint bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; /// Implement b2Shape. bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform, int32 childIndex) const; /// @see b2Shape::ComputeAABB void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; /// @see b2Shape::ComputeMass void ComputeMass(b2MassData* massData, float32 density) const; /// These are the edge vertices b2Vec2 m_vertex1, m_vertex2; /// Optional adjacent vertices. These are used for smooth collision. b2Vec2 m_vertex0, m_vertex3; bool m_hasVertex0, m_hasVertex3; }; inline b2EdgeShape::b2EdgeShape() { m_type = e_edge; m_radius = b2_polygonRadius; m_vertex0.x = 0.0f; m_vertex0.y = 0.0f; m_vertex3.x = 0.0f; m_vertex3.y = 0.0f; m_hasVertex0 = false; m_hasVertex3 = false; } #endif pybox2d-2.3.2/Box2D/Collision/Shapes/b2PolygonShape.cpp000066400000000000000000000237041276457661000225650ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const { void* mem = allocator->Allocate(sizeof(b2PolygonShape)); b2PolygonShape* clone = new (mem) b2PolygonShape; *clone = *this; return clone; } void b2PolygonShape::SetAsBox(float32 hx, float32 hy) { m_count = 4; m_vertices[0].Set(-hx, -hy); m_vertices[1].Set( hx, -hy); m_vertices[2].Set( hx, hy); m_vertices[3].Set(-hx, hy); m_normals[0].Set(0.0f, -1.0f); m_normals[1].Set(1.0f, 0.0f); m_normals[2].Set(0.0f, 1.0f); m_normals[3].Set(-1.0f, 0.0f); m_centroid.SetZero(); } void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle) { m_count = 4; m_vertices[0].Set(-hx, -hy); m_vertices[1].Set( hx, -hy); m_vertices[2].Set( hx, hy); m_vertices[3].Set(-hx, hy); m_normals[0].Set(0.0f, -1.0f); m_normals[1].Set(1.0f, 0.0f); m_normals[2].Set(0.0f, 1.0f); m_normals[3].Set(-1.0f, 0.0f); m_centroid = center; b2Transform xf; xf.p = center; xf.q.Set(angle); // Transform vertices and normals. for (int32 i = 0; i < m_count; ++i) { m_vertices[i] = b2Mul(xf, m_vertices[i]); m_normals[i] = b2Mul(xf.q, m_normals[i]); } } int32 b2PolygonShape::GetChildCount() const { return 1; } static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count) { b2Assert(count >= 3); b2Vec2 c; c.Set(0.0f, 0.0f); float32 area = 0.0f; // pRef is the reference point for forming triangles. // It's location doesn't change the result (except for rounding error). b2Vec2 pRef(0.0f, 0.0f); #if 0 // This code would put the reference point inside the polygon. for (int32 i = 0; i < count; ++i) { pRef += vs[i]; } pRef *= 1.0f / count; #endif const float32 inv3 = 1.0f / 3.0f; for (int32 i = 0; i < count; ++i) { // Triangle vertices. b2Vec2 p1 = pRef; b2Vec2 p2 = vs[i]; b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; b2Vec2 e1 = p2 - p1; b2Vec2 e2 = p3 - p1; float32 D = b2Cross(e1, e2); float32 triangleArea = 0.5f * D; area += triangleArea; // Area weighted centroid c += triangleArea * inv3 * (p1 + p2 + p3); } // Centroid b2Assert(area > b2_epsilon); c *= 1.0f / area; return c; } void b2PolygonShape::Set(const b2Vec2* vertices, int32 count) { b2Assert(3 <= count && count <= b2_maxPolygonVertices); if (count < 3) { SetAsBox(1.0f, 1.0f); return; } int32 n = b2Min(count, b2_maxPolygonVertices); // Copy vertices into local buffer b2Vec2 ps[b2_maxPolygonVertices]; for (int32 i = 0; i < n; ++i) { ps[i] = vertices[i]; } // Create the convex hull using the Gift wrapping algorithm // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm // Find the right most point on the hull int32 i0 = 0; float32 x0 = ps[0].x; for (int32 i = 1; i < count; ++i) { float32 x = ps[i].x; if (x > x0 || (x == x0 && ps[i].y < ps[i0].y)) { i0 = i; x0 = x; } } int32 hull[b2_maxPolygonVertices]; int32 m = 0; int32 ih = i0; for (;;) { hull[m] = ih; int32 ie = 0; for (int32 j = 1; j < n; ++j) { if (ie == ih) { ie = j; continue; } b2Vec2 r = ps[ie] - ps[hull[m]]; b2Vec2 v = ps[j] - ps[hull[m]]; float32 c = b2Cross(r, v); if (c < 0.0f) { ie = j; } // Collinearity check if (c == 0.0f && v.LengthSquared() > r.LengthSquared()) { ie = j; } } ++m; ih = ie; if (ie == i0) { break; } } m_count = m; // Copy vertices. for (int32 i = 0; i < m; ++i) { m_vertices[i] = ps[hull[i]]; } // Compute normals. Ensure the edges have non-zero length. for (int32 i = 0; i < m; ++i) { int32 i1 = i; int32 i2 = i + 1 < m ? i + 1 : 0; b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon); m_normals[i] = b2Cross(edge, 1.0f); m_normals[i].Normalize(); } // Compute the polygon centroid. m_centroid = ComputeCentroid(m_vertices, m); } bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const { b2Vec2 pLocal = b2MulT(xf.q, p - xf.p); for (int32 i = 0; i < m_count; ++i) { float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]); if (dot > 0.0f) { return false; } } return true; } bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& xf, int32 childIndex) const { B2_NOT_USED(childIndex); // Put the ray into the polygon's frame of reference. b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p); b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p); b2Vec2 d = p2 - p1; float32 lower = 0.0f, upper = input.maxFraction; int32 index = -1; for (int32 i = 0; i < m_count; ++i) { // p = p1 + a * d // dot(normal, p - v) = 0 // dot(normal, p1 - v) + a * dot(normal, d) = 0 float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1); float32 denominator = b2Dot(m_normals[i], d); if (denominator == 0.0f) { if (numerator < 0.0f) { return false; } } else { // Note: we want this predicate without division: // lower < numerator / denominator, where denominator < 0 // Since denominator < 0, we have to flip the inequality: // lower < numerator / denominator <==> denominator * lower > numerator. if (denominator < 0.0f && numerator < lower * denominator) { // Increase lower. // The segment enters this half-space. lower = numerator / denominator; index = i; } else if (denominator > 0.0f && numerator < upper * denominator) { // Decrease upper. // The segment exits this half-space. upper = numerator / denominator; } } // The use of epsilon here causes the assert on lower to trip // in some cases. Apparently the use of epsilon was to make edge // shapes work, but now those are handled separately. //if (upper < lower - b2_epsilon) if (upper < lower) { return false; } } b2Assert(0.0f <= lower && lower <= input.maxFraction); if (index >= 0) { output->fraction = lower; output->normal = b2Mul(xf.q, m_normals[index]); return true; } return false; } void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const { B2_NOT_USED(childIndex); b2Vec2 lower = b2Mul(xf, m_vertices[0]); b2Vec2 upper = lower; for (int32 i = 1; i < m_count; ++i) { b2Vec2 v = b2Mul(xf, m_vertices[i]); lower = b2Min(lower, v); upper = b2Max(upper, v); } b2Vec2 r(m_radius, m_radius); aabb->lowerBound = lower - r; aabb->upperBound = upper + r; } void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const { // Polygon mass, centroid, and inertia. // Let rho be the polygon density in mass per unit area. // Then: // mass = rho * int(dA) // centroid.x = (1/mass) * rho * int(x * dA) // centroid.y = (1/mass) * rho * int(y * dA) // I = rho * int((x*x + y*y) * dA) // // We can compute these integrals by summing all the integrals // for each triangle of the polygon. To evaluate the integral // for a single triangle, we make a change of variables to // the (u,v) coordinates of the triangle: // x = x0 + e1x * u + e2x * v // y = y0 + e1y * u + e2y * v // where 0 <= u && 0 <= v && u + v <= 1. // // We integrate u from [0,1-v] and then v from [0,1]. // We also need to use the Jacobian of the transformation: // D = cross(e1, e2) // // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3) // // The rest of the derivation is handled by computer algebra. b2Assert(m_count >= 3); b2Vec2 center; center.Set(0.0f, 0.0f); float32 area = 0.0f; float32 I = 0.0f; // s is the reference point for forming triangles. // It's location doesn't change the result (except for rounding error). b2Vec2 s(0.0f, 0.0f); // This code would put the reference point inside the polygon. for (int32 i = 0; i < m_count; ++i) { s += m_vertices[i]; } s *= 1.0f / m_count; const float32 k_inv3 = 1.0f / 3.0f; for (int32 i = 0; i < m_count; ++i) { // Triangle vertices. b2Vec2 e1 = m_vertices[i] - s; b2Vec2 e2 = i + 1 < m_count ? m_vertices[i+1] - s : m_vertices[0] - s; float32 D = b2Cross(e1, e2); float32 triangleArea = 0.5f * D; area += triangleArea; // Area weighted centroid center += triangleArea * k_inv3 * (e1 + e2); float32 ex1 = e1.x, ey1 = e1.y; float32 ex2 = e2.x, ey2 = e2.y; float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2; float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2; I += (0.25f * k_inv3 * D) * (intx2 + inty2); } // Total mass massData->mass = density * area; // Center of mass b2Assert(area > b2_epsilon); center *= 1.0f / area; massData->center = center + s; // Inertia tensor relative to the local origin (point s). massData->I = density * I; // Shift to center of mass then to original body origin. massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center)); } bool b2PolygonShape::Validate() const { for (int32 i = 0; i < m_count; ++i) { int32 i1 = i; int32 i2 = i < m_count - 1 ? i1 + 1 : 0; b2Vec2 p = m_vertices[i1]; b2Vec2 e = m_vertices[i2] - p; for (int32 j = 0; j < m_count; ++j) { if (j == i1 || j == i2) { continue; } b2Vec2 v = m_vertices[j] - p; float32 c = b2Cross(e, v); if (c < 0.0f) { return false; } } } return true; } pybox2d-2.3.2/Box2D/Collision/Shapes/b2PolygonShape.h000066400000000000000000000066331276457661000222340ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_POLYGON_SHAPE_H #define B2_POLYGON_SHAPE_H #include /// A convex polygon. It is assumed that the interior of the polygon is to /// the left of each edge. /// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. /// In most cases you should not need many vertices for a convex polygon. class b2PolygonShape : public b2Shape { public: b2PolygonShape(); /// Implement b2Shape. b2Shape* Clone(b2BlockAllocator* allocator) const; /// @see b2Shape::GetChildCount int32 GetChildCount() const; /// Create a convex hull from the given array of local points. /// The count must be in the range [3, b2_maxPolygonVertices]. /// @warning the points may be re-ordered, even if they form a convex polygon /// @warning collinear points are handled but not removed. Collinear points /// may lead to poor stacking behavior. void Set(const b2Vec2* points, int32 count); /// Build vertices to represent an axis-aligned box centered on the local origin. /// @param hx the half-width. /// @param hy the half-height. void SetAsBox(float32 hx, float32 hy); /// Build vertices to represent an oriented box. /// @param hx the half-width. /// @param hy the half-height. /// @param center the center of the box in local coordinates. /// @param angle the rotation of the box in local coordinates. void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle); /// @see b2Shape::TestPoint bool TestPoint(const b2Transform& transform, const b2Vec2& p) const; /// Implement b2Shape. bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform, int32 childIndex) const; /// @see b2Shape::ComputeAABB void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const; /// @see b2Shape::ComputeMass void ComputeMass(b2MassData* massData, float32 density) const; /// Get the vertex count. int32 GetVertexCount() const { return m_count; } /// Get a vertex by index. const b2Vec2& GetVertex(int32 index) const; /// Validate convexity. This is a very time consuming operation. /// @returns true if valid bool Validate() const; b2Vec2 m_centroid; b2Vec2 m_vertices[b2_maxPolygonVertices]; b2Vec2 m_normals[b2_maxPolygonVertices]; int32 m_count; }; inline b2PolygonShape::b2PolygonShape() { m_type = e_polygon; m_radius = b2_polygonRadius; m_count = 0; m_centroid.SetZero(); } inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const { b2Assert(0 <= index && index < m_count); return m_vertices[index]; } #endif pybox2d-2.3.2/Box2D/Collision/Shapes/b2Shape.h000066400000000000000000000066511276457661000206640ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_SHAPE_H #define B2_SHAPE_H #include #include #include /// This holds the mass data computed for a shape. struct b2MassData { /// The mass of the shape, usually in kilograms. float32 mass; /// The position of the shape's centroid relative to the shape's origin. b2Vec2 center; /// The rotational inertia of the shape about the local origin. float32 I; }; /// A shape is used for collision detection. You can create a shape however you like. /// Shapes used for simulation in b2World are created automatically when a b2Fixture /// is created. Shapes may encapsulate a one or more child shapes. class b2Shape { public: enum Type { e_circle = 0, e_edge = 1, e_polygon = 2, e_chain = 3, e_typeCount = 4 }; virtual ~b2Shape() {} /// Clone the concrete shape using the provided allocator. virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0; /// Get the type of this shape. You can use this to down cast to the concrete shape. /// @return the shape type. Type GetType() const; /// Get the number of child primitives. virtual int32 GetChildCount() const = 0; /// Test a point for containment in this shape. This only works for convex shapes. /// @param xf the shape world transform. /// @param p a point in world coordinates. virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0; /// Cast a ray against a child shape. /// @param output the ray-cast results. /// @param input the ray-cast input parameters. /// @param transform the transform to be applied to the shape. /// @param childIndex the child shape index virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, const b2Transform& transform, int32 childIndex) const = 0; /// Given a transform, compute the associated axis aligned bounding box for a child shape. /// @param aabb returns the axis aligned box. /// @param xf the world transform of the shape. /// @param childIndex the child shape virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0; /// Compute the mass properties of this shape using its dimensions and density. /// The inertia tensor is computed about the local origin. /// @param massData returns the mass data for this shape. /// @param density the density in kilograms per meter squared. virtual void ComputeMass(b2MassData* massData, float32 density) const = 0; Type m_type; float32 m_radius; }; inline b2Shape::Type b2Shape::GetType() const { return m_type; } #endif pybox2d-2.3.2/Box2D/Collision/b2BroadPhase.cpp000066400000000000000000000060651276457661000207430ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include using namespace std; b2BroadPhase::b2BroadPhase() { m_proxyCount = 0; m_pairCapacity = 16; m_pairCount = 0; m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); m_moveCapacity = 16; m_moveCount = 0; m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); } b2BroadPhase::~b2BroadPhase() { b2Free(m_moveBuffer); b2Free(m_pairBuffer); } int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) { int32 proxyId = m_tree.CreateProxy(aabb, userData); ++m_proxyCount; BufferMove(proxyId); return proxyId; } void b2BroadPhase::DestroyProxy(int32 proxyId) { UnBufferMove(proxyId); --m_proxyCount; m_tree.DestroyProxy(proxyId); } void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) { bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement); if (buffer) { BufferMove(proxyId); } } void b2BroadPhase::TouchProxy(int32 proxyId) { BufferMove(proxyId); } void b2BroadPhase::BufferMove(int32 proxyId) { if (m_moveCount == m_moveCapacity) { int32* oldBuffer = m_moveBuffer; m_moveCapacity *= 2; m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32)); memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32)); b2Free(oldBuffer); } m_moveBuffer[m_moveCount] = proxyId; ++m_moveCount; } void b2BroadPhase::UnBufferMove(int32 proxyId) { for (int32 i = 0; i < m_moveCount; ++i) { if (m_moveBuffer[i] == proxyId) { m_moveBuffer[i] = e_nullProxy; } } } // This is called from b2DynamicTree::Query when we are gathering pairs. bool b2BroadPhase::QueryCallback(int32 proxyId) { // A proxy cannot form a pair with itself. if (proxyId == m_queryProxyId) { return true; } // Grow the pair buffer as needed. if (m_pairCount == m_pairCapacity) { b2Pair* oldBuffer = m_pairBuffer; m_pairCapacity *= 2; m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair)); b2Free(oldBuffer); } m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId); m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId); ++m_pairCount; return true; } pybox2d-2.3.2/Box2D/Collision/b2BroadPhase.h000066400000000000000000000154541276457661000204120ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_BROAD_PHASE_H #define B2_BROAD_PHASE_H #include #include #include #include struct b2Pair { int32 proxyIdA; int32 proxyIdB; }; /// The broad-phase is used for computing pairs and performing volume queries and ray casts. /// This broad-phase does not persist pairs. Instead, this reports potentially new pairs. /// It is up to the client to consume the new pairs and to track subsequent overlap. class b2BroadPhase { public: enum { e_nullProxy = -1 }; b2BroadPhase(); ~b2BroadPhase(); /// Create a proxy with an initial AABB. Pairs are not reported until /// UpdatePairs is called. int32 CreateProxy(const b2AABB& aabb, void* userData); /// Destroy a proxy. It is up to the client to remove any pairs. void DestroyProxy(int32 proxyId); /// Call MoveProxy as many times as you like, then when you are done /// call UpdatePairs to finalized the proxy pairs (for your time step). void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement); /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. void TouchProxy(int32 proxyId); /// Get the fat AABB for a proxy. const b2AABB& GetFatAABB(int32 proxyId) const; /// Get user data from a proxy. Returns NULL if the id is invalid. void* GetUserData(int32 proxyId) const; /// Test overlap of fat AABBs. bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const; /// Get the number of proxies. int32 GetProxyCount() const; /// Update the pairs. This results in pair callbacks. This can only add pairs. template void UpdatePairs(T* callback); /// Query an AABB for overlapping proxies. The callback class /// is called for each proxy that overlaps the supplied AABB. template void Query(T* callback, const b2AABB& aabb) const; /// Ray-cast against the proxies in the tree. This relies on the callback /// to perform a exact ray-cast in the case were the proxy contains a shape. /// The callback also performs the any collision filtering. This has performance /// roughly equal to k * log(n), where k is the number of collisions and n is the /// number of proxies in the tree. /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). /// @param callback a callback class that is called for each proxy that is hit by the ray. template void RayCast(T* callback, const b2RayCastInput& input) const; /// Get the height of the embedded tree. int32 GetTreeHeight() const; /// Get the balance of the embedded tree. int32 GetTreeBalance() const; /// Get the quality metric of the embedded tree. float32 GetTreeQuality() const; /// Shift the world origin. Useful for large worlds. /// The shift formula is: position -= newOrigin /// @param newOrigin the new origin with respect to the old origin void ShiftOrigin(const b2Vec2& newOrigin); private: friend class b2DynamicTree; void BufferMove(int32 proxyId); void UnBufferMove(int32 proxyId); bool QueryCallback(int32 proxyId); b2DynamicTree m_tree; int32 m_proxyCount; int32* m_moveBuffer; int32 m_moveCapacity; int32 m_moveCount; b2Pair* m_pairBuffer; int32 m_pairCapacity; int32 m_pairCount; int32 m_queryProxyId; }; /// This is used to sort pairs. inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) { if (pair1.proxyIdA < pair2.proxyIdA) { return true; } if (pair1.proxyIdA == pair2.proxyIdA) { return pair1.proxyIdB < pair2.proxyIdB; } return false; } inline void* b2BroadPhase::GetUserData(int32 proxyId) const { return m_tree.GetUserData(proxyId); } inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const { const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA); const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB); return b2TestOverlap(aabbA, aabbB); } inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const { return m_tree.GetFatAABB(proxyId); } inline int32 b2BroadPhase::GetProxyCount() const { return m_proxyCount; } inline int32 b2BroadPhase::GetTreeHeight() const { return m_tree.GetHeight(); } inline int32 b2BroadPhase::GetTreeBalance() const { return m_tree.GetMaxBalance(); } inline float32 b2BroadPhase::GetTreeQuality() const { return m_tree.GetAreaRatio(); } template void b2BroadPhase::UpdatePairs(T* callback) { // Reset pair buffer m_pairCount = 0; // Perform tree queries for all moving proxies. for (int32 i = 0; i < m_moveCount; ++i) { m_queryProxyId = m_moveBuffer[i]; if (m_queryProxyId == e_nullProxy) { continue; } // We have to query the tree with the fat AABB so that // we don't fail to create a pair that may touch later. const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId); // Query tree, create pairs and add them pair buffer. m_tree.Query(this, fatAABB); } // Reset move buffer m_moveCount = 0; // Sort the pair buffer to expose duplicates. std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); // Send the pairs back to the client. int32 i = 0; while (i < m_pairCount) { b2Pair* primaryPair = m_pairBuffer + i; void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); callback->AddPair(userDataA, userDataB); ++i; // Skip any duplicate pairs. while (i < m_pairCount) { b2Pair* pair = m_pairBuffer + i; if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) { break; } ++i; } } // Try to keep the tree balanced. //m_tree.Rebalance(4); } template inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const { m_tree.Query(callback, aabb); } template inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const { m_tree.RayCast(callback, input); } inline void b2BroadPhase::ShiftOrigin(const b2Vec2& newOrigin) { m_tree.ShiftOrigin(newOrigin); } #endif pybox2d-2.3.2/Box2D/Collision/b2CollideCircle.cpp000066400000000000000000000104021276457661000214160ustar00rootroot00000000000000/* * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include void b2CollideCircles( b2Manifold* manifold, const b2CircleShape* circleA, const b2Transform& xfA, const b2CircleShape* circleB, const b2Transform& xfB) { manifold->pointCount = 0; b2Vec2 pA = b2Mul(xfA, circleA->m_p); b2Vec2 pB = b2Mul(xfB, circleB->m_p); b2Vec2 d = pB - pA; float32 distSqr = b2Dot(d, d); float32 rA = circleA->m_radius, rB = circleB->m_radius; float32 radius = rA + rB; if (distSqr > radius * radius) { return; } manifold->type = b2Manifold::e_circles; manifold->localPoint = circleA->m_p; manifold->localNormal.SetZero(); manifold->pointCount = 1; manifold->points[0].localPoint = circleB->m_p; manifold->points[0].id.key = 0; } void b2CollidePolygonAndCircle( b2Manifold* manifold, const b2PolygonShape* polygonA, const b2Transform& xfA, const b2CircleShape* circleB, const b2Transform& xfB) { manifold->pointCount = 0; // Compute circle position in the frame of the polygon. b2Vec2 c = b2Mul(xfB, circleB->m_p); b2Vec2 cLocal = b2MulT(xfA, c); // Find the min separating edge. int32 normalIndex = 0; float32 separation = -b2_maxFloat; float32 radius = polygonA->m_radius + circleB->m_radius; int32 vertexCount = polygonA->m_count; const b2Vec2* vertices = polygonA->m_vertices; const b2Vec2* normals = polygonA->m_normals; for (int32 i = 0; i < vertexCount; ++i) { float32 s = b2Dot(normals[i], cLocal - vertices[i]); if (s > radius) { // Early out. return; } if (s > separation) { separation = s; normalIndex = i; } } // Vertices that subtend the incident face. int32 vertIndex1 = normalIndex; int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; b2Vec2 v1 = vertices[vertIndex1]; b2Vec2 v2 = vertices[vertIndex2]; // If the center is inside the polygon ... if (separation < b2_epsilon) { manifold->pointCount = 1; manifold->type = b2Manifold::e_faceA; manifold->localNormal = normals[normalIndex]; manifold->localPoint = 0.5f * (v1 + v2); manifold->points[0].localPoint = circleB->m_p; manifold->points[0].id.key = 0; return; } // Compute barycentric coordinates float32 u1 = b2Dot(cLocal - v1, v2 - v1); float32 u2 = b2Dot(cLocal - v2, v1 - v2); if (u1 <= 0.0f) { if (b2DistanceSquared(cLocal, v1) > radius * radius) { return; } manifold->pointCount = 1; manifold->type = b2Manifold::e_faceA; manifold->localNormal = cLocal - v1; manifold->localNormal.Normalize(); manifold->localPoint = v1; manifold->points[0].localPoint = circleB->m_p; manifold->points[0].id.key = 0; } else if (u2 <= 0.0f) { if (b2DistanceSquared(cLocal, v2) > radius * radius) { return; } manifold->pointCount = 1; manifold->type = b2Manifold::e_faceA; manifold->localNormal = cLocal - v2; manifold->localNormal.Normalize(); manifold->localPoint = v2; manifold->points[0].localPoint = circleB->m_p; manifold->points[0].id.key = 0; } else { b2Vec2 faceCenter = 0.5f * (v1 + v2); float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]); if (separation > radius) { return; } manifold->pointCount = 1; manifold->type = b2Manifold::e_faceA; manifold->localNormal = normals[vertIndex1]; manifold->localPoint = faceCenter; manifold->points[0].localPoint = circleB->m_p; manifold->points[0].id.key = 0; } } pybox2d-2.3.2/Box2D/Collision/b2CollideEdge.cpp000066400000000000000000000362451276457661000210760ustar00rootroot00000000000000/* * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include // Compute contact points for edge versus circle. // This accounts for edge connectivity. void b2CollideEdgeAndCircle(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, const b2CircleShape* circleB, const b2Transform& xfB) { manifold->pointCount = 0; // Compute circle in frame of edge b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p)); b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2; b2Vec2 e = B - A; // Barycentric coordinates float32 u = b2Dot(e, B - Q); float32 v = b2Dot(e, Q - A); float32 radius = edgeA->m_radius + circleB->m_radius; b2ContactFeature cf; cf.indexB = 0; cf.typeB = b2ContactFeature::e_vertex; // Region A if (v <= 0.0f) { b2Vec2 P = A; b2Vec2 d = Q - P; float32 dd = b2Dot(d, d); if (dd > radius * radius) { return; } // Is there an edge connected to A? if (edgeA->m_hasVertex0) { b2Vec2 A1 = edgeA->m_vertex0; b2Vec2 B1 = A; b2Vec2 e1 = B1 - A1; float32 u1 = b2Dot(e1, B1 - Q); // Is the circle in Region AB of the previous edge? if (u1 > 0.0f) { return; } } cf.indexA = 0; cf.typeA = b2ContactFeature::e_vertex; manifold->pointCount = 1; manifold->type = b2Manifold::e_circles; manifold->localNormal.SetZero(); manifold->localPoint = P; manifold->points[0].id.key = 0; manifold->points[0].id.cf = cf; manifold->points[0].localPoint = circleB->m_p; return; } // Region B if (u <= 0.0f) { b2Vec2 P = B; b2Vec2 d = Q - P; float32 dd = b2Dot(d, d); if (dd > radius * radius) { return; } // Is there an edge connected to B? if (edgeA->m_hasVertex3) { b2Vec2 B2 = edgeA->m_vertex3; b2Vec2 A2 = B; b2Vec2 e2 = B2 - A2; float32 v2 = b2Dot(e2, Q - A2); // Is the circle in Region AB of the next edge? if (v2 > 0.0f) { return; } } cf.indexA = 1; cf.typeA = b2ContactFeature::e_vertex; manifold->pointCount = 1; manifold->type = b2Manifold::e_circles; manifold->localNormal.SetZero(); manifold->localPoint = P; manifold->points[0].id.key = 0; manifold->points[0].id.cf = cf; manifold->points[0].localPoint = circleB->m_p; return; } // Region AB float32 den = b2Dot(e, e); b2Assert(den > 0.0f); b2Vec2 P = (1.0f / den) * (u * A + v * B); b2Vec2 d = Q - P; float32 dd = b2Dot(d, d); if (dd > radius * radius) { return; } b2Vec2 n(-e.y, e.x); if (b2Dot(n, Q - A) < 0.0f) { n.Set(-n.x, -n.y); } n.Normalize(); cf.indexA = 0; cf.typeA = b2ContactFeature::e_face; manifold->pointCount = 1; manifold->type = b2Manifold::e_faceA; manifold->localNormal = n; manifold->localPoint = A; manifold->points[0].id.key = 0; manifold->points[0].id.cf = cf; manifold->points[0].localPoint = circleB->m_p; } // This structure is used to keep track of the best separating axis. struct b2EPAxis { enum Type { e_unknown, e_edgeA, e_edgeB }; Type type; int32 index; float32 separation; }; // This holds polygon B expressed in frame A. struct b2TempPolygon { b2Vec2 vertices[b2_maxPolygonVertices]; b2Vec2 normals[b2_maxPolygonVertices]; int32 count; }; // Reference face used for clipping struct b2ReferenceFace { int32 i1, i2; b2Vec2 v1, v2; b2Vec2 normal; b2Vec2 sideNormal1; float32 sideOffset1; b2Vec2 sideNormal2; float32 sideOffset2; }; // This class collides and edge and a polygon, taking into account edge adjacency. struct b2EPCollider { void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, const b2PolygonShape* polygonB, const b2Transform& xfB); b2EPAxis ComputeEdgeSeparation(); b2EPAxis ComputePolygonSeparation(); enum VertexType { e_isolated, e_concave, e_convex }; b2TempPolygon m_polygonB; b2Transform m_xf; b2Vec2 m_centroidB; b2Vec2 m_v0, m_v1, m_v2, m_v3; b2Vec2 m_normal0, m_normal1, m_normal2; b2Vec2 m_normal; VertexType m_type1, m_type2; b2Vec2 m_lowerLimit, m_upperLimit; float32 m_radius; bool m_front; }; // Algorithm: // 1. Classify v1 and v2 // 2. Classify polygon centroid as front or back // 3. Flip normal if necessary // 4. Initialize normal range to [-pi, pi] about face normal // 5. Adjust normal range according to adjacent edges // 6. Visit each separating axes, only accept axes within the range // 7. Return if _any_ axis indicates separation // 8. Clip void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, const b2PolygonShape* polygonB, const b2Transform& xfB) { m_xf = b2MulT(xfA, xfB); m_centroidB = b2Mul(m_xf, polygonB->m_centroid); m_v0 = edgeA->m_vertex0; m_v1 = edgeA->m_vertex1; m_v2 = edgeA->m_vertex2; m_v3 = edgeA->m_vertex3; bool hasVertex0 = edgeA->m_hasVertex0; bool hasVertex3 = edgeA->m_hasVertex3; b2Vec2 edge1 = m_v2 - m_v1; edge1.Normalize(); m_normal1.Set(edge1.y, -edge1.x); float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1); float32 offset0 = 0.0f, offset2 = 0.0f; bool convex1 = false, convex2 = false; // Is there a preceding edge? if (hasVertex0) { b2Vec2 edge0 = m_v1 - m_v0; edge0.Normalize(); m_normal0.Set(edge0.y, -edge0.x); convex1 = b2Cross(edge0, edge1) >= 0.0f; offset0 = b2Dot(m_normal0, m_centroidB - m_v0); } // Is there a following edge? if (hasVertex3) { b2Vec2 edge2 = m_v3 - m_v2; edge2.Normalize(); m_normal2.Set(edge2.y, -edge2.x); convex2 = b2Cross(edge1, edge2) > 0.0f; offset2 = b2Dot(m_normal2, m_centroidB - m_v2); } // Determine front or back collision. Determine collision normal limits. if (hasVertex0 && hasVertex3) { if (convex1 && convex2) { m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f; if (m_front) { m_normal = m_normal1; m_lowerLimit = m_normal0; m_upperLimit = m_normal2; } else { m_normal = -m_normal1; m_lowerLimit = -m_normal1; m_upperLimit = -m_normal1; } } else if (convex1) { m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f); if (m_front) { m_normal = m_normal1; m_lowerLimit = m_normal0; m_upperLimit = m_normal1; } else { m_normal = -m_normal1; m_lowerLimit = -m_normal2; m_upperLimit = -m_normal1; } } else if (convex2) { m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f); if (m_front) { m_normal = m_normal1; m_lowerLimit = m_normal1; m_upperLimit = m_normal2; } else { m_normal = -m_normal1; m_lowerLimit = -m_normal1; m_upperLimit = -m_normal0; } } else { m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f; if (m_front) { m_normal = m_normal1; m_lowerLimit = m_normal1; m_upperLimit = m_normal1; } else { m_normal = -m_normal1; m_lowerLimit = -m_normal2; m_upperLimit = -m_normal0; } } } else if (hasVertex0) { if (convex1) { m_front = offset0 >= 0.0f || offset1 >= 0.0f; if (m_front) { m_normal = m_normal1; m_lowerLimit = m_normal0; m_upperLimit = -m_normal1; } else { m_normal = -m_normal1; m_lowerLimit = m_normal1; m_upperLimit = -m_normal1; } } else { m_front = offset0 >= 0.0f && offset1 >= 0.0f; if (m_front) { m_normal = m_normal1; m_lowerLimit = m_normal1; m_upperLimit = -m_normal1; } else { m_normal = -m_normal1; m_lowerLimit = m_normal1; m_upperLimit = -m_normal0; } } } else if (hasVertex3) { if (convex2) { m_front = offset1 >= 0.0f || offset2 >= 0.0f; if (m_front) { m_normal = m_normal1; m_lowerLimit = -m_normal1; m_upperLimit = m_normal2; } else { m_normal = -m_normal1; m_lowerLimit = -m_normal1; m_upperLimit = m_normal1; } } else { m_front = offset1 >= 0.0f && offset2 >= 0.0f; if (m_front) { m_normal = m_normal1; m_lowerLimit = -m_normal1; m_upperLimit = m_normal1; } else { m_normal = -m_normal1; m_lowerLimit = -m_normal2; m_upperLimit = m_normal1; } } } else { m_front = offset1 >= 0.0f; if (m_front) { m_normal = m_normal1; m_lowerLimit = -m_normal1; m_upperLimit = -m_normal1; } else { m_normal = -m_normal1; m_lowerLimit = m_normal1; m_upperLimit = m_normal1; } } // Get polygonB in frameA m_polygonB.count = polygonB->m_count; for (int32 i = 0; i < polygonB->m_count; ++i) { m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]); m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]); } m_radius = 2.0f * b2_polygonRadius; manifold->pointCount = 0; b2EPAxis edgeAxis = ComputeEdgeSeparation(); // If no valid normal can be found than this edge should not collide. if (edgeAxis.type == b2EPAxis::e_unknown) { return; } if (edgeAxis.separation > m_radius) { return; } b2EPAxis polygonAxis = ComputePolygonSeparation(); if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius) { return; } // Use hysteresis for jitter reduction. const float32 k_relativeTol = 0.98f; const float32 k_absoluteTol = 0.001f; b2EPAxis primaryAxis; if (polygonAxis.type == b2EPAxis::e_unknown) { primaryAxis = edgeAxis; } else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol) { primaryAxis = polygonAxis; } else { primaryAxis = edgeAxis; } b2ClipVertex ie[2]; b2ReferenceFace rf; if (primaryAxis.type == b2EPAxis::e_edgeA) { manifold->type = b2Manifold::e_faceA; // Search for the polygon normal that is most anti-parallel to the edge normal. int32 bestIndex = 0; float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]); for (int32 i = 1; i < m_polygonB.count; ++i) { float32 value = b2Dot(m_normal, m_polygonB.normals[i]); if (value < bestValue) { bestValue = value; bestIndex = i; } } int32 i1 = bestIndex; int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0; ie[0].v = m_polygonB.vertices[i1]; ie[0].id.cf.indexA = 0; ie[0].id.cf.indexB = i1; ie[0].id.cf.typeA = b2ContactFeature::e_face; ie[0].id.cf.typeB = b2ContactFeature::e_vertex; ie[1].v = m_polygonB.vertices[i2]; ie[1].id.cf.indexA = 0; ie[1].id.cf.indexB = i2; ie[1].id.cf.typeA = b2ContactFeature::e_face; ie[1].id.cf.typeB = b2ContactFeature::e_vertex; if (m_front) { rf.i1 = 0; rf.i2 = 1; rf.v1 = m_v1; rf.v2 = m_v2; rf.normal = m_normal1; } else { rf.i1 = 1; rf.i2 = 0; rf.v1 = m_v2; rf.v2 = m_v1; rf.normal = -m_normal1; } } else { manifold->type = b2Manifold::e_faceB; ie[0].v = m_v1; ie[0].id.cf.indexA = 0; ie[0].id.cf.indexB = primaryAxis.index; ie[0].id.cf.typeA = b2ContactFeature::e_vertex; ie[0].id.cf.typeB = b2ContactFeature::e_face; ie[1].v = m_v2; ie[1].id.cf.indexA = 0; ie[1].id.cf.indexB = primaryAxis.index; ie[1].id.cf.typeA = b2ContactFeature::e_vertex; ie[1].id.cf.typeB = b2ContactFeature::e_face; rf.i1 = primaryAxis.index; rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0; rf.v1 = m_polygonB.vertices[rf.i1]; rf.v2 = m_polygonB.vertices[rf.i2]; rf.normal = m_polygonB.normals[rf.i1]; } rf.sideNormal1.Set(rf.normal.y, -rf.normal.x); rf.sideNormal2 = -rf.sideNormal1; rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1); rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2); // Clip incident edge against extruded edge1 side edges. b2ClipVertex clipPoints1[2]; b2ClipVertex clipPoints2[2]; int32 np; // Clip to box side 1 np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1); if (np < b2_maxManifoldPoints) { return; } // Clip to negative box side 1 np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2); if (np < b2_maxManifoldPoints) { return; } // Now clipPoints2 contains the clipped points. if (primaryAxis.type == b2EPAxis::e_edgeA) { manifold->localNormal = rf.normal; manifold->localPoint = rf.v1; } else { manifold->localNormal = polygonB->m_normals[rf.i1]; manifold->localPoint = polygonB->m_vertices[rf.i1]; } int32 pointCount = 0; for (int32 i = 0; i < b2_maxManifoldPoints; ++i) { float32 separation; separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1); if (separation <= m_radius) { b2ManifoldPoint* cp = manifold->points + pointCount; if (primaryAxis.type == b2EPAxis::e_edgeA) { cp->localPoint = b2MulT(m_xf, clipPoints2[i].v); cp->id = clipPoints2[i].id; } else { cp->localPoint = clipPoints2[i].v; cp->id.cf.typeA = clipPoints2[i].id.cf.typeB; cp->id.cf.typeB = clipPoints2[i].id.cf.typeA; cp->id.cf.indexA = clipPoints2[i].id.cf.indexB; cp->id.cf.indexB = clipPoints2[i].id.cf.indexA; } ++pointCount; } } manifold->pointCount = pointCount; } b2EPAxis b2EPCollider::ComputeEdgeSeparation() { b2EPAxis axis; axis.type = b2EPAxis::e_edgeA; axis.index = m_front ? 0 : 1; axis.separation = FLT_MAX; for (int32 i = 0; i < m_polygonB.count; ++i) { float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1); if (s < axis.separation) { axis.separation = s; } } return axis; } b2EPAxis b2EPCollider::ComputePolygonSeparation() { b2EPAxis axis; axis.type = b2EPAxis::e_unknown; axis.index = -1; axis.separation = -FLT_MAX; b2Vec2 perp(-m_normal.y, m_normal.x); for (int32 i = 0; i < m_polygonB.count; ++i) { b2Vec2 n = -m_polygonB.normals[i]; float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1); float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2); float32 s = b2Min(s1, s2); if (s > m_radius) { // No collision axis.type = b2EPAxis::e_edgeB; axis.index = i; axis.separation = s; return axis; } // Adjacency if (b2Dot(n, perp) >= 0.0f) { if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop) { continue; } } else { if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop) { continue; } } if (s > axis.separation) { axis.type = b2EPAxis::e_edgeB; axis.index = i; axis.separation = s; } } return axis; } void b2CollideEdgeAndPolygon( b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, const b2PolygonShape* polygonB, const b2Transform& xfB) { b2EPCollider collider; collider.Collide(manifold, edgeA, xfA, polygonB, xfB); } pybox2d-2.3.2/Box2D/Collision/b2CollidePolygon.cpp000066400000000000000000000207251276457661000216550ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include // Find the separation between poly1 and poly2 for a give edge normal on poly1. static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, const b2PolygonShape* poly2, const b2Transform& xf2) { const b2Vec2* vertices1 = poly1->m_vertices; const b2Vec2* normals1 = poly1->m_normals; int32 count2 = poly2->m_count; const b2Vec2* vertices2 = poly2->m_vertices; b2Assert(0 <= edge1 && edge1 < poly1->m_count); // Convert normal from poly1's frame into poly2's frame. b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]); b2Vec2 normal1 = b2MulT(xf2.q, normal1World); // Find support vertex on poly2 for -normal. int32 index = 0; float32 minDot = b2_maxFloat; for (int32 i = 0; i < count2; ++i) { float32 dot = b2Dot(vertices2[i], normal1); if (dot < minDot) { minDot = dot; index = i; } } b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]); b2Vec2 v2 = b2Mul(xf2, vertices2[index]); float32 separation = b2Dot(v2 - v1, normal1World); return separation; } // Find the max separation between poly1 and poly2 using edge normals from poly1. static float32 b2FindMaxSeparation(int32* edgeIndex, const b2PolygonShape* poly1, const b2Transform& xf1, const b2PolygonShape* poly2, const b2Transform& xf2) { int32 count1 = poly1->m_count; const b2Vec2* normals1 = poly1->m_normals; // Vector pointing from the centroid of poly1 to the centroid of poly2. b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid); b2Vec2 dLocal1 = b2MulT(xf1.q, d); // Find edge normal on poly1 that has the largest projection onto d. int32 edge = 0; float32 maxDot = -b2_maxFloat; for (int32 i = 0; i < count1; ++i) { float32 dot = b2Dot(normals1[i], dLocal1); if (dot > maxDot) { maxDot = dot; edge = i; } } // Get the separation for the edge normal. float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); // Check the separation for the previous edge normal. int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); // Check the separation for the next edge normal. int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0; float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); // Find the best edge and the search direction. int32 bestEdge; float32 bestSeparation; int32 increment; if (sPrev > s && sPrev > sNext) { increment = -1; bestEdge = prevEdge; bestSeparation = sPrev; } else if (sNext > s) { increment = 1; bestEdge = nextEdge; bestSeparation = sNext; } else { *edgeIndex = edge; return s; } // Perform a local search for the best edge normal. for ( ; ; ) { if (increment == -1) edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; else edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2); if (s > bestSeparation) { bestEdge = edge; bestSeparation = s; } else { break; } } *edgeIndex = bestEdge; return bestSeparation; } static void b2FindIncidentEdge(b2ClipVertex c[2], const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1, const b2PolygonShape* poly2, const b2Transform& xf2) { const b2Vec2* normals1 = poly1->m_normals; int32 count2 = poly2->m_count; const b2Vec2* vertices2 = poly2->m_vertices; const b2Vec2* normals2 = poly2->m_normals; b2Assert(0 <= edge1 && edge1 < poly1->m_count); // Get the normal of the reference edge in poly2's frame. b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1])); // Find the incident edge on poly2. int32 index = 0; float32 minDot = b2_maxFloat; for (int32 i = 0; i < count2; ++i) { float32 dot = b2Dot(normal1, normals2[i]); if (dot < minDot) { minDot = dot; index = i; } } // Build the clip vertices for the incident edge. int32 i1 = index; int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0; c[0].v = b2Mul(xf2, vertices2[i1]); c[0].id.cf.indexA = (uint8)edge1; c[0].id.cf.indexB = (uint8)i1; c[0].id.cf.typeA = b2ContactFeature::e_face; c[0].id.cf.typeB = b2ContactFeature::e_vertex; c[1].v = b2Mul(xf2, vertices2[i2]); c[1].id.cf.indexA = (uint8)edge1; c[1].id.cf.indexB = (uint8)i2; c[1].id.cf.typeA = b2ContactFeature::e_face; c[1].id.cf.typeB = b2ContactFeature::e_vertex; } // Find edge normal of max separation on A - return if separating axis is found // Find edge normal of max separation on B - return if separation axis is found // Choose reference edge as min(minA, minB) // Find incident edge // Clip // The normal points from 1 to 2 void b2CollidePolygons(b2Manifold* manifold, const b2PolygonShape* polyA, const b2Transform& xfA, const b2PolygonShape* polyB, const b2Transform& xfB) { manifold->pointCount = 0; float32 totalRadius = polyA->m_radius + polyB->m_radius; int32 edgeA = 0; float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); if (separationA > totalRadius) return; int32 edgeB = 0; float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); if (separationB > totalRadius) return; const b2PolygonShape* poly1; // reference polygon const b2PolygonShape* poly2; // incident polygon b2Transform xf1, xf2; int32 edge1; // reference edge uint8 flip; const float32 k_relativeTol = 0.98f; const float32 k_absoluteTol = 0.001f; if (separationB > k_relativeTol * separationA + k_absoluteTol) { poly1 = polyB; poly2 = polyA; xf1 = xfB; xf2 = xfA; edge1 = edgeB; manifold->type = b2Manifold::e_faceB; flip = 1; } else { poly1 = polyA; poly2 = polyB; xf1 = xfA; xf2 = xfB; edge1 = edgeA; manifold->type = b2Manifold::e_faceA; flip = 0; } b2ClipVertex incidentEdge[2]; b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); int32 count1 = poly1->m_count; const b2Vec2* vertices1 = poly1->m_vertices; int32 iv1 = edge1; int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0; b2Vec2 v11 = vertices1[iv1]; b2Vec2 v12 = vertices1[iv2]; b2Vec2 localTangent = v12 - v11; localTangent.Normalize(); b2Vec2 localNormal = b2Cross(localTangent, 1.0f); b2Vec2 planePoint = 0.5f * (v11 + v12); b2Vec2 tangent = b2Mul(xf1.q, localTangent); b2Vec2 normal = b2Cross(tangent, 1.0f); v11 = b2Mul(xf1, v11); v12 = b2Mul(xf1, v12); // Face offset. float32 frontOffset = b2Dot(normal, v11); // Side offsets, extended by polytope skin thickness. float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius; float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius; // Clip incident edge against extruded edge1 side edges. b2ClipVertex clipPoints1[2]; b2ClipVertex clipPoints2[2]; int np; // Clip to box side 1 np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1); if (np < 2) return; // Clip to negative box side 1 np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2); if (np < 2) { return; } // Now clipPoints2 contains the clipped points. manifold->localNormal = localNormal; manifold->localPoint = planePoint; int32 pointCount = 0; for (int32 i = 0; i < b2_maxManifoldPoints; ++i) { float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset; if (separation <= totalRadius) { b2ManifoldPoint* cp = manifold->points + pointCount; cp->localPoint = b2MulT(xf2, clipPoints2[i].v); cp->id = clipPoints2[i].id; if (flip) { // Swap features b2ContactFeature cf = cp->id.cf; cp->id.cf.indexA = cf.indexB; cp->id.cf.indexB = cf.indexA; cp->id.cf.typeA = cf.typeB; cp->id.cf.typeB = cf.typeA; } ++pointCount; } } manifold->pointCount = pointCount; } pybox2d-2.3.2/Box2D/Collision/b2Collision.cpp000066400000000000000000000142011276457661000206550ustar00rootroot00000000000000/* * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include void b2WorldManifold::Initialize(const b2Manifold* manifold, const b2Transform& xfA, float32 radiusA, const b2Transform& xfB, float32 radiusB) { if (manifold->pointCount == 0) { return; } switch (manifold->type) { case b2Manifold::e_circles: { normal.Set(1.0f, 0.0f); b2Vec2 pointA = b2Mul(xfA, manifold->localPoint); b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint); if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon) { normal = pointB - pointA; normal.Normalize(); } b2Vec2 cA = pointA + radiusA * normal; b2Vec2 cB = pointB - radiusB * normal; points[0] = 0.5f * (cA + cB); } break; case b2Manifold::e_faceA: { normal = b2Mul(xfA.q, manifold->localNormal); b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint); for (int32 i = 0; i < manifold->pointCount; ++i) { b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint); b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal; b2Vec2 cB = clipPoint - radiusB * normal; points[i] = 0.5f * (cA + cB); } } break; case b2Manifold::e_faceB: { normal = b2Mul(xfB.q, manifold->localNormal); b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint); for (int32 i = 0; i < manifold->pointCount; ++i) { b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint); b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal; b2Vec2 cA = clipPoint - radiusA * normal; points[i] = 0.5f * (cA + cB); } // Ensure normal points from A to B. normal = -normal; } break; } } void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], const b2Manifold* manifold1, const b2Manifold* manifold2) { for (int32 i = 0; i < b2_maxManifoldPoints; ++i) { state1[i] = b2_nullState; state2[i] = b2_nullState; } // Detect persists and removes. for (int32 i = 0; i < manifold1->pointCount; ++i) { b2ContactID id = manifold1->points[i].id; state1[i] = b2_removeState; for (int32 j = 0; j < manifold2->pointCount; ++j) { if (manifold2->points[j].id.key == id.key) { state1[i] = b2_persistState; break; } } } // Detect persists and adds. for (int32 i = 0; i < manifold2->pointCount; ++i) { b2ContactID id = manifold2->points[i].id; state2[i] = b2_addState; for (int32 j = 0; j < manifold1->pointCount; ++j) { if (manifold1->points[j].id.key == id.key) { state2[i] = b2_persistState; break; } } } } // From Real-time Collision Detection, p179. bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const { float32 tmin = -b2_maxFloat; float32 tmax = b2_maxFloat; b2Vec2 p = input.p1; b2Vec2 d = input.p2 - input.p1; b2Vec2 absD = b2Abs(d); b2Vec2 normal; for (int32 i = 0; i < 2; ++i) { if (absD(i) < b2_epsilon) { // Parallel. if (p(i) < lowerBound(i) || upperBound(i) < p(i)) { return false; } } else { float32 inv_d = 1.0f / d(i); float32 t1 = (lowerBound(i) - p(i)) * inv_d; float32 t2 = (upperBound(i) - p(i)) * inv_d; // Sign of the normal vector. float32 s = -1.0f; if (t1 > t2) { b2Swap(t1, t2); s = 1.0f; } // Push the min up if (t1 > tmin) { normal.SetZero(); normal(i) = s; tmin = t1; } // Pull the max down tmax = b2Min(tmax, t2); if (tmin > tmax) { return false; } } } // Does the ray start inside the box? // Does the ray intersect beyond the max fraction? if (tmin < 0.0f || input.maxFraction < tmin) { return false; } // Intersection. output->fraction = tmin; output->normal = normal; return true; } // Sutherland-Hodgman clipping. int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], const b2Vec2& normal, float32 offset, int32 vertexIndexA) { // Start with no output points int32 numOut = 0; // Calculate the distance of end points to the line float32 distance0 = b2Dot(normal, vIn[0].v) - offset; float32 distance1 = b2Dot(normal, vIn[1].v) - offset; // If the points are behind the plane if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; // If the points are on different sides of the plane if (distance0 * distance1 < 0.0f) { // Find intersection point of edge and plane float32 interp = distance0 / (distance0 - distance1); vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); // VertexA is hitting edgeB. vOut[numOut].id.cf.indexA = vertexIndexA; vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB; vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex; vOut[numOut].id.cf.typeB = b2ContactFeature::e_face; ++numOut; } return numOut; } bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, const b2Shape* shapeB, int32 indexB, const b2Transform& xfA, const b2Transform& xfB) { b2DistanceInput input; input.proxyA.Set(shapeA, indexA); input.proxyB.Set(shapeB, indexB); input.transformA = xfA; input.transformB = xfB; input.useRadii = true; b2SimplexCache cache; cache.count = 0; b2DistanceOutput output; b2Distance(&output, &cache, &input); return output.distance < 10.0f * b2_epsilon; } pybox2d-2.3.2/Box2D/Collision/b2Collision.h000066400000000000000000000214141276457661000203260ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_COLLISION_H #define B2_COLLISION_H #include #include /// @file /// Structures and functions used for computing contact points, distance /// queries, and TOI queries. class b2Shape; class b2CircleShape; class b2EdgeShape; class b2PolygonShape; const uint8 b2_nullFeature = UCHAR_MAX; /// The features that intersect to form the contact point /// This must be 4 bytes or less. struct b2ContactFeature { enum Type { e_vertex = 0, e_face = 1 }; uint8 indexA; ///< Feature index on shapeA uint8 indexB; ///< Feature index on shapeB uint8 typeA; ///< The feature type on shapeA uint8 typeB; ///< The feature type on shapeB }; /// Contact ids to facilitate warm starting. union b2ContactID { b2ContactFeature cf; uint32 key; ///< Used to quickly compare contact ids. }; /// A manifold point is a contact point belonging to a contact /// manifold. It holds details related to the geometry and dynamics /// of the contact points. /// The local point usage depends on the manifold type: /// -e_circles: the local center of circleB /// -e_faceA: the local center of cirlceB or the clip point of polygonB /// -e_faceB: the clip point of polygonA /// This structure is stored across time steps, so we keep it small. /// Note: the impulses are used for internal caching and may not /// provide reliable contact forces, especially for high speed collisions. struct b2ManifoldPoint { b2Vec2 localPoint; ///< usage depends on manifold type float32 normalImpulse; ///< the non-penetration impulse float32 tangentImpulse; ///< the friction impulse b2ContactID id; ///< uniquely identifies a contact point between two shapes }; /// A manifold for two touching convex shapes. /// Box2D supports multiple types of contact: /// - clip point versus plane with radius /// - point versus point with radius (circles) /// The local point usage depends on the manifold type: /// -e_circles: the local center of circleA /// -e_faceA: the center of faceA /// -e_faceB: the center of faceB /// Similarly the local normal usage: /// -e_circles: not used /// -e_faceA: the normal on polygonA /// -e_faceB: the normal on polygonB /// We store contacts in this way so that position correction can /// account for movement, which is critical for continuous physics. /// All contact scenarios must be expressed in one of these types. /// This structure is stored across time steps, so we keep it small. struct b2Manifold { enum Type { e_circles, e_faceA, e_faceB }; b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact b2Vec2 localNormal; ///< not use for Type::e_points b2Vec2 localPoint; ///< usage depends on manifold type Type type; int32 pointCount; ///< the number of manifold points }; /// This is used to compute the current state of a contact manifold. struct b2WorldManifold { /// Evaluate the manifold with supplied transforms. This assumes /// modest motion from the original state. This does not change the /// point count, impulses, etc. The radii must come from the shapes /// that generated the manifold. void Initialize(const b2Manifold* manifold, const b2Transform& xfA, float32 radiusA, const b2Transform& xfB, float32 radiusB); b2Vec2 normal; ///< world vector pointing from A to B b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection) }; /// This is used for determining the state of contact points. enum b2PointState { b2_nullState, ///< point does not exist b2_addState, ///< point was added in the update b2_persistState, ///< point persisted across the update b2_removeState ///< point was removed in the update }; /// Compute the point states given two manifolds. The states pertain to the transition from manifold1 /// to manifold2. So state1 is either persist or remove while state2 is either add or persist. void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], const b2Manifold* manifold1, const b2Manifold* manifold2); /// Used for computing contact manifolds. struct b2ClipVertex { b2Vec2 v; b2ContactID id; }; /// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). struct b2RayCastInput { b2Vec2 p1, p2; float32 maxFraction; }; /// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 /// come from b2RayCastInput. struct b2RayCastOutput { b2Vec2 normal; float32 fraction; }; /// An axis aligned bounding box. struct b2AABB { /// Verify that the bounds are sorted. bool IsValid() const; /// Get the center of the AABB. b2Vec2 GetCenter() const { return 0.5f * (lowerBound + upperBound); } /// Get the extents of the AABB (half-widths). b2Vec2 GetExtents() const { return 0.5f * (upperBound - lowerBound); } /// Get the perimeter length float32 GetPerimeter() const { float32 wx = upperBound.x - lowerBound.x; float32 wy = upperBound.y - lowerBound.y; return 2.0f * (wx + wy); } /// Combine an AABB into this one. void Combine(const b2AABB& aabb) { lowerBound = b2Min(lowerBound, aabb.lowerBound); upperBound = b2Max(upperBound, aabb.upperBound); } /// Combine two AABBs into this one. void Combine(const b2AABB& aabb1, const b2AABB& aabb2) { lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound); upperBound = b2Max(aabb1.upperBound, aabb2.upperBound); } /// Does this aabb contain the provided AABB. bool Contains(const b2AABB& aabb) const { bool result = true; result = result && lowerBound.x <= aabb.lowerBound.x; result = result && lowerBound.y <= aabb.lowerBound.y; result = result && aabb.upperBound.x <= upperBound.x; result = result && aabb.upperBound.y <= upperBound.y; return result; } bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const; b2Vec2 lowerBound; ///< the lower vertex b2Vec2 upperBound; ///< the upper vertex }; /// Compute the collision manifold between two circles. void b2CollideCircles(b2Manifold* manifold, const b2CircleShape* circleA, const b2Transform& xfA, const b2CircleShape* circleB, const b2Transform& xfB); /// Compute the collision manifold between a polygon and a circle. void b2CollidePolygonAndCircle(b2Manifold* manifold, const b2PolygonShape* polygonA, const b2Transform& xfA, const b2CircleShape* circleB, const b2Transform& xfB); /// Compute the collision manifold between two polygons. void b2CollidePolygons(b2Manifold* manifold, const b2PolygonShape* polygonA, const b2Transform& xfA, const b2PolygonShape* polygonB, const b2Transform& xfB); /// Compute the collision manifold between an edge and a circle. void b2CollideEdgeAndCircle(b2Manifold* manifold, const b2EdgeShape* polygonA, const b2Transform& xfA, const b2CircleShape* circleB, const b2Transform& xfB); /// Compute the collision manifold between an edge and a circle. void b2CollideEdgeAndPolygon(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA, const b2PolygonShape* circleB, const b2Transform& xfB); /// Clipping for contact manifolds. int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2], const b2Vec2& normal, float32 offset, int32 vertexIndexA); /// Determine if two generic shapes overlap. bool b2TestOverlap( const b2Shape* shapeA, int32 indexA, const b2Shape* shapeB, int32 indexB, const b2Transform& xfA, const b2Transform& xfB); // ---------------- Inline Functions ------------------------------------------ inline bool b2AABB::IsValid() const { b2Vec2 d = upperBound - lowerBound; bool valid = d.x >= 0.0f && d.y >= 0.0f; valid = valid && lowerBound.IsValid() && upperBound.IsValid(); return valid; } inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) { b2Vec2 d1, d2; d1 = b.lowerBound - a.upperBound; d2 = a.lowerBound - b.upperBound; if (d1.x > 0.0f || d1.y > 0.0f) return false; if (d2.x > 0.0f || d2.y > 0.0f) return false; return true; } #endif pybox2d-2.3.2/Box2D/Collision/b2Distance.cpp000066400000000000000000000315161276457661000204640ustar00rootroot00000000000000/* * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include // GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates. int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; void b2DistanceProxy::Set(const b2Shape* shape, int32 index) { switch (shape->GetType()) { case b2Shape::e_circle: { const b2CircleShape* circle = (b2CircleShape*)shape; m_vertices = &circle->m_p; m_count = 1; m_radius = circle->m_radius; } break; case b2Shape::e_polygon: { const b2PolygonShape* polygon = (b2PolygonShape*)shape; m_vertices = polygon->m_vertices; m_count = polygon->m_count; m_radius = polygon->m_radius; } break; case b2Shape::e_chain: { const b2ChainShape* chain = (b2ChainShape*)shape; b2Assert(0 <= index && index < chain->m_count); m_buffer[0] = chain->m_vertices[index]; if (index + 1 < chain->m_count) { m_buffer[1] = chain->m_vertices[index + 1]; } else { m_buffer[1] = chain->m_vertices[0]; } m_vertices = m_buffer; m_count = 2; m_radius = chain->m_radius; } break; case b2Shape::e_edge: { const b2EdgeShape* edge = (b2EdgeShape*)shape; m_vertices = &edge->m_vertex1; m_count = 2; m_radius = edge->m_radius; } break; default: b2Assert(false); } } struct b2SimplexVertex { b2Vec2 wA; // support point in proxyA b2Vec2 wB; // support point in proxyB b2Vec2 w; // wB - wA float32 a; // barycentric coordinate for closest point int32 indexA; // wA index int32 indexB; // wB index }; struct b2Simplex { void ReadCache( const b2SimplexCache* cache, const b2DistanceProxy* proxyA, const b2Transform& transformA, const b2DistanceProxy* proxyB, const b2Transform& transformB) { b2Assert(cache->count <= 3); // Copy data from cache. m_count = cache->count; b2SimplexVertex* vertices = &m_v1; for (int32 i = 0; i < m_count; ++i) { b2SimplexVertex* v = vertices + i; v->indexA = cache->indexA[i]; v->indexB = cache->indexB[i]; b2Vec2 wALocal = proxyA->GetVertex(v->indexA); b2Vec2 wBLocal = proxyB->GetVertex(v->indexB); v->wA = b2Mul(transformA, wALocal); v->wB = b2Mul(transformB, wBLocal); v->w = v->wB - v->wA; v->a = 0.0f; } // Compute the new simplex metric, if it is substantially different than // old metric then flush the simplex. if (m_count > 1) { float32 metric1 = cache->metric; float32 metric2 = GetMetric(); if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon) { // Reset the simplex. m_count = 0; } } // If the cache is empty or invalid ... if (m_count == 0) { b2SimplexVertex* v = vertices + 0; v->indexA = 0; v->indexB = 0; b2Vec2 wALocal = proxyA->GetVertex(0); b2Vec2 wBLocal = proxyB->GetVertex(0); v->wA = b2Mul(transformA, wALocal); v->wB = b2Mul(transformB, wBLocal); v->w = v->wB - v->wA; v->a = 1.0f; m_count = 1; } } void WriteCache(b2SimplexCache* cache) const { cache->metric = GetMetric(); cache->count = uint16(m_count); const b2SimplexVertex* vertices = &m_v1; for (int32 i = 0; i < m_count; ++i) { cache->indexA[i] = uint8(vertices[i].indexA); cache->indexB[i] = uint8(vertices[i].indexB); } } b2Vec2 GetSearchDirection() const { switch (m_count) { case 1: return -m_v1.w; case 2: { b2Vec2 e12 = m_v2.w - m_v1.w; float32 sgn = b2Cross(e12, -m_v1.w); if (sgn > 0.0f) { // Origin is left of e12. return b2Cross(1.0f, e12); } else { // Origin is right of e12. return b2Cross(e12, 1.0f); } } default: b2Assert(false); return b2Vec2_zero; } } b2Vec2 GetClosestPoint() const { switch (m_count) { case 0: b2Assert(false); return b2Vec2_zero; case 1: return m_v1.w; case 2: return m_v1.a * m_v1.w + m_v2.a * m_v2.w; case 3: return b2Vec2_zero; default: b2Assert(false); return b2Vec2_zero; } } void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const { switch (m_count) { case 0: b2Assert(false); break; case 1: *pA = m_v1.wA; *pB = m_v1.wB; break; case 2: *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA; *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB; break; case 3: *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA; *pB = *pA; break; default: b2Assert(false); break; } } float32 GetMetric() const { switch (m_count) { case 0: b2Assert(false); return 0.0f; case 1: return 0.0f; case 2: return b2Distance(m_v1.w, m_v2.w); case 3: return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w); default: b2Assert(false); return 0.0f; } } void Solve2(); void Solve3(); b2SimplexVertex m_v1, m_v2, m_v3; int32 m_count; }; // Solve a line segment using barycentric coordinates. // // p = a1 * w1 + a2 * w2 // a1 + a2 = 1 // // The vector from the origin to the closest point on the line is // perpendicular to the line. // e12 = w2 - w1 // dot(p, e) = 0 // a1 * dot(w1, e) + a2 * dot(w2, e) = 0 // // 2-by-2 linear system // [1 1 ][a1] = [1] // [w1.e12 w2.e12][a2] = [0] // // Define // d12_1 = dot(w2, e12) // d12_2 = -dot(w1, e12) // d12 = d12_1 + d12_2 // // Solution // a1 = d12_1 / d12 // a2 = d12_2 / d12 void b2Simplex::Solve2() { b2Vec2 w1 = m_v1.w; b2Vec2 w2 = m_v2.w; b2Vec2 e12 = w2 - w1; // w1 region float32 d12_2 = -b2Dot(w1, e12); if (d12_2 <= 0.0f) { // a2 <= 0, so we clamp it to 0 m_v1.a = 1.0f; m_count = 1; return; } // w2 region float32 d12_1 = b2Dot(w2, e12); if (d12_1 <= 0.0f) { // a1 <= 0, so we clamp it to 0 m_v2.a = 1.0f; m_count = 1; m_v1 = m_v2; return; } // Must be in e12 region. float32 inv_d12 = 1.0f / (d12_1 + d12_2); m_v1.a = d12_1 * inv_d12; m_v2.a = d12_2 * inv_d12; m_count = 2; } // Possible regions: // - points[2] // - edge points[0]-points[2] // - edge points[1]-points[2] // - inside the triangle void b2Simplex::Solve3() { b2Vec2 w1 = m_v1.w; b2Vec2 w2 = m_v2.w; b2Vec2 w3 = m_v3.w; // Edge12 // [1 1 ][a1] = [1] // [w1.e12 w2.e12][a2] = [0] // a3 = 0 b2Vec2 e12 = w2 - w1; float32 w1e12 = b2Dot(w1, e12); float32 w2e12 = b2Dot(w2, e12); float32 d12_1 = w2e12; float32 d12_2 = -w1e12; // Edge13 // [1 1 ][a1] = [1] // [w1.e13 w3.e13][a3] = [0] // a2 = 0 b2Vec2 e13 = w3 - w1; float32 w1e13 = b2Dot(w1, e13); float32 w3e13 = b2Dot(w3, e13); float32 d13_1 = w3e13; float32 d13_2 = -w1e13; // Edge23 // [1 1 ][a2] = [1] // [w2.e23 w3.e23][a3] = [0] // a1 = 0 b2Vec2 e23 = w3 - w2; float32 w2e23 = b2Dot(w2, e23); float32 w3e23 = b2Dot(w3, e23); float32 d23_1 = w3e23; float32 d23_2 = -w2e23; // Triangle123 float32 n123 = b2Cross(e12, e13); float32 d123_1 = n123 * b2Cross(w2, w3); float32 d123_2 = n123 * b2Cross(w3, w1); float32 d123_3 = n123 * b2Cross(w1, w2); // w1 region if (d12_2 <= 0.0f && d13_2 <= 0.0f) { m_v1.a = 1.0f; m_count = 1; return; } // e12 if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f) { float32 inv_d12 = 1.0f / (d12_1 + d12_2); m_v1.a = d12_1 * inv_d12; m_v2.a = d12_2 * inv_d12; m_count = 2; return; } // e13 if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f) { float32 inv_d13 = 1.0f / (d13_1 + d13_2); m_v1.a = d13_1 * inv_d13; m_v3.a = d13_2 * inv_d13; m_count = 2; m_v2 = m_v3; return; } // w2 region if (d12_1 <= 0.0f && d23_2 <= 0.0f) { m_v2.a = 1.0f; m_count = 1; m_v1 = m_v2; return; } // w3 region if (d13_1 <= 0.0f && d23_1 <= 0.0f) { m_v3.a = 1.0f; m_count = 1; m_v1 = m_v3; return; } // e23 if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f) { float32 inv_d23 = 1.0f / (d23_1 + d23_2); m_v2.a = d23_1 * inv_d23; m_v3.a = d23_2 * inv_d23; m_count = 2; m_v1 = m_v3; return; } // Must be in triangle123 float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3); m_v1.a = d123_1 * inv_d123; m_v2.a = d123_2 * inv_d123; m_v3.a = d123_3 * inv_d123; m_count = 3; } void b2Distance(b2DistanceOutput* output, b2SimplexCache* cache, const b2DistanceInput* input) { ++b2_gjkCalls; const b2DistanceProxy* proxyA = &input->proxyA; const b2DistanceProxy* proxyB = &input->proxyB; b2Transform transformA = input->transformA; b2Transform transformB = input->transformB; // Initialize the simplex. b2Simplex simplex; simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); // Get simplex vertices as an array. b2SimplexVertex* vertices = &simplex.m_v1; const int32 k_maxIters = 20; // These store the vertices of the last simplex so that we // can check for duplicates and prevent cycling. int32 saveA[3], saveB[3]; int32 saveCount = 0; float32 distanceSqr1 = b2_maxFloat; float32 distanceSqr2 = distanceSqr1; // Main iteration loop. int32 iter = 0; while (iter < k_maxIters) { // Copy simplex so we can identify duplicates. saveCount = simplex.m_count; for (int32 i = 0; i < saveCount; ++i) { saveA[i] = vertices[i].indexA; saveB[i] = vertices[i].indexB; } switch (simplex.m_count) { case 1: break; case 2: simplex.Solve2(); break; case 3: simplex.Solve3(); break; default: b2Assert(false); } // If we have 3 points, then the origin is in the corresponding triangle. if (simplex.m_count == 3) { break; } // Compute closest point. b2Vec2 p = simplex.GetClosestPoint(); distanceSqr2 = p.LengthSquared(); // Ensure progress if (distanceSqr2 >= distanceSqr1) { //break; } distanceSqr1 = distanceSqr2; // Get search direction. b2Vec2 d = simplex.GetSearchDirection(); // Ensure the search direction is numerically fit. if (d.LengthSquared() < b2_epsilon * b2_epsilon) { // The origin is probably contained by a line segment // or triangle. Thus the shapes are overlapped. // We can't return zero here even though there may be overlap. // In case the simplex is a point, segment, or triangle it is difficult // to determine if the origin is contained in the CSO or very close to it. break; } // Compute a tentative new simplex vertex using support points. b2SimplexVertex* vertex = vertices + simplex.m_count; vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d)); vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA)); b2Vec2 wBLocal; vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d)); vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB)); vertex->w = vertex->wB - vertex->wA; // Iteration count is equated to the number of support point calls. ++iter; ++b2_gjkIters; // Check for duplicate support points. This is the main termination criteria. bool duplicate = false; for (int32 i = 0; i < saveCount; ++i) { if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i]) { duplicate = true; break; } } // If we found a duplicate support point we must exit to avoid cycling. if (duplicate) { break; } // New vertex is ok and needed. ++simplex.m_count; } b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter); // Prepare output. simplex.GetWitnessPoints(&output->pointA, &output->pointB); output->distance = b2Distance(output->pointA, output->pointB); output->iterations = iter; // Cache the simplex. simplex.WriteCache(cache); // Apply radii if requested. if (input->useRadii) { float32 rA = proxyA->m_radius; float32 rB = proxyB->m_radius; if (output->distance > rA + rB && output->distance > b2_epsilon) { // Shapes are still no overlapped. // Move the witness points to the outer surface. output->distance -= rA + rB; b2Vec2 normal = output->pointB - output->pointA; normal.Normalize(); output->pointA += rA * normal; output->pointB -= rB * normal; } else { // Shapes are overlapped when radii are considered. // Move the witness points to the middle. b2Vec2 p = 0.5f * (output->pointA + output->pointB); output->pointA = p; output->pointB = p; output->distance = 0.0f; } } } pybox2d-2.3.2/Box2D/Collision/b2Distance.h000066400000000000000000000073011276457661000201240ustar00rootroot00000000000000 /* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_DISTANCE_H #define B2_DISTANCE_H #include class b2Shape; /// A distance proxy is used by the GJK algorithm. /// It encapsulates any shape. struct b2DistanceProxy { b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {} /// Initialize the proxy using the given shape. The shape /// must remain in scope while the proxy is in use. void Set(const b2Shape* shape, int32 index); /// Get the supporting vertex index in the given direction. int32 GetSupport(const b2Vec2& d) const; /// Get the supporting vertex in the given direction. const b2Vec2& GetSupportVertex(const b2Vec2& d) const; /// Get the vertex count. int32 GetVertexCount() const; /// Get a vertex by index. Used by b2Distance. const b2Vec2& GetVertex(int32 index) const; b2Vec2 m_buffer[2]; const b2Vec2* m_vertices; int32 m_count; float32 m_radius; }; /// Used to warm start b2Distance. /// Set count to zero on first call. struct b2SimplexCache { float32 metric; ///< length or area uint16 count; uint8 indexA[3]; ///< vertices on shape A uint8 indexB[3]; ///< vertices on shape B }; /// Input for b2Distance. /// You have to option to use the shape radii /// in the computation. Even struct b2DistanceInput { b2DistanceProxy proxyA; b2DistanceProxy proxyB; b2Transform transformA; b2Transform transformB; bool useRadii; }; /// Output for b2Distance. struct b2DistanceOutput { b2Vec2 pointA; ///< closest point on shapeA b2Vec2 pointB; ///< closest point on shapeB float32 distance; int32 iterations; ///< number of GJK iterations used }; /// Compute the closest points between two shapes. Supports any combination of: /// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output. /// On the first call set b2SimplexCache.count to zero. void b2Distance(b2DistanceOutput* output, b2SimplexCache* cache, const b2DistanceInput* input); ////////////////////////////////////////////////////////////////////////// inline int32 b2DistanceProxy::GetVertexCount() const { return m_count; } inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const { b2Assert(0 <= index && index < m_count); return m_vertices[index]; } inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const { int32 bestIndex = 0; float32 bestValue = b2Dot(m_vertices[0], d); for (int32 i = 1; i < m_count; ++i) { float32 value = b2Dot(m_vertices[i], d); if (value > bestValue) { bestIndex = i; bestValue = value; } } return bestIndex; } inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const { int32 bestIndex = 0; float32 bestValue = b2Dot(m_vertices[0], d); for (int32 i = 1; i < m_count; ++i) { float32 value = b2Dot(m_vertices[i], d); if (value > bestValue) { bestIndex = i; bestValue = value; } } return m_vertices[bestIndex]; } #endif pybox2d-2.3.2/Box2D/Collision/b2DynamicTree.cpp000066400000000000000000000410151276457661000211310ustar00rootroot00000000000000/* * Copyright (c) 2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include using namespace std; b2DynamicTree::b2DynamicTree() { m_root = b2_nullNode; m_nodeCapacity = 16; m_nodeCount = 0; m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode)); // Build a linked list for the free list. for (int32 i = 0; i < m_nodeCapacity - 1; ++i) { m_nodes[i].next = i + 1; m_nodes[i].height = -1; } m_nodes[m_nodeCapacity-1].next = b2_nullNode; m_nodes[m_nodeCapacity-1].height = -1; m_freeList = 0; m_path = 0; m_insertionCount = 0; } b2DynamicTree::~b2DynamicTree() { // This frees the entire tree in one shot. b2Free(m_nodes); } // Allocate a node from the pool. Grow the pool if necessary. int32 b2DynamicTree::AllocateNode() { // Expand the node pool as needed. if (m_freeList == b2_nullNode) { b2Assert(m_nodeCount == m_nodeCapacity); // The free list is empty. Rebuild a bigger pool. b2TreeNode* oldNodes = m_nodes; m_nodeCapacity *= 2; m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode)); memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode)); b2Free(oldNodes); // Build a linked list for the free list. The parent // pointer becomes the "next" pointer. for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i) { m_nodes[i].next = i + 1; m_nodes[i].height = -1; } m_nodes[m_nodeCapacity-1].next = b2_nullNode; m_nodes[m_nodeCapacity-1].height = -1; m_freeList = m_nodeCount; } // Peel a node off the free list. int32 nodeId = m_freeList; m_freeList = m_nodes[nodeId].next; m_nodes[nodeId].parent = b2_nullNode; m_nodes[nodeId].child1 = b2_nullNode; m_nodes[nodeId].child2 = b2_nullNode; m_nodes[nodeId].height = 0; m_nodes[nodeId].userData = NULL; ++m_nodeCount; return nodeId; } // Return a node to the pool. void b2DynamicTree::FreeNode(int32 nodeId) { b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); b2Assert(0 < m_nodeCount); m_nodes[nodeId].next = m_freeList; m_nodes[nodeId].height = -1; m_freeList = nodeId; --m_nodeCount; } // Create a proxy in the tree as a leaf node. We return the index // of the node instead of a pointer so that we can grow // the node pool. int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) { int32 proxyId = AllocateNode(); // Fatten the aabb. b2Vec2 r(b2_aabbExtension, b2_aabbExtension); m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r; m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r; m_nodes[proxyId].userData = userData; m_nodes[proxyId].height = 0; InsertLeaf(proxyId); return proxyId; } void b2DynamicTree::DestroyProxy(int32 proxyId) { b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); b2Assert(m_nodes[proxyId].IsLeaf()); RemoveLeaf(proxyId); FreeNode(proxyId); } bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement) { b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); b2Assert(m_nodes[proxyId].IsLeaf()); if (m_nodes[proxyId].aabb.Contains(aabb)) { return false; } RemoveLeaf(proxyId); // Extend AABB. b2AABB b = aabb; b2Vec2 r(b2_aabbExtension, b2_aabbExtension); b.lowerBound = b.lowerBound - r; b.upperBound = b.upperBound + r; // Predict AABB displacement. b2Vec2 d = b2_aabbMultiplier * displacement; if (d.x < 0.0f) { b.lowerBound.x += d.x; } else { b.upperBound.x += d.x; } if (d.y < 0.0f) { b.lowerBound.y += d.y; } else { b.upperBound.y += d.y; } m_nodes[proxyId].aabb = b; InsertLeaf(proxyId); return true; } void b2DynamicTree::InsertLeaf(int32 leaf) { ++m_insertionCount; if (m_root == b2_nullNode) { m_root = leaf; m_nodes[m_root].parent = b2_nullNode; return; } // Find the best sibling for this node b2AABB leafAABB = m_nodes[leaf].aabb; int32 index = m_root; while (m_nodes[index].IsLeaf() == false) { int32 child1 = m_nodes[index].child1; int32 child2 = m_nodes[index].child2; float32 area = m_nodes[index].aabb.GetPerimeter(); b2AABB combinedAABB; combinedAABB.Combine(m_nodes[index].aabb, leafAABB); float32 combinedArea = combinedAABB.GetPerimeter(); // Cost of creating a new parent for this node and the new leaf float32 cost = 2.0f * combinedArea; // Minimum cost of pushing the leaf further down the tree float32 inheritanceCost = 2.0f * (combinedArea - area); // Cost of descending into child1 float32 cost1; if (m_nodes[child1].IsLeaf()) { b2AABB aabb; aabb.Combine(leafAABB, m_nodes[child1].aabb); cost1 = aabb.GetPerimeter() + inheritanceCost; } else { b2AABB aabb; aabb.Combine(leafAABB, m_nodes[child1].aabb); float32 oldArea = m_nodes[child1].aabb.GetPerimeter(); float32 newArea = aabb.GetPerimeter(); cost1 = (newArea - oldArea) + inheritanceCost; } // Cost of descending into child2 float32 cost2; if (m_nodes[child2].IsLeaf()) { b2AABB aabb; aabb.Combine(leafAABB, m_nodes[child2].aabb); cost2 = aabb.GetPerimeter() + inheritanceCost; } else { b2AABB aabb; aabb.Combine(leafAABB, m_nodes[child2].aabb); float32 oldArea = m_nodes[child2].aabb.GetPerimeter(); float32 newArea = aabb.GetPerimeter(); cost2 = newArea - oldArea + inheritanceCost; } // Descend according to the minimum cost. if (cost < cost1 && cost < cost2) { break; } // Descend if (cost1 < cost2) { index = child1; } else { index = child2; } } int32 sibling = index; // Create a new parent. int32 oldParent = m_nodes[sibling].parent; int32 newParent = AllocateNode(); m_nodes[newParent].parent = oldParent; m_nodes[newParent].userData = NULL; m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb); m_nodes[newParent].height = m_nodes[sibling].height + 1; if (oldParent != b2_nullNode) { // The sibling was not the root. if (m_nodes[oldParent].child1 == sibling) { m_nodes[oldParent].child1 = newParent; } else { m_nodes[oldParent].child2 = newParent; } m_nodes[newParent].child1 = sibling; m_nodes[newParent].child2 = leaf; m_nodes[sibling].parent = newParent; m_nodes[leaf].parent = newParent; } else { // The sibling was the root. m_nodes[newParent].child1 = sibling; m_nodes[newParent].child2 = leaf; m_nodes[sibling].parent = newParent; m_nodes[leaf].parent = newParent; m_root = newParent; } // Walk back up the tree fixing heights and AABBs index = m_nodes[leaf].parent; while (index != b2_nullNode) { index = Balance(index); int32 child1 = m_nodes[index].child1; int32 child2 = m_nodes[index].child2; b2Assert(child1 != b2_nullNode); b2Assert(child2 != b2_nullNode); m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); index = m_nodes[index].parent; } //Validate(); } void b2DynamicTree::RemoveLeaf(int32 leaf) { if (leaf == m_root) { m_root = b2_nullNode; return; } int32 parent = m_nodes[leaf].parent; int32 grandParent = m_nodes[parent].parent; int32 sibling; if (m_nodes[parent].child1 == leaf) { sibling = m_nodes[parent].child2; } else { sibling = m_nodes[parent].child1; } if (grandParent != b2_nullNode) { // Destroy parent and connect sibling to grandParent. if (m_nodes[grandParent].child1 == parent) { m_nodes[grandParent].child1 = sibling; } else { m_nodes[grandParent].child2 = sibling; } m_nodes[sibling].parent = grandParent; FreeNode(parent); // Adjust ancestor bounds. int32 index = grandParent; while (index != b2_nullNode) { index = Balance(index); int32 child1 = m_nodes[index].child1; int32 child2 = m_nodes[index].child2; m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height); index = m_nodes[index].parent; } } else { m_root = sibling; m_nodes[sibling].parent = b2_nullNode; FreeNode(parent); } //Validate(); } // Perform a left or right rotation if node A is imbalanced. // Returns the new root index. int32 b2DynamicTree::Balance(int32 iA) { b2Assert(iA != b2_nullNode); b2TreeNode* A = m_nodes + iA; if (A->IsLeaf() || A->height < 2) { return iA; } int32 iB = A->child1; int32 iC = A->child2; b2Assert(0 <= iB && iB < m_nodeCapacity); b2Assert(0 <= iC && iC < m_nodeCapacity); b2TreeNode* B = m_nodes + iB; b2TreeNode* C = m_nodes + iC; int32 balance = C->height - B->height; // Rotate C up if (balance > 1) { int32 iF = C->child1; int32 iG = C->child2; b2TreeNode* F = m_nodes + iF; b2TreeNode* G = m_nodes + iG; b2Assert(0 <= iF && iF < m_nodeCapacity); b2Assert(0 <= iG && iG < m_nodeCapacity); // Swap A and C C->child1 = iA; C->parent = A->parent; A->parent = iC; // A's old parent should point to C if (C->parent != b2_nullNode) { if (m_nodes[C->parent].child1 == iA) { m_nodes[C->parent].child1 = iC; } else { b2Assert(m_nodes[C->parent].child2 == iA); m_nodes[C->parent].child2 = iC; } } else { m_root = iC; } // Rotate if (F->height > G->height) { C->child2 = iF; A->child2 = iG; G->parent = iA; A->aabb.Combine(B->aabb, G->aabb); C->aabb.Combine(A->aabb, F->aabb); A->height = 1 + b2Max(B->height, G->height); C->height = 1 + b2Max(A->height, F->height); } else { C->child2 = iG; A->child2 = iF; F->parent = iA; A->aabb.Combine(B->aabb, F->aabb); C->aabb.Combine(A->aabb, G->aabb); A->height = 1 + b2Max(B->height, F->height); C->height = 1 + b2Max(A->height, G->height); } return iC; } // Rotate B up if (balance < -1) { int32 iD = B->child1; int32 iE = B->child2; b2TreeNode* D = m_nodes + iD; b2TreeNode* E = m_nodes + iE; b2Assert(0 <= iD && iD < m_nodeCapacity); b2Assert(0 <= iE && iE < m_nodeCapacity); // Swap A and B B->child1 = iA; B->parent = A->parent; A->parent = iB; // A's old parent should point to B if (B->parent != b2_nullNode) { if (m_nodes[B->parent].child1 == iA) { m_nodes[B->parent].child1 = iB; } else { b2Assert(m_nodes[B->parent].child2 == iA); m_nodes[B->parent].child2 = iB; } } else { m_root = iB; } // Rotate if (D->height > E->height) { B->child2 = iD; A->child1 = iE; E->parent = iA; A->aabb.Combine(C->aabb, E->aabb); B->aabb.Combine(A->aabb, D->aabb); A->height = 1 + b2Max(C->height, E->height); B->height = 1 + b2Max(A->height, D->height); } else { B->child2 = iE; A->child1 = iD; D->parent = iA; A->aabb.Combine(C->aabb, D->aabb); B->aabb.Combine(A->aabb, E->aabb); A->height = 1 + b2Max(C->height, D->height); B->height = 1 + b2Max(A->height, E->height); } return iB; } return iA; } int32 b2DynamicTree::GetHeight() const { if (m_root == b2_nullNode) { return 0; } return m_nodes[m_root].height; } // float32 b2DynamicTree::GetAreaRatio() const { if (m_root == b2_nullNode) { return 0.0f; } const b2TreeNode* root = m_nodes + m_root; float32 rootArea = root->aabb.GetPerimeter(); float32 totalArea = 0.0f; for (int32 i = 0; i < m_nodeCapacity; ++i) { const b2TreeNode* node = m_nodes + i; if (node->height < 0) { // Free node in pool continue; } totalArea += node->aabb.GetPerimeter(); } return totalArea / rootArea; } // Compute the height of a sub-tree. int32 b2DynamicTree::ComputeHeight(int32 nodeId) const { b2Assert(0 <= nodeId && nodeId < m_nodeCapacity); b2TreeNode* node = m_nodes + nodeId; if (node->IsLeaf()) { return 0; } int32 height1 = ComputeHeight(node->child1); int32 height2 = ComputeHeight(node->child2); return 1 + b2Max(height1, height2); } int32 b2DynamicTree::ComputeHeight() const { int32 height = ComputeHeight(m_root); return height; } void b2DynamicTree::ValidateStructure(int32 index) const { if (index == b2_nullNode) { return; } if (index == m_root) { b2Assert(m_nodes[index].parent == b2_nullNode); } const b2TreeNode* node = m_nodes + index; int32 child1 = node->child1; int32 child2 = node->child2; if (node->IsLeaf()) { b2Assert(child1 == b2_nullNode); b2Assert(child2 == b2_nullNode); b2Assert(node->height == 0); return; } b2Assert(0 <= child1 && child1 < m_nodeCapacity); b2Assert(0 <= child2 && child2 < m_nodeCapacity); b2Assert(m_nodes[child1].parent == index); b2Assert(m_nodes[child2].parent == index); ValidateStructure(child1); ValidateStructure(child2); } void b2DynamicTree::ValidateMetrics(int32 index) const { if (index == b2_nullNode) { return; } const b2TreeNode* node = m_nodes + index; int32 child1 = node->child1; int32 child2 = node->child2; if (node->IsLeaf()) { b2Assert(child1 == b2_nullNode); b2Assert(child2 == b2_nullNode); b2Assert(node->height == 0); return; } b2Assert(0 <= child1 && child1 < m_nodeCapacity); b2Assert(0 <= child2 && child2 < m_nodeCapacity); int32 height1 = m_nodes[child1].height; int32 height2 = m_nodes[child2].height; int32 height; height = 1 + b2Max(height1, height2); b2Assert(node->height == height); b2AABB aabb; aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb); b2Assert(aabb.lowerBound == node->aabb.lowerBound); b2Assert(aabb.upperBound == node->aabb.upperBound); ValidateMetrics(child1); ValidateMetrics(child2); } void b2DynamicTree::Validate() const { ValidateStructure(m_root); ValidateMetrics(m_root); int32 freeCount = 0; int32 freeIndex = m_freeList; while (freeIndex != b2_nullNode) { b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity); freeIndex = m_nodes[freeIndex].next; ++freeCount; } b2Assert(GetHeight() == ComputeHeight()); b2Assert(m_nodeCount + freeCount == m_nodeCapacity); } int32 b2DynamicTree::GetMaxBalance() const { int32 maxBalance = 0; for (int32 i = 0; i < m_nodeCapacity; ++i) { const b2TreeNode* node = m_nodes + i; if (node->height <= 1) { continue; } b2Assert(node->IsLeaf() == false); int32 child1 = node->child1; int32 child2 = node->child2; int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height); maxBalance = b2Max(maxBalance, balance); } return maxBalance; } void b2DynamicTree::RebuildBottomUp() { int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32)); int32 count = 0; // Build array of leaves. Free the rest. for (int32 i = 0; i < m_nodeCapacity; ++i) { if (m_nodes[i].height < 0) { // free node in pool continue; } if (m_nodes[i].IsLeaf()) { m_nodes[i].parent = b2_nullNode; nodes[count] = i; ++count; } else { FreeNode(i); } } while (count > 1) { float32 minCost = b2_maxFloat; int32 iMin = -1, jMin = -1; for (int32 i = 0; i < count; ++i) { b2AABB aabbi = m_nodes[nodes[i]].aabb; for (int32 j = i + 1; j < count; ++j) { b2AABB aabbj = m_nodes[nodes[j]].aabb; b2AABB b; b.Combine(aabbi, aabbj); float32 cost = b.GetPerimeter(); if (cost < minCost) { iMin = i; jMin = j; minCost = cost; } } } int32 index1 = nodes[iMin]; int32 index2 = nodes[jMin]; b2TreeNode* child1 = m_nodes + index1; b2TreeNode* child2 = m_nodes + index2; int32 parentIndex = AllocateNode(); b2TreeNode* parent = m_nodes + parentIndex; parent->child1 = index1; parent->child2 = index2; parent->height = 1 + b2Max(child1->height, child2->height); parent->aabb.Combine(child1->aabb, child2->aabb); parent->parent = b2_nullNode; child1->parent = parentIndex; child2->parent = parentIndex; nodes[jMin] = nodes[count-1]; nodes[iMin] = parentIndex; --count; } m_root = nodes[0]; b2Free(nodes); Validate(); } void b2DynamicTree::ShiftOrigin(const b2Vec2& newOrigin) { // Build array of leaves. Free the rest. for (int32 i = 0; i < m_nodeCapacity; ++i) { m_nodes[i].aabb.lowerBound -= newOrigin; m_nodes[i].aabb.upperBound -= newOrigin; } } pybox2d-2.3.2/Box2D/Collision/b2DynamicTree.h000066400000000000000000000167761276457661000206160ustar00rootroot00000000000000/* * Copyright (c) 2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_DYNAMIC_TREE_H #define B2_DYNAMIC_TREE_H #include #include #define b2_nullNode (-1) /// A node in the dynamic tree. The client does not interact with this directly. struct b2TreeNode { bool IsLeaf() const { return child1 == b2_nullNode; } /// Enlarged AABB b2AABB aabb; void* userData; union { int32 parent; int32 next; }; int32 child1; int32 child2; // leaf = 0, free node = -1 int32 height; }; /// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. /// A dynamic tree arranges data in a binary tree to accelerate /// queries such as volume queries and ray casts. Leafs are proxies /// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor /// so that the proxy AABB is bigger than the client object. This allows the client /// object to move by small amounts without triggering a tree update. /// /// Nodes are pooled and relocatable, so we use node indices rather than pointers. class b2DynamicTree { public: /// Constructing the tree initializes the node pool. b2DynamicTree(); /// Destroy the tree, freeing the node pool. ~b2DynamicTree(); /// Create a proxy. Provide a tight fitting AABB and a userData pointer. int32 CreateProxy(const b2AABB& aabb, void* userData); /// Destroy a proxy. This asserts if the id is invalid. void DestroyProxy(int32 proxyId); /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB, /// then the proxy is removed from the tree and re-inserted. Otherwise /// the function returns immediately. /// @return true if the proxy was re-inserted. bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement); /// Get proxy user data. /// @return the proxy user data or 0 if the id is invalid. void* GetUserData(int32 proxyId) const; /// Get the fat AABB for a proxy. const b2AABB& GetFatAABB(int32 proxyId) const; /// Query an AABB for overlapping proxies. The callback class /// is called for each proxy that overlaps the supplied AABB. template void Query(T* callback, const b2AABB& aabb) const; /// Ray-cast against the proxies in the tree. This relies on the callback /// to perform a exact ray-cast in the case were the proxy contains a shape. /// The callback also performs the any collision filtering. This has performance /// roughly equal to k * log(n), where k is the number of collisions and n is the /// number of proxies in the tree. /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). /// @param callback a callback class that is called for each proxy that is hit by the ray. template void RayCast(T* callback, const b2RayCastInput& input) const; /// Validate this tree. For testing. void Validate() const; /// Compute the height of the binary tree in O(N) time. Should not be /// called often. int32 GetHeight() const; /// Get the maximum balance of an node in the tree. The balance is the difference /// in height of the two children of a node. int32 GetMaxBalance() const; /// Get the ratio of the sum of the node areas to the root area. float32 GetAreaRatio() const; /// Build an optimal tree. Very expensive. For testing. void RebuildBottomUp(); /// Shift the world origin. Useful for large worlds. /// The shift formula is: position -= newOrigin /// @param newOrigin the new origin with respect to the old origin void ShiftOrigin(const b2Vec2& newOrigin); private: int32 AllocateNode(); void FreeNode(int32 node); void InsertLeaf(int32 node); void RemoveLeaf(int32 node); int32 Balance(int32 index); int32 ComputeHeight() const; int32 ComputeHeight(int32 nodeId) const; void ValidateStructure(int32 index) const; void ValidateMetrics(int32 index) const; int32 m_root; b2TreeNode* m_nodes; int32 m_nodeCount; int32 m_nodeCapacity; int32 m_freeList; /// This is used to incrementally traverse the tree for re-balancing. uint32 m_path; int32 m_insertionCount; }; inline void* b2DynamicTree::GetUserData(int32 proxyId) const { b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); return m_nodes[proxyId].userData; } inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const { b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); return m_nodes[proxyId].aabb; } template inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const { b2GrowableStack stack; stack.Push(m_root); while (stack.GetCount() > 0) { int32 nodeId = stack.Pop(); if (nodeId == b2_nullNode) { continue; } const b2TreeNode* node = m_nodes + nodeId; if (b2TestOverlap(node->aabb, aabb)) { if (node->IsLeaf()) { bool proceed = callback->QueryCallback(nodeId); if (proceed == false) { return; } } else { stack.Push(node->child1); stack.Push(node->child2); } } } } template inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const { b2Vec2 p1 = input.p1; b2Vec2 p2 = input.p2; b2Vec2 r = p2 - p1; b2Assert(r.LengthSquared() > 0.0f); r.Normalize(); // v is perpendicular to the segment. b2Vec2 v = b2Cross(1.0f, r); b2Vec2 abs_v = b2Abs(v); // Separating axis for segment (Gino, p80). // |dot(v, p1 - c)| > dot(|v|, h) float32 maxFraction = input.maxFraction; // Build a bounding box for the segment. b2AABB segmentAABB; { b2Vec2 t = p1 + maxFraction * (p2 - p1); segmentAABB.lowerBound = b2Min(p1, t); segmentAABB.upperBound = b2Max(p1, t); } b2GrowableStack stack; stack.Push(m_root); while (stack.GetCount() > 0) { int32 nodeId = stack.Pop(); if (nodeId == b2_nullNode) { continue; } const b2TreeNode* node = m_nodes + nodeId; if (b2TestOverlap(node->aabb, segmentAABB) == false) { continue; } // Separating axis for segment (Gino, p80). // |dot(v, p1 - c)| > dot(|v|, h) b2Vec2 c = node->aabb.GetCenter(); b2Vec2 h = node->aabb.GetExtents(); float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h); if (separation > 0.0f) { continue; } if (node->IsLeaf()) { b2RayCastInput subInput; subInput.p1 = input.p1; subInput.p2 = input.p2; subInput.maxFraction = maxFraction; float32 value = callback->RayCastCallback(subInput, nodeId); if (value == 0.0f) { // The client has terminated the ray cast. return; } if (value > 0.0f) { // Update segment bounding box. maxFraction = value; b2Vec2 t = p1 + maxFraction * (p2 - p1); segmentAABB.lowerBound = b2Min(p1, t); segmentAABB.upperBound = b2Max(p1, t); } } else { stack.Push(node->child1); stack.Push(node->child2); } } } #endif pybox2d-2.3.2/Box2D/Collision/b2TimeOfImpact.cpp000066400000000000000000000266721276457661000212620ustar00rootroot00000000000000/* * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #include using namespace std; float32 b2_toiTime, b2_toiMaxTime; int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters; int32 b2_toiRootIters, b2_toiMaxRootIters; // struct b2SeparationFunction { enum Type { e_points, e_faceA, e_faceB }; // TODO_ERIN might not need to return the separation float32 Initialize(const b2SimplexCache* cache, const b2DistanceProxy* proxyA, const b2Sweep& sweepA, const b2DistanceProxy* proxyB, const b2Sweep& sweepB, float32 t1) { m_proxyA = proxyA; m_proxyB = proxyB; int32 count = cache->count; b2Assert(0 < count && count < 3); m_sweepA = sweepA; m_sweepB = sweepB; b2Transform xfA, xfB; m_sweepA.GetTransform(&xfA, t1); m_sweepB.GetTransform(&xfB, t1); if (count == 1) { m_type = e_points; b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]); b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); b2Vec2 pointA = b2Mul(xfA, localPointA); b2Vec2 pointB = b2Mul(xfB, localPointB); m_axis = pointB - pointA; float32 s = m_axis.Normalize(); return s; } else if (cache->indexA[0] == cache->indexA[1]) { // Two points on B and one on A. m_type = e_faceB; b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]); b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]); m_axis = b2Cross(localPointB2 - localPointB1, 1.0f); m_axis.Normalize(); b2Vec2 normal = b2Mul(xfB.q, m_axis); m_localPoint = 0.5f * (localPointB1 + localPointB2); b2Vec2 pointB = b2Mul(xfB, m_localPoint); b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]); b2Vec2 pointA = b2Mul(xfA, localPointA); float32 s = b2Dot(pointA - pointB, normal); if (s < 0.0f) { m_axis = -m_axis; s = -s; } return s; } else { // Two points on A and one or two points on B. m_type = e_faceA; b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]); b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]); m_axis = b2Cross(localPointA2 - localPointA1, 1.0f); m_axis.Normalize(); b2Vec2 normal = b2Mul(xfA.q, m_axis); m_localPoint = 0.5f * (localPointA1 + localPointA2); b2Vec2 pointA = b2Mul(xfA, m_localPoint); b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]); b2Vec2 pointB = b2Mul(xfB, localPointB); float32 s = b2Dot(pointB - pointA, normal); if (s < 0.0f) { m_axis = -m_axis; s = -s; } return s; } } // float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const { b2Transform xfA, xfB; m_sweepA.GetTransform(&xfA, t); m_sweepB.GetTransform(&xfB, t); switch (m_type) { case e_points: { b2Vec2 axisA = b2MulT(xfA.q, m_axis); b2Vec2 axisB = b2MulT(xfB.q, -m_axis); *indexA = m_proxyA->GetSupport(axisA); *indexB = m_proxyB->GetSupport(axisB); b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); b2Vec2 pointA = b2Mul(xfA, localPointA); b2Vec2 pointB = b2Mul(xfB, localPointB); float32 separation = b2Dot(pointB - pointA, m_axis); return separation; } case e_faceA: { b2Vec2 normal = b2Mul(xfA.q, m_axis); b2Vec2 pointA = b2Mul(xfA, m_localPoint); b2Vec2 axisB = b2MulT(xfB.q, -normal); *indexA = -1; *indexB = m_proxyB->GetSupport(axisB); b2Vec2 localPointB = m_proxyB->GetVertex(*indexB); b2Vec2 pointB = b2Mul(xfB, localPointB); float32 separation = b2Dot(pointB - pointA, normal); return separation; } case e_faceB: { b2Vec2 normal = b2Mul(xfB.q, m_axis); b2Vec2 pointB = b2Mul(xfB, m_localPoint); b2Vec2 axisA = b2MulT(xfA.q, -normal); *indexB = -1; *indexA = m_proxyA->GetSupport(axisA); b2Vec2 localPointA = m_proxyA->GetVertex(*indexA); b2Vec2 pointA = b2Mul(xfA, localPointA); float32 separation = b2Dot(pointA - pointB, normal); return separation; } default: b2Assert(false); *indexA = -1; *indexB = -1; return 0.0f; } } // float32 Evaluate(int32 indexA, int32 indexB, float32 t) const { b2Transform xfA, xfB; m_sweepA.GetTransform(&xfA, t); m_sweepB.GetTransform(&xfB, t); switch (m_type) { case e_points: { b2Vec2 localPointA = m_proxyA->GetVertex(indexA); b2Vec2 localPointB = m_proxyB->GetVertex(indexB); b2Vec2 pointA = b2Mul(xfA, localPointA); b2Vec2 pointB = b2Mul(xfB, localPointB); float32 separation = b2Dot(pointB - pointA, m_axis); return separation; } case e_faceA: { b2Vec2 normal = b2Mul(xfA.q, m_axis); b2Vec2 pointA = b2Mul(xfA, m_localPoint); b2Vec2 localPointB = m_proxyB->GetVertex(indexB); b2Vec2 pointB = b2Mul(xfB, localPointB); float32 separation = b2Dot(pointB - pointA, normal); return separation; } case e_faceB: { b2Vec2 normal = b2Mul(xfB.q, m_axis); b2Vec2 pointB = b2Mul(xfB, m_localPoint); b2Vec2 localPointA = m_proxyA->GetVertex(indexA); b2Vec2 pointA = b2Mul(xfA, localPointA); float32 separation = b2Dot(pointA - pointB, normal); return separation; } default: b2Assert(false); return 0.0f; } } const b2DistanceProxy* m_proxyA; const b2DistanceProxy* m_proxyB; b2Sweep m_sweepA, m_sweepB; Type m_type; b2Vec2 m_localPoint; b2Vec2 m_axis; }; // CCD via the local separating axis method. This seeks progression // by computing the largest time at which separation is maintained. void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input) { b2Timer timer; ++b2_toiCalls; output->state = b2TOIOutput::e_unknown; output->t = input->tMax; const b2DistanceProxy* proxyA = &input->proxyA; const b2DistanceProxy* proxyB = &input->proxyB; b2Sweep sweepA = input->sweepA; b2Sweep sweepB = input->sweepB; // Large rotations can make the root finder fail, so we normalize the // sweep angles. sweepA.Normalize(); sweepB.Normalize(); float32 tMax = input->tMax; float32 totalRadius = proxyA->m_radius + proxyB->m_radius; float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop); float32 tolerance = 0.25f * b2_linearSlop; b2Assert(target > tolerance); float32 t1 = 0.0f; const int32 k_maxIterations = 20; // TODO_ERIN b2Settings int32 iter = 0; // Prepare input for distance query. b2SimplexCache cache; cache.count = 0; b2DistanceInput distanceInput; distanceInput.proxyA = input->proxyA; distanceInput.proxyB = input->proxyB; distanceInput.useRadii = false; // The outer loop progressively attempts to compute new separating axes. // This loop terminates when an axis is repeated (no progress is made). for(;;) { b2Transform xfA, xfB; sweepA.GetTransform(&xfA, t1); sweepB.GetTransform(&xfB, t1); // Get the distance between shapes. We can also use the results // to get a separating axis. distanceInput.transformA = xfA; distanceInput.transformB = xfB; b2DistanceOutput distanceOutput; b2Distance(&distanceOutput, &cache, &distanceInput); // If the shapes are overlapped, we give up on continuous collision. if (distanceOutput.distance <= 0.0f) { // Failure! output->state = b2TOIOutput::e_overlapped; output->t = 0.0f; break; } if (distanceOutput.distance < target + tolerance) { // Victory! output->state = b2TOIOutput::e_touching; output->t = t1; break; } // Initialize the separating axis. b2SeparationFunction fcn; fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1); #if 0 // Dump the curve seen by the root finder { const int32 N = 100; float32 dx = 1.0f / N; float32 xs[N+1]; float32 fs[N+1]; float32 x = 0.0f; for (int32 i = 0; i <= N; ++i) { sweepA.GetTransform(&xfA, x); sweepB.GetTransform(&xfB, x); float32 f = fcn.Evaluate(xfA, xfB) - target; printf("%g %g\n", x, f); xs[i] = x; fs[i] = f; x += dx; } } #endif // Compute the TOI on the separating axis. We do this by successively // resolving the deepest point. This loop is bounded by the number of vertices. bool done = false; float32 t2 = tMax; int32 pushBackIter = 0; for (;;) { // Find the deepest point at t2. Store the witness point indices. int32 indexA, indexB; float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2); // Is the final configuration separated? if (s2 > target + tolerance) { // Victory! output->state = b2TOIOutput::e_separated; output->t = tMax; done = true; break; } // Has the separation reached tolerance? if (s2 > target - tolerance) { // Advance the sweeps t1 = t2; break; } // Compute the initial separation of the witness points. float32 s1 = fcn.Evaluate(indexA, indexB, t1); // Check for initial overlap. This might happen if the root finder // runs out of iterations. if (s1 < target - tolerance) { output->state = b2TOIOutput::e_failed; output->t = t1; done = true; break; } // Check for touching if (s1 <= target + tolerance) { // Victory! t1 should hold the TOI (could be 0.0). output->state = b2TOIOutput::e_touching; output->t = t1; done = true; break; } // Compute 1D root of: f(x) - target = 0 int32 rootIterCount = 0; float32 a1 = t1, a2 = t2; for (;;) { // Use a mix of the secant rule and bisection. float32 t; if (rootIterCount & 1) { // Secant rule to improve convergence. t = a1 + (target - s1) * (a2 - a1) / (s2 - s1); } else { // Bisection to guarantee progress. t = 0.5f * (a1 + a2); } ++rootIterCount; ++b2_toiRootIters; float32 s = fcn.Evaluate(indexA, indexB, t); if (b2Abs(s - target) < tolerance) { // t2 holds a tentative value for t1 t2 = t; break; } // Ensure we continue to bracket the root. if (s > target) { a1 = t; s1 = s; } else { a2 = t; s2 = s; } if (rootIterCount == 50) { break; } } b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount); ++pushBackIter; if (pushBackIter == b2_maxPolygonVertices) { break; } } ++iter; ++b2_toiIters; if (done) { break; } if (iter == k_maxIterations) { // Root finder got stuck. Semi-victory. output->state = b2TOIOutput::e_failed; output->t = t1; break; } } b2_toiMaxIters = b2Max(b2_toiMaxIters, iter); float32 time = timer.GetMilliseconds(); b2_toiMaxTime = b2Max(b2_toiMaxTime, time); b2_toiTime += time; } pybox2d-2.3.2/Box2D/Collision/b2TimeOfImpact.h000066400000000000000000000035071276457661000207170ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_TIME_OF_IMPACT_H #define B2_TIME_OF_IMPACT_H #include #include /// Input parameters for b2TimeOfImpact struct b2TOIInput { b2DistanceProxy proxyA; b2DistanceProxy proxyB; b2Sweep sweepA; b2Sweep sweepB; float32 tMax; // defines sweep interval [0, tMax] }; // Output parameters for b2TimeOfImpact. struct b2TOIOutput { enum State { e_unknown, e_failed, e_overlapped, e_touching, e_separated }; State state; float32 t; }; /// Compute the upper bound on time before two shapes penetrate. Time is represented as /// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, /// non-tunneling collision. If you change the time interval, you should call this function /// again. /// Note: use b2Distance to compute the contact point and normal at the time of impact. void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input); #endif pybox2d-2.3.2/Box2D/Common/000077500000000000000000000000001276457661000152715ustar00rootroot00000000000000pybox2d-2.3.2/Box2D/Common/b2BlockAllocator.cpp000066400000000000000000000114411276457661000211150ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include using namespace std; int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = { 16, // 0 32, // 1 64, // 2 96, // 3 128, // 4 160, // 5 192, // 6 224, // 7 256, // 8 320, // 9 384, // 10 448, // 11 512, // 12 640, // 13 }; uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1]; bool b2BlockAllocator::s_blockSizeLookupInitialized; struct b2Chunk { int32 blockSize; b2Block* blocks; }; struct b2Block { b2Block* next; }; b2BlockAllocator::b2BlockAllocator() { b2Assert(b2_blockSizes < UCHAR_MAX); m_chunkSpace = b2_chunkArrayIncrement; m_chunkCount = 0; m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); memset(m_freeLists, 0, sizeof(m_freeLists)); if (s_blockSizeLookupInitialized == false) { int32 j = 0; for (int32 i = 1; i <= b2_maxBlockSize; ++i) { b2Assert(j < b2_blockSizes); if (i <= s_blockSizes[j]) { s_blockSizeLookup[i] = (uint8)j; } else { ++j; s_blockSizeLookup[i] = (uint8)j; } } s_blockSizeLookupInitialized = true; } } b2BlockAllocator::~b2BlockAllocator() { for (int32 i = 0; i < m_chunkCount; ++i) { b2Free(m_chunks[i].blocks); } b2Free(m_chunks); } void* b2BlockAllocator::Allocate(int32 size) { if (size == 0) return NULL; b2Assert(0 < size); if (size > b2_maxBlockSize) { return b2Alloc(size); } int32 index = s_blockSizeLookup[size]; b2Assert(0 <= index && index < b2_blockSizes); if (m_freeLists[index]) { b2Block* block = m_freeLists[index]; m_freeLists[index] = block->next; return block; } else { if (m_chunkCount == m_chunkSpace) { b2Chunk* oldChunks = m_chunks; m_chunkSpace += b2_chunkArrayIncrement; m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk)); memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk)); b2Free(oldChunks); } b2Chunk* chunk = m_chunks + m_chunkCount; chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize); #if defined(_DEBUG) memset(chunk->blocks, 0xcd, b2_chunkSize); #endif int32 blockSize = s_blockSizes[index]; chunk->blockSize = blockSize; int32 blockCount = b2_chunkSize / blockSize; b2Assert(blockCount * blockSize <= b2_chunkSize); for (int32 i = 0; i < blockCount - 1; ++i) { b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i); b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1)); block->next = next; } b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1)); last->next = NULL; m_freeLists[index] = chunk->blocks->next; ++m_chunkCount; return chunk->blocks; } } void b2BlockAllocator::Free(void* p, int32 size) { if (size == 0) { return; } b2Assert(0 < size); if (size > b2_maxBlockSize) { b2Free(p); return; } int32 index = s_blockSizeLookup[size]; b2Assert(0 <= index && index < b2_blockSizes); #ifdef _DEBUG // Verify the memory address and size is valid. int32 blockSize = s_blockSizes[index]; bool found = false; for (int32 i = 0; i < m_chunkCount; ++i) { b2Chunk* chunk = m_chunks + i; if (chunk->blockSize != blockSize) { b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks || (int8*)chunk->blocks + b2_chunkSize <= (int8*)p); } else { if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize) { found = true; } } } b2Assert(found); memset(p, 0xfd, blockSize); #endif b2Block* block = (b2Block*)p; block->next = m_freeLists[index]; m_freeLists[index] = block; } void b2BlockAllocator::Clear() { for (int32 i = 0; i < m_chunkCount; ++i) { b2Free(m_chunks[i].blocks); } m_chunkCount = 0; memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); memset(m_freeLists, 0, sizeof(m_freeLists)); } pybox2d-2.3.2/Box2D/Common/b2BlockAllocator.h000066400000000000000000000036441276457661000205700ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_BLOCK_ALLOCATOR_H #define B2_BLOCK_ALLOCATOR_H #include const int32 b2_chunkSize = 16 * 1024; const int32 b2_maxBlockSize = 640; const int32 b2_blockSizes = 14; const int32 b2_chunkArrayIncrement = 128; struct b2Block; struct b2Chunk; /// This is a small object allocator used for allocating small /// objects that persist for more than one time step. /// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp class b2BlockAllocator { public: b2BlockAllocator(); ~b2BlockAllocator(); /// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize. void* Allocate(int32 size); /// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize. void Free(void* p, int32 size); void Clear(); private: b2Chunk* m_chunks; int32 m_chunkCount; int32 m_chunkSpace; b2Block* m_freeLists[b2_blockSizes]; static int32 s_blockSizes[b2_blockSizes]; static uint8 s_blockSizeLookup[b2_maxBlockSize + 1]; static bool s_blockSizeLookupInitialized; }; #endif pybox2d-2.3.2/Box2D/Common/b2Draw.cpp000066400000000000000000000023011276457661000171120ustar00rootroot00000000000000/* * Copyright (c) 2011 Erin Catto http://box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include b2Draw::b2Draw() { m_drawFlags = 0; } void b2Draw::SetFlags(uint32 flags) { m_drawFlags = flags; } uint32 b2Draw::GetFlags() const { return m_drawFlags; } void b2Draw::AppendFlags(uint32 flags) { m_drawFlags |= flags; } void b2Draw::ClearFlags(uint32 flags) { m_drawFlags &= ~flags; } pybox2d-2.3.2/Box2D/Common/b2Draw.h000066400000000000000000000053521276457661000165700ustar00rootroot00000000000000/* * Copyright (c) 2011 Erin Catto http://box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_DRAW_H #define B2_DRAW_H #include /// Color for debug drawing. Each value has the range [0,1]. struct b2Color { b2Color() {} b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {} void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; } float32 r, g, b; }; /// Implement and register this class with a b2World to provide debug drawing of physics /// entities in your game. class b2Draw { public: b2Draw(); virtual ~b2Draw() {} enum { e_shapeBit = 0x0001, ///< draw shapes e_jointBit = 0x0002, ///< draw joint connections e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes e_pairBit = 0x0008, ///< draw broad-phase pairs e_centerOfMassBit = 0x0010 ///< draw center of mass frame }; /// Set the drawing flags. void SetFlags(uint32 flags); /// Get the drawing flags. uint32 GetFlags() const; /// Append flags to the current flags. void AppendFlags(uint32 flags); /// Clear flags from the current flags. void ClearFlags(uint32 flags); /// Draw a closed polygon provided in CCW order. virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; /// Draw a solid closed polygon provided in CCW order. virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; /// Draw a circle. virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0; /// Draw a solid circle. virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0; /// Draw a line segment. virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0; /// Draw a transform. Choose your own length scale. /// @param xf a transform. virtual void DrawTransform(const b2Transform& xf) = 0; protected: uint32 m_drawFlags; }; #endif pybox2d-2.3.2/Box2D/Common/b2GrowableStack.h000066400000000000000000000036231276457661000204220ustar00rootroot00000000000000/* * Copyright (c) 2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_GROWABLE_STACK_H #define B2_GROWABLE_STACK_H #include #include /// This is a growable LIFO stack with an initial capacity of N. /// If the stack size exceeds the initial capacity, the heap is used /// to increase the size of the stack. template class b2GrowableStack { public: b2GrowableStack() { m_stack = m_array; m_count = 0; m_capacity = N; } ~b2GrowableStack() { if (m_stack != m_array) { b2Free(m_stack); m_stack = NULL; } } void Push(const T& element) { if (m_count == m_capacity) { T* old = m_stack; m_capacity *= 2; m_stack = (T*)b2Alloc(m_capacity * sizeof(T)); std::memcpy(m_stack, old, m_count * sizeof(T)); if (old != m_array) { b2Free(old); } } m_stack[m_count] = element; ++m_count; } T Pop() { b2Assert(m_count > 0); --m_count; return m_stack[m_count]; } int32 GetCount() { return m_count; } private: T* m_stack; T m_array[N]; int32 m_count; int32 m_capacity; }; #endif pybox2d-2.3.2/Box2D/Common/b2Math.cpp000066400000000000000000000052411276457661000171140ustar00rootroot00000000000000/* * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include const b2Vec2 b2Vec2_zero(0.0f, 0.0f); /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const { float32 det = b2Dot(ex, b2Cross(ey, ez)); if (det != 0.0f) { det = 1.0f / det; } b2Vec3 x; x.x = det * b2Dot(b, b2Cross(ey, ez)); x.y = det * b2Dot(ex, b2Cross(b, ez)); x.z = det * b2Dot(ex, b2Cross(ey, b)); return x; } /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const { float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; float32 det = a11 * a22 - a12 * a21; if (det != 0.0f) { det = 1.0f / det; } b2Vec2 x; x.x = det * (a22 * b.x - a12 * b.y); x.y = det * (a11 * b.y - a21 * b.x); return x; } /// void b2Mat33::GetInverse22(b2Mat33* M) const { float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; float32 det = a * d - b * c; if (det != 0.0f) { det = 1.0f / det; } M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f; M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f; M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f; } /// Returns the zero matrix if singular. void b2Mat33::GetSymInverse33(b2Mat33* M) const { float32 det = b2Dot(ex, b2Cross(ey, ez)); if (det != 0.0f) { det = 1.0f / det; } float32 a11 = ex.x, a12 = ey.x, a13 = ez.x; float32 a22 = ey.y, a23 = ez.y; float32 a33 = ez.z; M->ex.x = det * (a22 * a33 - a23 * a23); M->ex.y = det * (a13 * a23 - a12 * a33); M->ex.z = det * (a12 * a23 - a13 * a22); M->ey.x = M->ex.y; M->ey.y = det * (a11 * a33 - a13 * a13); M->ey.z = det * (a13 * a12 - a11 * a23); M->ez.x = M->ex.z; M->ez.y = M->ey.z; M->ez.z = det * (a11 * a22 - a12 * a12); } pybox2d-2.3.2/Box2D/Common/b2Math.h000066400000000000000000000402671276457661000165700ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_MATH_H #define B2_MATH_H #include #include #include #include #include /// This function is used to ensure that a floating point number is /// not a NaN or infinity. inline bool b2IsValid(float32 x) { if (x != x) { // NaN. return false; } float32 infinity = std::numeric_limits::infinity(); return -infinity < x && x < infinity; } /// This is a approximate yet fast inverse square-root. inline float32 b2InvSqrt(float32 x) { union { float32 x; int32 i; } convert; convert.x = x; float32 xhalf = 0.5f * x; convert.i = 0x5f3759df - (convert.i >> 1); x = convert.x; x = x * (1.5f - xhalf * x * x); return x; } #define b2Sqrt(x) std::sqrt(x) #define b2Atan2(y, x) std::atan2(y, x) /// A 2D column vector. struct b2Vec2 { /// Default constructor does nothing (for performance). b2Vec2() {} /// Construct using coordinates. b2Vec2(float32 x, float32 y) : x(x), y(y) {} /// Set this vector to all zeros. void SetZero() { x = 0.0f; y = 0.0f; } /// Set this vector to some specified coordinates. void Set(float32 x_, float32 y_) { x = x_; y = y_; } /// Negate this vector. b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; } /// Read from and indexed element. float32 operator () (int32 i) const { return (&x)[i]; } /// Write to an indexed element. float32& operator () (int32 i) { return (&x)[i]; } /// Add a vector to this vector. void operator += (const b2Vec2& v) { x += v.x; y += v.y; } /// Subtract a vector from this vector. void operator -= (const b2Vec2& v) { x -= v.x; y -= v.y; } /// Multiply this vector by a scalar. void operator *= (float32 a) { x *= a; y *= a; } /// Get the length of this vector (the norm). float32 Length() const { return b2Sqrt(x * x + y * y); } /// Get the length squared. For performance, use this instead of /// b2Vec2::Length (if possible). float32 LengthSquared() const { return x * x + y * y; } /// Convert this vector into a unit vector. Returns the length. float32 Normalize() { float32 length = Length(); if (length < b2_epsilon) { return 0.0f; } float32 invLength = 1.0f / length; x *= invLength; y *= invLength; return length; } /// Does this vector contain finite coordinates? bool IsValid() const { return b2IsValid(x) && b2IsValid(y); } /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other) b2Vec2 Skew() const { return b2Vec2(-y, x); } float32 x, y; }; /// A 2D column vector with 3 elements. struct b2Vec3 { /// Default constructor does nothing (for performance). b2Vec3() {} /// Construct using coordinates. b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {} /// Set this vector to all zeros. void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; } /// Set this vector to some specified coordinates. void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; } /// Negate this vector. b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; } /// Add a vector to this vector. void operator += (const b2Vec3& v) { x += v.x; y += v.y; z += v.z; } /// Subtract a vector from this vector. void operator -= (const b2Vec3& v) { x -= v.x; y -= v.y; z -= v.z; } /// Multiply this vector by a scalar. void operator *= (float32 s) { x *= s; y *= s; z *= s; } float32 x, y, z; }; /// A 2-by-2 matrix. Stored in column-major order. struct b2Mat22 { /// The default constructor does nothing (for performance). b2Mat22() {} /// Construct this matrix using columns. b2Mat22(const b2Vec2& c1, const b2Vec2& c2) { ex = c1; ey = c2; } /// Construct this matrix using scalars. b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22) { ex.x = a11; ex.y = a21; ey.x = a12; ey.y = a22; } /// Initialize this matrix using columns. void Set(const b2Vec2& c1, const b2Vec2& c2) { ex = c1; ey = c2; } /// Set this to the identity matrix. void SetIdentity() { ex.x = 1.0f; ey.x = 0.0f; ex.y = 0.0f; ey.y = 1.0f; } /// Set this matrix to all zeros. void SetZero() { ex.x = 0.0f; ey.x = 0.0f; ex.y = 0.0f; ey.y = 0.0f; } b2Mat22 GetInverse() const { float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y; b2Mat22 B; float32 det = a * d - b * c; if (det != 0.0f) { det = 1.0f / det; } B.ex.x = det * d; B.ey.x = -det * b; B.ex.y = -det * c; B.ey.y = det * a; return B; } /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. b2Vec2 Solve(const b2Vec2& b) const { float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y; float32 det = a11 * a22 - a12 * a21; if (det != 0.0f) { det = 1.0f / det; } b2Vec2 x; x.x = det * (a22 * b.x - a12 * b.y); x.y = det * (a11 * b.y - a21 * b.x); return x; } b2Vec2 ex, ey; }; /// A 3-by-3 matrix. Stored in column-major order. struct b2Mat33 { /// The default constructor does nothing (for performance). b2Mat33() {} /// Construct this matrix using columns. b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3) { ex = c1; ey = c2; ez = c3; } /// Set this matrix to all zeros. void SetZero() { ex.SetZero(); ey.SetZero(); ez.SetZero(); } /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. b2Vec3 Solve33(const b2Vec3& b) const; /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. Solve only the upper /// 2-by-2 matrix equation. b2Vec2 Solve22(const b2Vec2& b) const; /// Get the inverse of this matrix as a 2-by-2. /// Returns the zero matrix if singular. void GetInverse22(b2Mat33* M) const; /// Get the symmetric inverse of this matrix as a 3-by-3. /// Returns the zero matrix if singular. void GetSymInverse33(b2Mat33* M) const; b2Vec3 ex, ey, ez; }; /// Rotation struct b2Rot { b2Rot() {} /// Initialize from an angle in radians explicit b2Rot(float32 angle) { /// TODO_ERIN optimize s = sinf(angle); c = cosf(angle); } /// Set using an angle in radians. void Set(float32 angle) { /// TODO_ERIN optimize s = sinf(angle); c = cosf(angle); } /// Set to the identity rotation void SetIdentity() { s = 0.0f; c = 1.0f; } /// Get the angle in radians float32 GetAngle() const { return b2Atan2(s, c); } /// Get the x-axis b2Vec2 GetXAxis() const { return b2Vec2(c, s); } /// Get the u-axis b2Vec2 GetYAxis() const { return b2Vec2(-s, c); } /// Sine and cosine float32 s, c; }; /// A transform contains translation and rotation. It is used to represent /// the position and orientation of rigid frames. struct b2Transform { /// The default constructor does nothing. b2Transform() {} /// Initialize using a position vector and a rotation. b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {} /// Set this to the identity transform. void SetIdentity() { p.SetZero(); q.SetIdentity(); } /// Set this based on the position and angle. void Set(const b2Vec2& position, float32 angle) { p = position; q.Set(angle); } b2Vec2 p; b2Rot q; }; /// This describes the motion of a body/shape for TOI computation. /// Shapes are defined with respect to the body origin, which may /// no coincide with the center of mass. However, to support dynamics /// we must interpolate the center of mass position. struct b2Sweep { /// Get the interpolated transform at a specific time. /// @param beta is a factor in [0,1], where 0 indicates alpha0. void GetTransform(b2Transform* xfb, float32 beta) const; /// Advance the sweep forward, yielding a new initial state. /// @param alpha the new initial time. void Advance(float32 alpha); /// Normalize the angles. void Normalize(); b2Vec2 localCenter; ///< local center of mass position b2Vec2 c0, c; ///< center world positions float32 a0, a; ///< world angles /// Fraction of the current time step in the range [0,1] /// c0 and a0 are the positions at alpha0. float32 alpha0; }; /// Useful constant extern const b2Vec2 b2Vec2_zero; /// Perform the dot product on two vectors. inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b) { return a.x * b.x + a.y * b.y; } /// Perform the cross product on two vectors. In 2D this produces a scalar. inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b) { return a.x * b.y - a.y * b.x; } /// Perform the cross product on a vector and a scalar. In 2D this produces /// a vector. inline b2Vec2 b2Cross(const b2Vec2& a, float32 s) { return b2Vec2(s * a.y, -s * a.x); } /// Perform the cross product on a scalar and a vector. In 2D this produces /// a vector. inline b2Vec2 b2Cross(float32 s, const b2Vec2& a) { return b2Vec2(-s * a.y, s * a.x); } /// Multiply a matrix times a vector. If a rotation matrix is provided, /// then this transforms the vector from one frame to another. inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v) { return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); } /// Multiply a matrix transpose times a vector. If a rotation matrix is provided, /// then this transforms the vector from one frame to another (inverse transform). inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v) { return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey)); } /// Add two vectors component-wise. inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b) { return b2Vec2(a.x + b.x, a.y + b.y); } /// Subtract two vectors component-wise. inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b) { return b2Vec2(a.x - b.x, a.y - b.y); } inline b2Vec2 operator * (float32 s, const b2Vec2& a) { return b2Vec2(s * a.x, s * a.y); } inline bool operator == (const b2Vec2& a, const b2Vec2& b) { return a.x == b.x && a.y == b.y; } inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b) { b2Vec2 c = a - b; return c.Length(); } inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b) { b2Vec2 c = a - b; return b2Dot(c, c); } inline b2Vec3 operator * (float32 s, const b2Vec3& a) { return b2Vec3(s * a.x, s * a.y, s * a.z); } /// Add two vectors component-wise. inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b) { return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z); } /// Subtract two vectors component-wise. inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b) { return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z); } /// Perform the dot product on two vectors. inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b) { return a.x * b.x + a.y * b.y + a.z * b.z; } /// Perform the cross product on two vectors. inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b) { return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B) { return b2Mat22(A.ex + B.ex, A.ey + B.ey); } // A * B inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B) { return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey)); } // A^T * B inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B) { b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex)); b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey)); return b2Mat22(c1, c2); } /// Multiply a matrix times a vector. inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v) { return v.x * A.ex + v.y * A.ey + v.z * A.ez; } /// Multiply a matrix times a vector. inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v) { return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y); } /// Multiply two rotations: q * r inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r) { // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc] // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc] // s = qs * rc + qc * rs // c = qc * rc - qs * rs b2Rot qr; qr.s = q.s * r.c + q.c * r.s; qr.c = q.c * r.c - q.s * r.s; return qr; } /// Transpose multiply two rotations: qT * r inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r) { // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc] // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc] // s = qc * rs - qs * rc // c = qc * rc + qs * rs b2Rot qr; qr.s = q.c * r.s - q.s * r.c; qr.c = q.c * r.c + q.s * r.s; return qr; } /// Rotate a vector inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v) { return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y); } /// Inverse rotate a vector inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v) { return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y); } inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v) { float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x; float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y; return b2Vec2(x, y); } inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v) { float32 px = v.x - T.p.x; float32 py = v.y - T.p.y; float32 x = (T.q.c * px + T.q.s * py); float32 y = (-T.q.s * px + T.q.c * py); return b2Vec2(x, y); } // v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p // = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B) { b2Transform C; C.q = b2Mul(A.q, B.q); C.p = b2Mul(A.q, B.p) + A.p; return C; } // v2 = A.q' * (B.q * v1 + B.p - A.p) // = A.q' * B.q * v1 + A.q' * (B.p - A.p) inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B) { b2Transform C; C.q = b2MulT(A.q, B.q); C.p = b2MulT(A.q, B.p - A.p); return C; } template inline T b2Abs(T a) { return a > T(0) ? a : -a; } inline b2Vec2 b2Abs(const b2Vec2& a) { return b2Vec2(b2Abs(a.x), b2Abs(a.y)); } inline b2Mat22 b2Abs(const b2Mat22& A) { return b2Mat22(b2Abs(A.ex), b2Abs(A.ey)); } template inline T b2Min(T a, T b) { return a < b ? a : b; } inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b) { return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y)); } template inline T b2Max(T a, T b) { return a > b ? a : b; } inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b) { return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y)); } template inline T b2Clamp(T a, T low, T high) { return b2Max(low, b2Min(a, high)); } inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high) { return b2Max(low, b2Min(a, high)); } template inline void b2Swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } /// "Next Largest Power of 2 /// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm /// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with /// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next /// largest power of 2. For a 32-bit value:" inline uint32 b2NextPowerOfTwo(uint32 x) { x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); return x + 1; } inline bool b2IsPowerOfTwo(uint32 x) { bool result = x > 0 && (x & (x - 1)) == 0; return result; } inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const { xf->p = (1.0f - beta) * c0 + beta * c; float32 angle = (1.0f - beta) * a0 + beta * a; xf->q.Set(angle); // Shift to origin xf->p -= b2Mul(xf->q, localCenter); } inline void b2Sweep::Advance(float32 alpha) { b2Assert(alpha0 < 1.0f); float32 beta = (alpha - alpha0) / (1.0f - alpha0); c0 = (1.0f - beta) * c0 + beta * c; a0 = (1.0f - beta) * a0 + beta * a; alpha0 = alpha; } /// Normalize an angle in radians to be between -pi and pi inline void b2Sweep::Normalize() { float32 twoPi = 2.0f * b2_pi; float32 d = twoPi * floorf(a0 / twoPi); a0 -= d; a -= d; } #endif pybox2d-2.3.2/Box2D/Common/b2Settings.cpp000066400000000000000000000025121276457661000200210ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include b2Version b2_version = {2, 3, 0}; // Memory allocators. Modify these to use your own allocator. void* b2Alloc(int32 size) { return malloc(size); } void b2Free(void* mem) { free(mem); } // You can modify this to use your logging facility. void b2Log(const char* string, ...) { va_list args; va_start(args, string); vprintf(string, args); va_end(args); } pybox2d-2.3.2/Box2D/Common/b2Settings.h000066400000000000000000000125161276457661000174730ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_SETTINGS_H #define B2_SETTINGS_H #include #include #define B2_NOT_USED(x) ((void)(x)) #define USE_EXCEPTIONS #ifdef USE_EXCEPTIONS #include class b2AssertException {}; #define b2Assert(A) if (!(A)) { PyErr_SetString(PyExc_AssertionError, #A); throw b2AssertException(); } #else #define b2Assert(A) assert(A) #endif typedef signed char int8; typedef signed short int16; typedef signed int int32; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; typedef float float32; typedef double float64; #define b2_maxFloat FLT_MAX #define b2_epsilon FLT_EPSILON #define b2_pi 3.14159265359f /// @file /// Global tuning constants based on meters-kilograms-seconds (MKS) units. /// // Collision /// The maximum number of contact points between two convex shapes. Do /// not change this value. #define b2_maxManifoldPoints 2 /// The maximum number of vertices on a convex polygon. You cannot increase /// this too much because b2BlockAllocator has a maximum object size. #define b2_maxPolygonVertices 16 /// This is used to fatten AABBs in the dynamic tree. This allows proxies /// to move by a small amount without triggering a tree adjustment. /// This is in meters. #define b2_aabbExtension 0.1f /// This is used to fatten AABBs in the dynamic tree. This is used to predict /// the future position based on the current displacement. /// This is a dimensionless multiplier. #define b2_aabbMultiplier 2.0f /// A small length used as a collision and constraint tolerance. Usually it is /// chosen to be numerically significant, but visually insignificant. #define b2_linearSlop 0.005f /// A small angle used as a collision and constraint tolerance. Usually it is /// chosen to be numerically significant, but visually insignificant. #define b2_angularSlop (2.0f / 180.0f * b2_pi) /// The radius of the polygon/edge shape skin. This should not be modified. Making /// this smaller means polygons will have an insufficient buffer for continuous collision. /// Making it larger may create artifacts for vertex collision. #define b2_polygonRadius (2.0f * b2_linearSlop) /// Maximum number of sub-steps per contact in continuous physics simulation. #define b2_maxSubSteps 8 // Dynamics /// Maximum number of contacts to be handled to solve a TOI impact. #define b2_maxTOIContacts 32 /// A velocity threshold for elastic collisions. Any collision with a relative linear /// velocity below this threshold will be treated as inelastic. #define b2_velocityThreshold 1.0f /// The maximum linear position correction used when solving constraints. This helps to /// prevent overshoot. #define b2_maxLinearCorrection 0.2f /// The maximum angular position correction used when solving constraints. This helps to /// prevent overshoot. #define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi) /// The maximum linear velocity of a body. This limit is very large and is used /// to prevent numerical problems. You shouldn't need to adjust this. #define b2_maxTranslation 2.0f #define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation) /// The maximum angular velocity of a body. This limit is very large and is used /// to prevent numerical problems. You shouldn't need to adjust this. #define b2_maxRotation (0.5f * b2_pi) #define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation) /// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so /// that overlap is removed in one time step. However using values close to 1 often lead /// to overshoot. #define b2_baumgarte 0.2f #define b2_toiBaugarte 0.75f // Sleep /// The time that a body must be still before it will go to sleep. #define b2_timeToSleep 0.5f /// A body cannot sleep if its linear velocity is above this tolerance. #define b2_linearSleepTolerance 0.01f /// A body cannot sleep if its angular velocity is above this tolerance. #define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi) // Memory Allocation /// Implement this function to use your own memory allocator. void* b2Alloc(int32 size); /// If you implement b2Alloc, you should also implement this function. void b2Free(void* mem); /// Logging function. void b2Log(const char* string, ...); /// Version numbering scheme. /// See http://en.wikipedia.org/wiki/Software_versioning struct b2Version { int32 major; ///< significant changes int32 minor; ///< incremental changes int32 revision; ///< bug fixes }; /// Current version. extern b2Version b2_version; #endif pybox2d-2.3.2/Box2D/Common/b2StackAllocator.cpp000066400000000000000000000040011276457661000211220ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include b2StackAllocator::b2StackAllocator() { m_index = 0; m_allocation = 0; m_maxAllocation = 0; m_entryCount = 0; } b2StackAllocator::~b2StackAllocator() { b2Assert(m_index == 0); b2Assert(m_entryCount == 0); } void* b2StackAllocator::Allocate(int32 size) { b2Assert(m_entryCount < b2_maxStackEntries); b2StackEntry* entry = m_entries + m_entryCount; entry->size = size; if (m_index + size > b2_stackSize) { entry->data = (char*)b2Alloc(size); entry->usedMalloc = true; } else { entry->data = m_data + m_index; entry->usedMalloc = false; m_index += size; } m_allocation += size; m_maxAllocation = b2Max(m_maxAllocation, m_allocation); ++m_entryCount; return entry->data; } void b2StackAllocator::Free(void* p) { b2Assert(m_entryCount > 0); b2StackEntry* entry = m_entries + m_entryCount - 1; b2Assert(p == entry->data); if (entry->usedMalloc) { b2Free(p); } else { m_index -= entry->size; } m_allocation -= entry->size; --m_entryCount; p = NULL; } int32 b2StackAllocator::GetMaxAllocation() const { return m_maxAllocation; } pybox2d-2.3.2/Box2D/Common/b2StackAllocator.h000066400000000000000000000032101276457661000205700ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_STACK_ALLOCATOR_H #define B2_STACK_ALLOCATOR_H #include const int32 b2_stackSize = 100 * 1024; // 100k const int32 b2_maxStackEntries = 32; struct b2StackEntry { char* data; int32 size; bool usedMalloc; }; // This is a stack allocator used for fast per step allocations. // You must nest allocate/free pairs. The code will assert // if you try to interleave multiple allocate/free pairs. class b2StackAllocator { public: b2StackAllocator(); ~b2StackAllocator(); void* Allocate(int32 size); void Free(void* p); int32 GetMaxAllocation() const; private: char m_data[b2_stackSize]; int32 m_index; int32 m_allocation; int32 m_maxAllocation; b2StackEntry m_entries[b2_maxStackEntries]; int32 m_entryCount; }; #endif pybox2d-2.3.2/Box2D/Common/b2Timer.cpp000066400000000000000000000043361276457661000173070ustar00rootroot00000000000000/* * Copyright (c) 2011 Erin Catto http://box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #if defined(_WIN32) float64 b2Timer::s_invFrequency = 0.0f; #include b2Timer::b2Timer() { LARGE_INTEGER largeInteger; if (s_invFrequency == 0.0f) { QueryPerformanceFrequency(&largeInteger); s_invFrequency = float64(largeInteger.QuadPart); if (s_invFrequency > 0.0f) { s_invFrequency = 1000.0f / s_invFrequency; } } QueryPerformanceCounter(&largeInteger); m_start = float64(largeInteger.QuadPart); } void b2Timer::Reset() { LARGE_INTEGER largeInteger; QueryPerformanceCounter(&largeInteger); m_start = float64(largeInteger.QuadPart); } float32 b2Timer::GetMilliseconds() const { LARGE_INTEGER largeInteger; QueryPerformanceCounter(&largeInteger); float64 count = float64(largeInteger.QuadPart); float32 ms = float32(s_invFrequency * (count - m_start)); return ms; } #elif defined(__linux__) || defined (__APPLE__) #include b2Timer::b2Timer() { Reset(); } void b2Timer::Reset() { timeval t; gettimeofday(&t, 0); m_start_sec = t.tv_sec; m_start_msec = t.tv_usec * 0.001f; } float32 b2Timer::GetMilliseconds() const { timeval t; gettimeofday(&t, 0); return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec; } #else b2Timer::b2Timer() { } void b2Timer::Reset() { } float32 b2Timer::GetMilliseconds() const { return 0.0f; } #endif pybox2d-2.3.2/Box2D/Common/b2Timer.h000066400000000000000000000026521276457661000167530ustar00rootroot00000000000000/* * Copyright (c) 2011 Erin Catto http://box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_TIMER_H #define B2_TIMER_H #include /// Timer for profiling. This has platform specific code and may /// not work on every platform. class b2Timer { public: /// Constructor b2Timer(); /// Reset the timer. void Reset(); /// Get the time since construction or the last reset. float32 GetMilliseconds() const; private: #if defined(_WIN32) float64 m_start; static float64 s_invFrequency; #elif defined(__linux__) || defined (__APPLE__) unsigned long m_start_sec; unsigned long m_start_msec; #endif }; #endif pybox2d-2.3.2/Box2D/Dynamics/000077500000000000000000000000001276457661000156105ustar00rootroot00000000000000pybox2d-2.3.2/Box2D/Dynamics/Contacts/000077500000000000000000000000001276457661000173665ustar00rootroot00000000000000pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.cpp000066400000000000000000000043741276457661000244310ustar00rootroot00000000000000/* * Copyright (c) 2006-2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include using namespace std; b2Contact* b2ChainAndCircleContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2ChainAndCircleContact)); return new (mem) b2ChainAndCircleContact(fixtureA, indexA, fixtureB, indexB); } void b2ChainAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2ChainAndCircleContact*)contact)->~b2ChainAndCircleContact(); allocator->Free(contact, sizeof(b2ChainAndCircleContact)); } b2ChainAndCircleContact::b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) : b2Contact(fixtureA, indexA, fixtureB, indexB) { b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); } void b2ChainAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) { b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); b2EdgeShape edge; chain->GetChildEdge(&edge, m_indexA); b2CollideEdgeAndCircle( manifold, &edge, xfA, (b2CircleShape*)m_fixtureB->GetShape(), xfB); } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h000066400000000000000000000030031276457661000240620ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H #define B2_CHAIN_AND_CIRCLE_CONTACT_H #include class b2BlockAllocator; class b2ChainAndCircleContact : public b2Contact { public: static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); ~b2ChainAndCircleContact() {} void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); }; #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.cpp000066400000000000000000000044131276457661000246510ustar00rootroot00000000000000/* * Copyright (c) 2006-2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include using namespace std; b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact)); return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB); } void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact(); allocator->Free(contact, sizeof(b2ChainAndPolygonContact)); } b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB) : b2Contact(fixtureA, indexA, fixtureB, indexB) { b2Assert(m_fixtureA->GetType() == b2Shape::e_chain); b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); } void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) { b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape(); b2EdgeShape edge; chain->GetChildEdge(&edge, m_indexA); b2CollideEdgeAndPolygon( manifold, &edge, xfA, (b2PolygonShape*)m_fixtureB->GetShape(), xfB); } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h000066400000000000000000000030101276457661000243060ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CHAIN_AND_POLYGON_CONTACT_H #define B2_CHAIN_AND_POLYGON_CONTACT_H #include class b2BlockAllocator; class b2ChainAndPolygonContact : public b2Contact { public: static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); ~b2ChainAndPolygonContact() {} void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); }; #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2CircleContact.cpp000066400000000000000000000040421276457661000230330ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #include using namespace std; b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2CircleContact)); return new (mem) b2CircleContact(fixtureA, fixtureB); } void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2CircleContact*)contact)->~b2CircleContact(); allocator->Free(contact, sizeof(b2CircleContact)); } b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) : b2Contact(fixtureA, 0, fixtureB, 0) { b2Assert(m_fixtureA->GetType() == b2Shape::e_circle); b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); } void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) { b2CollideCircles(manifold, (b2CircleShape*)m_fixtureA->GetShape(), xfA, (b2CircleShape*)m_fixtureB->GetShape(), xfB); } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2CircleContact.h000066400000000000000000000026731276457661000225100ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CIRCLE_CONTACT_H #define B2_CIRCLE_CONTACT_H #include class b2BlockAllocator; class b2CircleContact : public b2Contact { public: static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); ~b2CircleContact() {} void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); }; #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2Contact.cpp000066400000000000000000000163401276457661000217150ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; bool b2Contact::s_initialized = false; void b2Contact::InitializeRegisters() { AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle); AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle); AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon); AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle); AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon); AddType(b2ChainAndCircleContact::Create, b2ChainAndCircleContact::Destroy, b2Shape::e_chain, b2Shape::e_circle); AddType(b2ChainAndPolygonContact::Create, b2ChainAndPolygonContact::Destroy, b2Shape::e_chain, b2Shape::e_polygon); } void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn, b2Shape::Type type1, b2Shape::Type type2) { b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); s_registers[type1][type2].createFcn = createFcn; s_registers[type1][type2].destroyFcn = destoryFcn; s_registers[type1][type2].primary = true; if (type1 != type2) { s_registers[type2][type1].createFcn = createFcn; s_registers[type2][type1].destroyFcn = destoryFcn; s_registers[type2][type1].primary = false; } } b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator) { if (s_initialized == false) { InitializeRegisters(); s_initialized = true; } b2Shape::Type type1 = fixtureA->GetType(); b2Shape::Type type2 = fixtureB->GetType(); b2Assert(0 <= type1 && type1 < b2Shape::e_typeCount); b2Assert(0 <= type2 && type2 < b2Shape::e_typeCount); b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn; if (createFcn) { if (s_registers[type1][type2].primary) { return createFcn(fixtureA, indexA, fixtureB, indexB, allocator); } else { return createFcn(fixtureB, indexB, fixtureA, indexA, allocator); } } else { return NULL; } } void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { b2Assert(s_initialized == true); b2Fixture* fixtureA = contact->m_fixtureA; b2Fixture* fixtureB = contact->m_fixtureB; if (contact->m_manifold.pointCount > 0 && fixtureA->IsSensor() == false && fixtureB->IsSensor() == false) { fixtureA->GetBody()->SetAwake(true); fixtureB->GetBody()->SetAwake(true); } b2Shape::Type typeA = fixtureA->GetType(); b2Shape::Type typeB = fixtureB->GetType(); b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); b2Assert(0 <= typeA && typeB < b2Shape::e_typeCount); b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn; destroyFcn(contact, allocator); } b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB) { m_flags = e_enabledFlag; m_fixtureA = fA; m_fixtureB = fB; m_indexA = indexA; m_indexB = indexB; m_manifold.pointCount = 0; m_prev = NULL; m_next = NULL; m_nodeA.contact = NULL; m_nodeA.prev = NULL; m_nodeA.next = NULL; m_nodeA.other = NULL; m_nodeB.contact = NULL; m_nodeB.prev = NULL; m_nodeB.next = NULL; m_nodeB.other = NULL; m_toiCount = 0; m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); m_tangentSpeed = 0.0f; } // Update the contact manifold and touching status. // Note: do not assume the fixture AABBs are overlapping or are valid. void b2Contact::Update(b2ContactListener* listener) { b2Manifold oldManifold = m_manifold; // Re-enable this contact. m_flags |= e_enabledFlag; bool touching = false; bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag; bool sensorA = m_fixtureA->IsSensor(); bool sensorB = m_fixtureB->IsSensor(); bool sensor = sensorA || sensorB; b2Body* bodyA = m_fixtureA->GetBody(); b2Body* bodyB = m_fixtureB->GetBody(); const b2Transform& xfA = bodyA->GetTransform(); const b2Transform& xfB = bodyB->GetTransform(); // Is this contact a sensor? if (sensor) { const b2Shape* shapeA = m_fixtureA->GetShape(); const b2Shape* shapeB = m_fixtureB->GetShape(); touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB); // Sensors don't generate manifolds. m_manifold.pointCount = 0; } else { Evaluate(&m_manifold, xfA, xfB); touching = m_manifold.pointCount > 0; // Match old contact ids to new contact ids and copy the // stored impulses to warm start the solver. for (int32 i = 0; i < m_manifold.pointCount; ++i) { b2ManifoldPoint* mp2 = m_manifold.points + i; mp2->normalImpulse = 0.0f; mp2->tangentImpulse = 0.0f; b2ContactID id2 = mp2->id; for (int32 j = 0; j < oldManifold.pointCount; ++j) { b2ManifoldPoint* mp1 = oldManifold.points + j; if (mp1->id.key == id2.key) { mp2->normalImpulse = mp1->normalImpulse; mp2->tangentImpulse = mp1->tangentImpulse; break; } } } if (touching != wasTouching) { bodyA->SetAwake(true); bodyB->SetAwake(true); } } if (touching) { m_flags |= e_touchingFlag; } else { m_flags &= ~e_touchingFlag; } if (wasTouching == false && touching == true && listener) { listener->BeginContact(this); } if (wasTouching == true && touching == false && listener) { listener->EndContact(this); } if (sensor == false && touching && listener) { listener->PreSolve(this, &oldManifold); } } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2Contact.h000066400000000000000000000221411276457661000213560ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CONTACT_H #define B2_CONTACT_H #include #include #include #include class b2Body; class b2Contact; class b2Fixture; class b2World; class b2BlockAllocator; class b2StackAllocator; class b2ContactListener; /// Friction mixing law. The idea is to allow either fixture to drive the restitution to zero. /// For example, anything slides on ice. inline float32 b2MixFriction(float32 friction1, float32 friction2) { return std::sqrt(friction1 * friction2); } /// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. /// For example, a superball bounces on anything. inline float32 b2MixRestitution(float32 restitution1, float32 restitution2) { return restitution1 > restitution2 ? restitution1 : restitution2; } typedef b2Contact* b2ContactCreateFcn( b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); struct b2ContactRegister { b2ContactCreateFcn* createFcn; b2ContactDestroyFcn* destroyFcn; bool primary; }; /// A contact edge is used to connect bodies and contacts together /// in a contact graph where each body is a node and each contact /// is an edge. A contact edge belongs to a doubly linked list /// maintained in each attached body. Each contact has two contact /// nodes, one for each attached body. struct b2ContactEdge { b2Body* other; ///< provides quick access to the other body attached. b2Contact* contact; ///< the contact b2ContactEdge* prev; ///< the previous contact edge in the body's contact list b2ContactEdge* next; ///< the next contact edge in the body's contact list }; /// The class manages contact between two shapes. A contact exists for each overlapping /// AABB in the broad-phase (except if filtered). Therefore a contact object may exist /// that has no contact points. class b2Contact { public: /// Get the contact manifold. Do not modify the manifold unless you understand the /// internals of Box2D. b2Manifold* GetManifold(); const b2Manifold* GetManifold() const; /// Get the world manifold. void GetWorldManifold(b2WorldManifold* worldManifold) const; /// Is this contact touching? bool IsTouching() const; /// Enable/disable this contact. This can be used inside the pre-solve /// contact listener. The contact is only disabled for the current /// time step (or sub-step in continuous collisions). void SetEnabled(bool flag); /// Has this contact been disabled? bool IsEnabled() const; /// Get the next contact in the world's contact list. b2Contact* GetNext(); const b2Contact* GetNext() const; /// Get fixture A in this contact. b2Fixture* GetFixtureA(); const b2Fixture* GetFixtureA() const; /// Get the child primitive index for fixture A. int32 GetChildIndexA() const; /// Get fixture B in this contact. b2Fixture* GetFixtureB(); const b2Fixture* GetFixtureB() const; /// Get the child primitive index for fixture B. int32 GetChildIndexB() const; /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve. /// This value persists until set or reset. void SetFriction(float32 friction); /// Get the friction. float32 GetFriction() const; /// Reset the friction mixture to the default value. void ResetFriction(); /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. /// The value persists until you set or reset. void SetRestitution(float32 restitution); /// Get the restitution. float32 GetRestitution() const; /// Reset the restitution to the default value. void ResetRestitution(); /// Set the desired tangent speed for a conveyor belt behavior. In meters per second. void SetTangentSpeed(float32 speed); /// Get the desired tangent speed. In meters per second. float32 GetTangentSpeed() const; /// Evaluate this contact with your own manifold and transforms. virtual void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) = 0; protected: friend class b2ContactManager; friend class b2World; friend class b2ContactSolver; friend class b2Body; friend class b2Fixture; // Flags stored in m_flags enum { // Used when crawling contact graph when forming islands. e_islandFlag = 0x0001, // Set when the shapes are touching. e_touchingFlag = 0x0002, // This contact can be disabled (by user) e_enabledFlag = 0x0004, // This contact needs filtering because a fixture filter was changed. e_filterFlag = 0x0008, // This bullet contact had a TOI event e_bulletHitFlag = 0x0010, // This contact has a valid TOI in m_toi e_toiFlag = 0x0020 }; /// Flag this contact for filtering. Filtering will occur the next time step. void FlagForFiltering(); static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn, b2Shape::Type typeA, b2Shape::Type typeB); static void InitializeRegisters(); static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2Shape::Type typeA, b2Shape::Type typeB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2Contact() : m_fixtureA(NULL), m_fixtureB(NULL) {} b2Contact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB); virtual ~b2Contact() {} void Update(b2ContactListener* listener); static b2ContactRegister s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount]; static bool s_initialized; uint32 m_flags; // World pool and list pointers. b2Contact* m_prev; b2Contact* m_next; // Nodes for connecting bodies. b2ContactEdge m_nodeA; b2ContactEdge m_nodeB; b2Fixture* m_fixtureA; b2Fixture* m_fixtureB; int32 m_indexA; int32 m_indexB; b2Manifold m_manifold; int32 m_toiCount; float32 m_toi; float32 m_friction; float32 m_restitution; float32 m_tangentSpeed; }; inline b2Manifold* b2Contact::GetManifold() { return &m_manifold; } inline const b2Manifold* b2Contact::GetManifold() const { return &m_manifold; } inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const { const b2Body* bodyA = m_fixtureA->GetBody(); const b2Body* bodyB = m_fixtureB->GetBody(); const b2Shape* shapeA = m_fixtureA->GetShape(); const b2Shape* shapeB = m_fixtureB->GetShape(); worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius); } inline void b2Contact::SetEnabled(bool flag) { if (flag) { m_flags |= e_enabledFlag; } else { m_flags &= ~e_enabledFlag; } } inline bool b2Contact::IsEnabled() const { return (m_flags & e_enabledFlag) == e_enabledFlag; } inline bool b2Contact::IsTouching() const { return (m_flags & e_touchingFlag) == e_touchingFlag; } inline b2Contact* b2Contact::GetNext() { return m_next; } inline const b2Contact* b2Contact::GetNext() const { return m_next; } inline b2Fixture* b2Contact::GetFixtureA() { return m_fixtureA; } inline const b2Fixture* b2Contact::GetFixtureA() const { return m_fixtureA; } inline b2Fixture* b2Contact::GetFixtureB() { return m_fixtureB; } inline int32 b2Contact::GetChildIndexA() const { return m_indexA; } inline const b2Fixture* b2Contact::GetFixtureB() const { return m_fixtureB; } inline int32 b2Contact::GetChildIndexB() const { return m_indexB; } inline void b2Contact::FlagForFiltering() { m_flags |= e_filterFlag; } inline void b2Contact::SetFriction(float32 friction) { m_friction = friction; } inline float32 b2Contact::GetFriction() const { return m_friction; } inline void b2Contact::ResetFriction() { m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); } inline void b2Contact::SetRestitution(float32 restitution) { m_restitution = restitution; } inline float32 b2Contact::GetRestitution() const { return m_restitution; } inline void b2Contact::ResetRestitution() { m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); } inline void b2Contact::SetTangentSpeed(float32 speed) { m_tangentSpeed = speed; } inline float32 b2Contact::GetTangentSpeed() const { return m_tangentSpeed; } #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2ContactSolver.cpp000066400000000000000000000543601276457661000231140ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #define B2_DEBUG_SOLVER 0 struct b2ContactPositionConstraint { b2Vec2 localPoints[b2_maxManifoldPoints]; b2Vec2 localNormal; b2Vec2 localPoint; int32 indexA; int32 indexB; float32 invMassA, invMassB; b2Vec2 localCenterA, localCenterB; float32 invIA, invIB; b2Manifold::Type type; float32 radiusA, radiusB; int32 pointCount; }; b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def) { m_step = def->step; m_allocator = def->allocator; m_count = def->count; m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint)); m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint)); m_positions = def->positions; m_velocities = def->velocities; m_contacts = def->contacts; // Initialize position independent portions of the constraints. for (int32 i = 0; i < m_count; ++i) { b2Contact* contact = m_contacts[i]; b2Fixture* fixtureA = contact->m_fixtureA; b2Fixture* fixtureB = contact->m_fixtureB; b2Shape* shapeA = fixtureA->GetShape(); b2Shape* shapeB = fixtureB->GetShape(); float32 radiusA = shapeA->m_radius; float32 radiusB = shapeB->m_radius; b2Body* bodyA = fixtureA->GetBody(); b2Body* bodyB = fixtureB->GetBody(); b2Manifold* manifold = contact->GetManifold(); int32 pointCount = manifold->pointCount; b2Assert(pointCount > 0); b2ContactVelocityConstraint* vc = m_velocityConstraints + i; vc->friction = contact->m_friction; vc->restitution = contact->m_restitution; vc->tangentSpeed = contact->m_tangentSpeed; vc->indexA = bodyA->m_islandIndex; vc->indexB = bodyB->m_islandIndex; vc->invMassA = bodyA->m_invMass; vc->invMassB = bodyB->m_invMass; vc->invIA = bodyA->m_invI; vc->invIB = bodyB->m_invI; vc->contactIndex = i; vc->pointCount = pointCount; vc->K.SetZero(); vc->normalMass.SetZero(); b2ContactPositionConstraint* pc = m_positionConstraints + i; pc->indexA = bodyA->m_islandIndex; pc->indexB = bodyB->m_islandIndex; pc->invMassA = bodyA->m_invMass; pc->invMassB = bodyB->m_invMass; pc->localCenterA = bodyA->m_sweep.localCenter; pc->localCenterB = bodyB->m_sweep.localCenter; pc->invIA = bodyA->m_invI; pc->invIB = bodyB->m_invI; pc->localNormal = manifold->localNormal; pc->localPoint = manifold->localPoint; pc->pointCount = pointCount; pc->radiusA = radiusA; pc->radiusB = radiusB; pc->type = manifold->type; for (int32 j = 0; j < pointCount; ++j) { b2ManifoldPoint* cp = manifold->points + j; b2VelocityConstraintPoint* vcp = vc->points + j; if (m_step.warmStarting) { vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse; vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse; } else { vcp->normalImpulse = 0.0f; vcp->tangentImpulse = 0.0f; } vcp->rA.SetZero(); vcp->rB.SetZero(); vcp->normalMass = 0.0f; vcp->tangentMass = 0.0f; vcp->velocityBias = 0.0f; pc->localPoints[j] = cp->localPoint; } } } b2ContactSolver::~b2ContactSolver() { m_allocator->Free(m_velocityConstraints); m_allocator->Free(m_positionConstraints); } // Initialize position dependent portions of the velocity constraints. void b2ContactSolver::InitializeVelocityConstraints() { for (int32 i = 0; i < m_count; ++i) { b2ContactVelocityConstraint* vc = m_velocityConstraints + i; b2ContactPositionConstraint* pc = m_positionConstraints + i; float32 radiusA = pc->radiusA; float32 radiusB = pc->radiusB; b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); int32 indexA = vc->indexA; int32 indexB = vc->indexB; float32 mA = vc->invMassA; float32 mB = vc->invMassB; float32 iA = vc->invIA; float32 iB = vc->invIB; b2Vec2 localCenterA = pc->localCenterA; b2Vec2 localCenterB = pc->localCenterB; b2Vec2 cA = m_positions[indexA].c; float32 aA = m_positions[indexA].a; b2Vec2 vA = m_velocities[indexA].v; float32 wA = m_velocities[indexA].w; b2Vec2 cB = m_positions[indexB].c; float32 aB = m_positions[indexB].a; b2Vec2 vB = m_velocities[indexB].v; float32 wB = m_velocities[indexB].w; b2Assert(manifold->pointCount > 0); b2Transform xfA, xfB; xfA.q.Set(aA); xfB.q.Set(aB); xfA.p = cA - b2Mul(xfA.q, localCenterA); xfB.p = cB - b2Mul(xfB.q, localCenterB); b2WorldManifold worldManifold; worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB); vc->normal = worldManifold.normal; int32 pointCount = vc->pointCount; for (int32 j = 0; j < pointCount; ++j) { b2VelocityConstraintPoint* vcp = vc->points + j; vcp->rA = worldManifold.points[j] - cA; vcp->rB = worldManifold.points[j] - cB; float32 rnA = b2Cross(vcp->rA, vc->normal); float32 rnB = b2Cross(vcp->rB, vc->normal); float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB; vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f; b2Vec2 tangent = b2Cross(vc->normal, 1.0f); float32 rtA = b2Cross(vcp->rA, tangent); float32 rtB = b2Cross(vcp->rB, tangent); float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB; vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f; // Setup a velocity bias for restitution. vcp->velocityBias = 0.0f; float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA)); if (vRel < -b2_velocityThreshold) { vcp->velocityBias = -vc->restitution * vRel; } } // If we have two points, then prepare the block solver. if (vc->pointCount == 2) { b2VelocityConstraintPoint* vcp1 = vc->points + 0; b2VelocityConstraintPoint* vcp2 = vc->points + 1; float32 rn1A = b2Cross(vcp1->rA, vc->normal); float32 rn1B = b2Cross(vcp1->rB, vc->normal); float32 rn2A = b2Cross(vcp2->rA, vc->normal); float32 rn2B = b2Cross(vcp2->rB, vc->normal); float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B; float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B; float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B; // Ensure a reasonable condition number. const float32 k_maxConditionNumber = 1000.0f; if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) { // K is safe to invert. vc->K.ex.Set(k11, k12); vc->K.ey.Set(k12, k22); vc->normalMass = vc->K.GetInverse(); } else { // The constraints are redundant, just use one. // TODO_ERIN use deepest? vc->pointCount = 1; } } } } void b2ContactSolver::WarmStart() { // Warm start. for (int32 i = 0; i < m_count; ++i) { b2ContactVelocityConstraint* vc = m_velocityConstraints + i; int32 indexA = vc->indexA; int32 indexB = vc->indexB; float32 mA = vc->invMassA; float32 iA = vc->invIA; float32 mB = vc->invMassB; float32 iB = vc->invIB; int32 pointCount = vc->pointCount; b2Vec2 vA = m_velocities[indexA].v; float32 wA = m_velocities[indexA].w; b2Vec2 vB = m_velocities[indexB].v; float32 wB = m_velocities[indexB].w; b2Vec2 normal = vc->normal; b2Vec2 tangent = b2Cross(normal, 1.0f); for (int32 j = 0; j < pointCount; ++j) { b2VelocityConstraintPoint* vcp = vc->points + j; b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent; wA -= iA * b2Cross(vcp->rA, P); vA -= mA * P; wB += iB * b2Cross(vcp->rB, P); vB += mB * P; } m_velocities[indexA].v = vA; m_velocities[indexA].w = wA; m_velocities[indexB].v = vB; m_velocities[indexB].w = wB; } } void b2ContactSolver::SolveVelocityConstraints() { for (int32 i = 0; i < m_count; ++i) { b2ContactVelocityConstraint* vc = m_velocityConstraints + i; int32 indexA = vc->indexA; int32 indexB = vc->indexB; float32 mA = vc->invMassA; float32 iA = vc->invIA; float32 mB = vc->invMassB; float32 iB = vc->invIB; int32 pointCount = vc->pointCount; b2Vec2 vA = m_velocities[indexA].v; float32 wA = m_velocities[indexA].w; b2Vec2 vB = m_velocities[indexB].v; float32 wB = m_velocities[indexB].w; b2Vec2 normal = vc->normal; b2Vec2 tangent = b2Cross(normal, 1.0f); float32 friction = vc->friction; b2Assert(pointCount == 1 || pointCount == 2); // Solve tangent constraints first because non-penetration is more important // than friction. for (int32 j = 0; j < pointCount; ++j) { b2VelocityConstraintPoint* vcp = vc->points + j; // Relative velocity at contact b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); // Compute tangent force float32 vt = b2Dot(dv, tangent) - vc->tangentSpeed; float32 lambda = vcp->tangentMass * (-vt); // b2Clamp the accumulated force float32 maxFriction = friction * vcp->normalImpulse; float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction); lambda = newImpulse - vcp->tangentImpulse; vcp->tangentImpulse = newImpulse; // Apply contact impulse b2Vec2 P = lambda * tangent; vA -= mA * P; wA -= iA * b2Cross(vcp->rA, P); vB += mB * P; wB += iB * b2Cross(vcp->rB, P); } // Solve normal constraints if (vc->pointCount == 1) { b2VelocityConstraintPoint* vcp = vc->points + 0; // Relative velocity at contact b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA); // Compute normal impulse float32 vn = b2Dot(dv, normal); float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias); // b2Clamp the accumulated impulse float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f); lambda = newImpulse - vcp->normalImpulse; vcp->normalImpulse = newImpulse; // Apply contact impulse b2Vec2 P = lambda * normal; vA -= mA * P; wA -= iA * b2Cross(vcp->rA, P); vB += mB * P; wB += iB * b2Cross(vcp->rB, P); } else { // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite). // Build the mini LCP for this contact patch // // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2 // // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n ) // b = vn0 - velocityBias // // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid // solution that satisfies the problem is chosen. // // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i). // // Substitute: // // x = a + d // // a := old total impulse // x := new total impulse // d := incremental impulse // // For the current iteration we extend the formula for the incremental impulse // to compute the new total impulse: // // vn = A * d + b // = A * (x - a) + b // = A * x + b - A * a // = A * x + b' // b' = b - A * a; b2VelocityConstraintPoint* cp1 = vc->points + 0; b2VelocityConstraintPoint* cp2 = vc->points + 1; b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse); b2Assert(a.x >= 0.0f && a.y >= 0.0f); // Relative velocity at contact b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); // Compute normal velocity float32 vn1 = b2Dot(dv1, normal); float32 vn2 = b2Dot(dv2, normal); b2Vec2 b; b.x = vn1 - cp1->velocityBias; b.y = vn2 - cp2->velocityBias; // Compute b' b -= b2Mul(vc->K, a); const float32 k_errorTol = 1e-3f; B2_NOT_USED(k_errorTol); for (;;) { // // Case 1: vn = 0 // // 0 = A * x + b' // // Solve for x: // // x = - inv(A) * b' // b2Vec2 x = - b2Mul(vc->normalMass, b); if (x.x >= 0.0f && x.y >= 0.0f) { // Get the incremental impulse b2Vec2 d = x - a; // Apply incremental impulse b2Vec2 P1 = d.x * normal; b2Vec2 P2 = d.y * normal; vA -= mA * (P1 + P2); wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); vB += mB * (P1 + P2); wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); // Accumulate cp1->normalImpulse = x.x; cp2->normalImpulse = x.y; #if B2_DEBUG_SOLVER == 1 // Postconditions dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); // Compute normal velocity vn1 = b2Dot(dv1, normal); vn2 = b2Dot(dv2, normal); b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); #endif break; } // // Case 2: vn1 = 0 and x2 = 0 // // 0 = a11 * x1 + a12 * 0 + b1' // vn2 = a21 * x1 + a22 * 0 + b2' // x.x = - cp1->normalMass * b.x; x.y = 0.0f; vn1 = 0.0f; vn2 = vc->K.ex.y * x.x + b.y; if (x.x >= 0.0f && vn2 >= 0.0f) { // Get the incremental impulse b2Vec2 d = x - a; // Apply incremental impulse b2Vec2 P1 = d.x * normal; b2Vec2 P2 = d.y * normal; vA -= mA * (P1 + P2); wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); vB += mB * (P1 + P2); wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); // Accumulate cp1->normalImpulse = x.x; cp2->normalImpulse = x.y; #if B2_DEBUG_SOLVER == 1 // Postconditions dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA); // Compute normal velocity vn1 = b2Dot(dv1, normal); b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); #endif break; } // // Case 3: vn2 = 0 and x1 = 0 // // vn1 = a11 * 0 + a12 * x2 + b1' // 0 = a21 * 0 + a22 * x2 + b2' // x.x = 0.0f; x.y = - cp2->normalMass * b.y; vn1 = vc->K.ey.x * x.y + b.x; vn2 = 0.0f; if (x.y >= 0.0f && vn1 >= 0.0f) { // Resubstitute for the incremental impulse b2Vec2 d = x - a; // Apply incremental impulse b2Vec2 P1 = d.x * normal; b2Vec2 P2 = d.y * normal; vA -= mA * (P1 + P2); wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); vB += mB * (P1 + P2); wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); // Accumulate cp1->normalImpulse = x.x; cp2->normalImpulse = x.y; #if B2_DEBUG_SOLVER == 1 // Postconditions dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA); // Compute normal velocity vn2 = b2Dot(dv2, normal); b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); #endif break; } // // Case 4: x1 = 0 and x2 = 0 // // vn1 = b1 // vn2 = b2; x.x = 0.0f; x.y = 0.0f; vn1 = b.x; vn2 = b.y; if (vn1 >= 0.0f && vn2 >= 0.0f ) { // Resubstitute for the incremental impulse b2Vec2 d = x - a; // Apply incremental impulse b2Vec2 P1 = d.x * normal; b2Vec2 P2 = d.y * normal; vA -= mA * (P1 + P2); wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2)); vB += mB * (P1 + P2); wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2)); // Accumulate cp1->normalImpulse = x.x; cp2->normalImpulse = x.y; break; } // No solution, give up. This is hit sometimes, but it doesn't seem to matter. break; } } m_velocities[indexA].v = vA; m_velocities[indexA].w = wA; m_velocities[indexB].v = vB; m_velocities[indexB].w = wB; } } void b2ContactSolver::StoreImpulses() { for (int32 i = 0; i < m_count; ++i) { b2ContactVelocityConstraint* vc = m_velocityConstraints + i; b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold(); for (int32 j = 0; j < vc->pointCount; ++j) { manifold->points[j].normalImpulse = vc->points[j].normalImpulse; manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse; } } } struct b2PositionSolverManifold { void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index) { b2Assert(pc->pointCount > 0); switch (pc->type) { case b2Manifold::e_circles: { b2Vec2 pointA = b2Mul(xfA, pc->localPoint); b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]); normal = pointB - pointA; normal.Normalize(); point = 0.5f * (pointA + pointB); separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB; } break; case b2Manifold::e_faceA: { normal = b2Mul(xfA.q, pc->localNormal); b2Vec2 planePoint = b2Mul(xfA, pc->localPoint); b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]); separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; point = clipPoint; } break; case b2Manifold::e_faceB: { normal = b2Mul(xfB.q, pc->localNormal); b2Vec2 planePoint = b2Mul(xfB, pc->localPoint); b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]); separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB; point = clipPoint; // Ensure normal points from A to B normal = -normal; } break; } } b2Vec2 normal; b2Vec2 point; float32 separation; }; // Sequential solver. bool b2ContactSolver::SolvePositionConstraints() { float32 minSeparation = 0.0f; for (int32 i = 0; i < m_count; ++i) { b2ContactPositionConstraint* pc = m_positionConstraints + i; int32 indexA = pc->indexA; int32 indexB = pc->indexB; b2Vec2 localCenterA = pc->localCenterA; float32 mA = pc->invMassA; float32 iA = pc->invIA; b2Vec2 localCenterB = pc->localCenterB; float32 mB = pc->invMassB; float32 iB = pc->invIB; int32 pointCount = pc->pointCount; b2Vec2 cA = m_positions[indexA].c; float32 aA = m_positions[indexA].a; b2Vec2 cB = m_positions[indexB].c; float32 aB = m_positions[indexB].a; // Solve normal constraints for (int32 j = 0; j < pointCount; ++j) { b2Transform xfA, xfB; xfA.q.Set(aA); xfB.q.Set(aB); xfA.p = cA - b2Mul(xfA.q, localCenterA); xfB.p = cB - b2Mul(xfB.q, localCenterB); b2PositionSolverManifold psm; psm.Initialize(pc, xfA, xfB, j); b2Vec2 normal = psm.normal; b2Vec2 point = psm.point; float32 separation = psm.separation; b2Vec2 rA = point - cA; b2Vec2 rB = point - cB; // Track max constraint error. minSeparation = b2Min(minSeparation, separation); // Prevent large corrections and allow slop. float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); // Compute the effective mass. float32 rnA = b2Cross(rA, normal); float32 rnB = b2Cross(rB, normal); float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; // Compute normal impulse float32 impulse = K > 0.0f ? - C / K : 0.0f; b2Vec2 P = impulse * normal; cA -= mA * P; aA -= iA * b2Cross(rA, P); cB += mB * P; aB += iB * b2Cross(rB, P); } m_positions[indexA].c = cA; m_positions[indexA].a = aA; m_positions[indexB].c = cB; m_positions[indexB].a = aB; } // We can't expect minSpeparation >= -b2_linearSlop because we don't // push the separation above -b2_linearSlop. return minSeparation >= -3.0f * b2_linearSlop; } // Sequential position solver for position constraints. bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB) { float32 minSeparation = 0.0f; for (int32 i = 0; i < m_count; ++i) { b2ContactPositionConstraint* pc = m_positionConstraints + i; int32 indexA = pc->indexA; int32 indexB = pc->indexB; b2Vec2 localCenterA = pc->localCenterA; b2Vec2 localCenterB = pc->localCenterB; int32 pointCount = pc->pointCount; float32 mA = 0.0f; float32 iA = 0.0f; if (indexA == toiIndexA || indexA == toiIndexB) { mA = pc->invMassA; iA = pc->invIA; } float32 mB = 0.0f; float32 iB = 0.; if (indexB == toiIndexA || indexB == toiIndexB) { mB = pc->invMassB; iB = pc->invIB; } b2Vec2 cA = m_positions[indexA].c; float32 aA = m_positions[indexA].a; b2Vec2 cB = m_positions[indexB].c; float32 aB = m_positions[indexB].a; // Solve normal constraints for (int32 j = 0; j < pointCount; ++j) { b2Transform xfA, xfB; xfA.q.Set(aA); xfB.q.Set(aB); xfA.p = cA - b2Mul(xfA.q, localCenterA); xfB.p = cB - b2Mul(xfB.q, localCenterB); b2PositionSolverManifold psm; psm.Initialize(pc, xfA, xfB, j); b2Vec2 normal = psm.normal; b2Vec2 point = psm.point; float32 separation = psm.separation; b2Vec2 rA = point - cA; b2Vec2 rB = point - cB; // Track max constraint error. minSeparation = b2Min(minSeparation, separation); // Prevent large corrections and allow slop. float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f); // Compute the effective mass. float32 rnA = b2Cross(rA, normal); float32 rnB = b2Cross(rB, normal); float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB; // Compute normal impulse float32 impulse = K > 0.0f ? - C / K : 0.0f; b2Vec2 P = impulse * normal; cA -= mA * P; aA -= iA * b2Cross(rA, P); cB += mB * P; aB += iB * b2Cross(rB, P); } m_positions[indexA].c = cA; m_positions[indexA].a = aA; m_positions[indexB].c = cB; m_positions[indexB].a = aB; } // We can't expect minSpeparation >= -b2_linearSlop because we don't // push the separation above -b2_linearSlop. return minSeparation >= -1.5f * b2_linearSlop; } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2ContactSolver.h000066400000000000000000000045621276457661000225600ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CONTACT_SOLVER_H #define B2_CONTACT_SOLVER_H #include #include #include class b2Contact; class b2Body; class b2StackAllocator; struct b2ContactPositionConstraint; struct b2VelocityConstraintPoint { b2Vec2 rA; b2Vec2 rB; float32 normalImpulse; float32 tangentImpulse; float32 normalMass; float32 tangentMass; float32 velocityBias; }; struct b2ContactVelocityConstraint { b2VelocityConstraintPoint points[b2_maxManifoldPoints]; b2Vec2 normal; b2Mat22 normalMass; b2Mat22 K; int32 indexA; int32 indexB; float32 invMassA, invMassB; float32 invIA, invIB; float32 friction; float32 restitution; float32 tangentSpeed; int32 pointCount; int32 contactIndex; }; struct b2ContactSolverDef { b2TimeStep step; b2Contact** contacts; int32 count; b2Position* positions; b2Velocity* velocities; b2StackAllocator* allocator; }; class b2ContactSolver { public: b2ContactSolver(b2ContactSolverDef* def); ~b2ContactSolver(); void InitializeVelocityConstraints(); void WarmStart(); void SolveVelocityConstraints(); void StoreImpulses(); bool SolvePositionConstraints(); bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB); b2TimeStep m_step; b2Position* m_positions; b2Velocity* m_velocities; b2StackAllocator* m_allocator; b2ContactPositionConstraint* m_positionConstraints; b2ContactVelocityConstraint* m_velocityConstraints; b2Contact** m_contacts; int m_count; }; #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp000066400000000000000000000037731276457661000242550ustar00rootroot00000000000000/* * Copyright (c) 2006-2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include using namespace std; b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact)); return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB); } void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact(); allocator->Free(contact, sizeof(b2EdgeAndCircleContact)); } b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) : b2Contact(fixtureA, 0, fixtureB, 0) { b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); } void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) { b2CollideEdgeAndCircle( manifold, (b2EdgeShape*)m_fixtureA->GetShape(), xfA, (b2CircleShape*)m_fixtureB->GetShape(), xfB); } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h000066400000000000000000000027421276457661000237150ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_EDGE_AND_CIRCLE_CONTACT_H #define B2_EDGE_AND_CIRCLE_CONTACT_H #include class b2BlockAllocator; class b2EdgeAndCircleContact : public b2Contact { public: static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); ~b2EdgeAndCircleContact() {} void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); }; #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.cpp000066400000000000000000000040111276457661000244650ustar00rootroot00000000000000/* * Copyright (c) 2006-2010 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include using namespace std; b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact)); return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB); } void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact(); allocator->Free(contact, sizeof(b2EdgeAndPolygonContact)); } b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) : b2Contact(fixtureA, 0, fixtureB, 0) { b2Assert(m_fixtureA->GetType() == b2Shape::e_edge); b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); } void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) { b2CollideEdgeAndPolygon( manifold, (b2EdgeShape*)m_fixtureA->GetShape(), xfA, (b2PolygonShape*)m_fixtureB->GetShape(), xfB); } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h000066400000000000000000000027471276457661000241500ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_EDGE_AND_POLYGON_CONTACT_H #define B2_EDGE_AND_POLYGON_CONTACT_H #include class b2BlockAllocator; class b2EdgeAndPolygonContact : public b2Contact { public: static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); ~b2EdgeAndPolygonContact() {} void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); }; #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2NullContact.h000066400000000000000000000023311276457661000222100ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_NULL_CONTACT_H #define B2_NULL_CONTACT_H #include class b2NullContact : public b2Contact { public: b2NullContact() {} void Evaluate() {} float32 ComputeTOI(const b2Sweep& sweepA, const b2Sweep& sweepB) const { B2_NOT_USED(sweepA); B2_NOT_USED(sweepB); return 1.0f; } }; #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp000066400000000000000000000040451276457661000250310ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include using namespace std; b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact)); return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB); } void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact(); allocator->Free(contact, sizeof(b2PolygonAndCircleContact)); } b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB) : b2Contact(fixtureA, 0, fixtureB, 0) { b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); b2Assert(m_fixtureB->GetType() == b2Shape::e_circle); } void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) { b2CollidePolygonAndCircle( manifold, (b2PolygonShape*)m_fixtureA->GetShape(), xfA, (b2CircleShape*)m_fixtureB->GetShape(), xfB); } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h000066400000000000000000000027501276457661000244770ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H #define B2_POLYGON_AND_CIRCLE_CONTACT_H #include class b2BlockAllocator; class b2PolygonAndCircleContact : public b2Contact { public: static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB); ~b2PolygonAndCircleContact() {} void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); }; #endif pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2PolygonContact.cpp000066400000000000000000000040651276457661000232660ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #include using namespace std; b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2PolygonContact)); return new (mem) b2PolygonContact(fixtureA, fixtureB); } void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2PolygonContact*)contact)->~b2PolygonContact(); allocator->Free(contact, sizeof(b2PolygonContact)); } b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB) : b2Contact(fixtureA, 0, fixtureB, 0) { b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon); b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon); } void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) { b2CollidePolygons( manifold, (b2PolygonShape*)m_fixtureA->GetShape(), xfA, (b2PolygonShape*)m_fixtureB->GetShape(), xfB); } pybox2d-2.3.2/Box2D/Dynamics/Contacts/b2PolygonContact.h000066400000000000000000000027001276457661000227250ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_POLYGON_CONTACT_H #define B2_POLYGON_CONTACT_H #include class b2BlockAllocator; class b2PolygonContact : public b2Contact { public: static b2Contact* Create( b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB); ~b2PolygonContact() {} void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); }; #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/000077500000000000000000000000001276457661000170565ustar00rootroot00000000000000pybox2d-2.3.2/Box2D/Dynamics/Joints/b2DistanceJoint.cpp000066400000000000000000000161771276457661000225600ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // 1-D constrained system // m (v2 - v1) = lambda // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass. // x2 = x1 + h * v2 // 1-D mass-damper-spring system // m (v2 - v1) + h * d * v2 + h * k * // C = norm(p2 - p1) - L // u = (p2 - p1) / norm(p2 - p1) // Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1)) // J = [-u -cross(r1, u) u cross(r2, u)] // K = J * invM * JT // = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2 void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor1, const b2Vec2& anchor2) { bodyA = b1; bodyB = b2; localAnchorA = bodyA->GetLocalPoint(anchor1); localAnchorB = bodyB->GetLocalPoint(anchor2); b2Vec2 d = anchor2 - anchor1; length = d.Length(); } b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def) : b2Joint(def) { m_localAnchorA = def->localAnchorA; m_localAnchorB = def->localAnchorB; m_length = def->length; m_frequencyHz = def->frequencyHz; m_dampingRatio = def->dampingRatio; m_impulse = 0.0f; m_gamma = 0.0f; m_bias = 0.0f; } void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); m_u = cB + m_rB - cA - m_rA; // Handle singularity. float32 length = m_u.Length(); if (length > b2_linearSlop) { m_u *= 1.0f / length; } else { m_u.Set(0.0f, 0.0f); } float32 crAu = b2Cross(m_rA, m_u); float32 crBu = b2Cross(m_rB, m_u); float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu; // Compute the effective mass matrix. m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; if (m_frequencyHz > 0.0f) { float32 C = length - m_length; // Frequency float32 omega = 2.0f * b2_pi * m_frequencyHz; // Damping coefficient float32 d = 2.0f * m_mass * m_dampingRatio * omega; // Spring stiffness float32 k = m_mass * omega * omega; // magic formulas float32 h = data.step.dt; m_gamma = h * (d + h * k); m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; m_bias = C * h * k * m_gamma; invMass += m_gamma; m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; } else { m_gamma = 0.0f; m_bias = 0.0f; } if (data.step.warmStarting) { // Scale the impulse to support a variable time step. m_impulse *= data.step.dtRatio; b2Vec2 P = m_impulse * m_u; vA -= m_invMassA * P; wA -= m_invIA * b2Cross(m_rA, P); vB += m_invMassB * P; wB += m_invIB * b2Cross(m_rB, P); } else { m_impulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; // Cdot = dot(u, v + cross(w, r)) b2Vec2 vpA = vA + b2Cross(wA, m_rA); b2Vec2 vpB = vB + b2Cross(wB, m_rB); float32 Cdot = b2Dot(m_u, vpB - vpA); float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse); m_impulse += impulse; b2Vec2 P = impulse * m_u; vA -= m_invMassA * P; wA -= m_invIA * b2Cross(m_rA, P); vB += m_invMassB * P; wB += m_invIB * b2Cross(m_rB, P); data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data) { if (m_frequencyHz > 0.0f) { // There is no position correction for soft distance constraints. return true; } b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Rot qA(aA), qB(aB); b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); b2Vec2 u = cB + rB - cA - rA; float32 length = u.Normalize(); float32 C = length - m_length; C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection); float32 impulse = -m_mass * C; b2Vec2 P = impulse * u; cA -= m_invMassA * P; aA -= m_invIA * b2Cross(rA, P); cB += m_invMassB * P; aB += m_invIB * b2Cross(rB, P); data.positions[m_indexA].c = cA; data.positions[m_indexA].a = aA; data.positions[m_indexB].c = cB; data.positions[m_indexB].a = aB; return b2Abs(C) < b2_linearSlop; } b2Vec2 b2DistanceJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2DistanceJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 F = (inv_dt * m_impulse) * m_u; return F; } float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const { B2_NOT_USED(inv_dt); return 0.0f; } void b2DistanceJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2DistanceJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); b2Log(" jd.length = %.15lef;\n", m_length); b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2DistanceJoint.h000066400000000000000000000107531276457661000222170ustar00rootroot00000000000000/* * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_DISTANCE_JOINT_H #define B2_DISTANCE_JOINT_H #include /// Distance joint definition. This requires defining an /// anchor point on both bodies and the non-zero length of the /// distance joint. The definition uses local anchor points /// so that the initial configuration can violate the constraint /// slightly. This helps when saving and loading a game. /// @warning Do not use a zero or short length. struct b2DistanceJointDef : public b2JointDef { b2DistanceJointDef() { type = e_distanceJoint; localAnchorA.Set(0.0f, 0.0f); localAnchorB.Set(0.0f, 0.0f); length = 1.0f; frequencyHz = 0.0f; dampingRatio = 0.0f; } /// Initialize the bodies, anchors, and length using the world /// anchors. void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchorA, const b2Vec2& anchorB); /// The local anchor point relative to bodyA's origin. b2Vec2 localAnchorA; /// The local anchor point relative to bodyB's origin. b2Vec2 localAnchorB; /// The natural length between the anchor points. float32 length; /// The mass-spring-damper frequency in Hertz. A value of 0 /// disables softness. float32 frequencyHz; /// The damping ratio. 0 = no damping, 1 = critical damping. float32 dampingRatio; }; /// A distance joint constrains two points on two bodies /// to remain at a fixed distance from each other. You can view /// this as a massless, rigid rod. class b2DistanceJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; /// Get the reaction force given the inverse time step. /// Unit is N. b2Vec2 GetReactionForce(float32 inv_dt) const; /// Get the reaction torque given the inverse time step. /// Unit is N*m. This is always zero for a distance joint. float32 GetReactionTorque(float32 inv_dt) const; /// The local anchor point relative to bodyA's origin. const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } /// The local anchor point relative to bodyB's origin. const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } /// Set/get the natural length. /// Manipulating the length can lead to non-physical behavior when the frequency is zero. void SetLength(float32 length); float32 GetLength() const; /// Set/get frequency in Hz. void SetFrequency(float32 hz); float32 GetFrequency() const; /// Set/get damping ratio. void SetDampingRatio(float32 ratio); float32 GetDampingRatio() const; /// Dump joint to dmLog void Dump(); protected: friend class b2Joint; b2DistanceJoint(const b2DistanceJointDef* data); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); float32 m_frequencyHz; float32 m_dampingRatio; float32 m_bias; // Solver shared b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; float32 m_gamma; float32 m_impulse; float32 m_length; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_u; b2Vec2 m_rA; b2Vec2 m_rB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; float32 m_mass; }; inline void b2DistanceJoint::SetLength(float32 length) { m_length = length; } inline float32 b2DistanceJoint::GetLength() const { return m_length; } inline void b2DistanceJoint::SetFrequency(float32 hz) { m_frequencyHz = hz; } inline float32 b2DistanceJoint::GetFrequency() const { return m_frequencyHz; } inline void b2DistanceJoint::SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } inline float32 b2DistanceJoint::GetDampingRatio() const { return m_dampingRatio; } #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2FrictionJoint.cpp000066400000000000000000000153551276457661000226000ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // Point-to-point constraint // Cdot = v2 - v1 // = v2 + cross(w2, r2) - v1 - cross(w1, r1) // J = [-I -r1_skew I r2_skew ] // Identity used: // w k % (rx i + ry j) = w * (-ry i + rx j) // Angle constraint // Cdot = w2 - w1 // J = [0 0 -1 0 0 1] // K = invI1 + invI2 void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) { bodyA = bA; bodyB = bB; localAnchorA = bodyA->GetLocalPoint(anchor); localAnchorB = bodyB->GetLocalPoint(anchor); } b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def) : b2Joint(def) { m_localAnchorA = def->localAnchorA; m_localAnchorB = def->localAnchorB; m_linearImpulse.SetZero(); m_angularImpulse = 0.0f; m_maxForce = def->maxForce; m_maxTorque = def->maxTorque; } void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); // Compute the effective mass matrix. m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); // J = [-I -r1_skew I r2_skew] // [ 0 -1 0 1] // r_skew = [-ry; rx] // Matlab // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; b2Mat22 K; K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y; K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y; K.ey.x = K.ex.y; K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x; m_linearMass = K.GetInverse(); m_angularMass = iA + iB; if (m_angularMass > 0.0f) { m_angularMass = 1.0f / m_angularMass; } if (data.step.warmStarting) { // Scale impulses to support a variable time step. m_linearImpulse *= data.step.dtRatio; m_angularImpulse *= data.step.dtRatio; b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y); vA -= mA * P; wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse); vB += mB * P; wB += iB * (b2Cross(m_rB, P) + m_angularImpulse); } else { m_linearImpulse.SetZero(); m_angularImpulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; float32 h = data.step.dt; // Solve angular friction { float32 Cdot = wB - wA; float32 impulse = -m_angularMass * Cdot; float32 oldImpulse = m_angularImpulse; float32 maxImpulse = h * m_maxTorque; m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_angularImpulse - oldImpulse; wA -= iA * impulse; wB += iB * impulse; } // Solve linear friction { b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); b2Vec2 impulse = -b2Mul(m_linearMass, Cdot); b2Vec2 oldImpulse = m_linearImpulse; m_linearImpulse += impulse; float32 maxImpulse = h * m_maxForce; if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) { m_linearImpulse.Normalize(); m_linearImpulse *= maxImpulse; } impulse = m_linearImpulse - oldImpulse; vA -= mA * impulse; wA -= iA * b2Cross(m_rA, impulse); vB += mB * impulse; wB += iB * b2Cross(m_rB, impulse); } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data) { B2_NOT_USED(data); return true; } b2Vec2 b2FrictionJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2FrictionJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const { return inv_dt * m_linearImpulse; } float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * m_angularImpulse; } void b2FrictionJoint::SetMaxForce(float32 force) { b2Assert(b2IsValid(force) && force >= 0.0f); m_maxForce = force; } float32 b2FrictionJoint::GetMaxForce() const { return m_maxForce; } void b2FrictionJoint::SetMaxTorque(float32 torque) { b2Assert(b2IsValid(torque) && torque >= 0.0f); m_maxTorque = torque; } float32 b2FrictionJoint::GetMaxTorque() const { return m_maxTorque; } void b2FrictionJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2FrictionJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); b2Log(" jd.maxForce = %.15lef;\n", m_maxForce); b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2FrictionJoint.h000066400000000000000000000063311276457661000222370ustar00rootroot00000000000000/* * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_FRICTION_JOINT_H #define B2_FRICTION_JOINT_H #include /// Friction joint definition. struct b2FrictionJointDef : public b2JointDef { b2FrictionJointDef() { type = e_frictionJoint; localAnchorA.SetZero(); localAnchorB.SetZero(); maxForce = 0.0f; maxTorque = 0.0f; } /// Initialize the bodies, anchors, axis, and reference angle using the world /// anchor and world axis. void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); /// The local anchor point relative to bodyA's origin. b2Vec2 localAnchorA; /// The local anchor point relative to bodyB's origin. b2Vec2 localAnchorB; /// The maximum friction force in N. float32 maxForce; /// The maximum friction torque in N-m. float32 maxTorque; }; /// Friction joint. This is used for top-down friction. /// It provides 2D translational friction and angular friction. class b2FrictionJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// The local anchor point relative to bodyA's origin. const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } /// The local anchor point relative to bodyB's origin. const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } /// Set the maximum friction force in N. void SetMaxForce(float32 force); /// Get the maximum friction force in N. float32 GetMaxForce() const; /// Set the maximum friction torque in N*m. void SetMaxTorque(float32 torque); /// Get the maximum friction torque in N*m. float32 GetMaxTorque() const; /// Dump joint to dmLog void Dump(); protected: friend class b2Joint; b2FrictionJoint(const b2FrictionJointDef* def); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; // Solver shared b2Vec2 m_linearImpulse; float32 m_angularImpulse; float32 m_maxForce; float32 m_maxTorque; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_rA; b2Vec2 m_rB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; b2Mat22 m_linearMass; float32 m_angularMass; }; #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2GearJoint.cpp000066400000000000000000000265201276457661000216750ustar00rootroot00000000000000/* * Copyright (c) 2007-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include // Gear Joint: // C0 = (coordinate1 + ratio * coordinate2)_initial // C = (coordinate1 + ratio * coordinate2) - C0 = 0 // J = [J1 ratio * J2] // K = J * invM * JT // = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T // // Revolute: // coordinate = rotation // Cdot = angularVelocity // J = [0 0 1] // K = J * invM * JT = invI // // Prismatic: // coordinate = dot(p - pg, ug) // Cdot = dot(v + cross(w, r), ug) // J = [ug cross(r, ug)] // K = J * invM * JT = invMass + invI * cross(r, ug)^2 b2GearJoint::b2GearJoint(const b2GearJointDef* def) : b2Joint(def) { m_joint1 = def->joint1; m_joint2 = def->joint2; m_typeA = m_joint1->GetType(); m_typeB = m_joint2->GetType(); b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint); b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint); float32 coordinateA, coordinateB; // TODO_ERIN there might be some problem with the joint edges in b2Joint. m_bodyC = m_joint1->GetBodyA(); m_bodyA = m_joint1->GetBodyB(); // Get geometry of joint1 b2Transform xfA = m_bodyA->m_xf; float32 aA = m_bodyA->m_sweep.a; b2Transform xfC = m_bodyC->m_xf; float32 aC = m_bodyC->m_sweep.a; if (m_typeA == e_revoluteJoint) { b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1; m_localAnchorC = revolute->m_localAnchorA; m_localAnchorA = revolute->m_localAnchorB; m_referenceAngleA = revolute->m_referenceAngle; m_localAxisC.SetZero(); coordinateA = aA - aC - m_referenceAngleA; } else { b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1; m_localAnchorC = prismatic->m_localAnchorA; m_localAnchorA = prismatic->m_localAnchorB; m_referenceAngleA = prismatic->m_referenceAngle; m_localAxisC = prismatic->m_localXAxisA; b2Vec2 pC = m_localAnchorC; b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p)); coordinateA = b2Dot(pA - pC, m_localAxisC); } m_bodyD = m_joint2->GetBodyA(); m_bodyB = m_joint2->GetBodyB(); // Get geometry of joint2 b2Transform xfB = m_bodyB->m_xf; float32 aB = m_bodyB->m_sweep.a; b2Transform xfD = m_bodyD->m_xf; float32 aD = m_bodyD->m_sweep.a; if (m_typeB == e_revoluteJoint) { b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2; m_localAnchorD = revolute->m_localAnchorA; m_localAnchorB = revolute->m_localAnchorB; m_referenceAngleB = revolute->m_referenceAngle; m_localAxisD.SetZero(); coordinateB = aB - aD - m_referenceAngleB; } else { b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2; m_localAnchorD = prismatic->m_localAnchorA; m_localAnchorB = prismatic->m_localAnchorB; m_referenceAngleB = prismatic->m_referenceAngle; m_localAxisD = prismatic->m_localXAxisA; b2Vec2 pD = m_localAnchorD; b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p)); coordinateB = b2Dot(pB - pD, m_localAxisD); } m_ratio = def->ratio; m_constant = coordinateA + m_ratio * coordinateB; m_impulse = 0.0f; } void b2GearJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_indexC = m_bodyC->m_islandIndex; m_indexD = m_bodyD->m_islandIndex; m_lcA = m_bodyA->m_sweep.localCenter; m_lcB = m_bodyB->m_sweep.localCenter; m_lcC = m_bodyC->m_sweep.localCenter; m_lcD = m_bodyD->m_sweep.localCenter; m_mA = m_bodyA->m_invMass; m_mB = m_bodyB->m_invMass; m_mC = m_bodyC->m_invMass; m_mD = m_bodyD->m_invMass; m_iA = m_bodyA->m_invI; m_iB = m_bodyB->m_invI; m_iC = m_bodyC->m_invI; m_iD = m_bodyD->m_invI; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; float32 aC = data.positions[m_indexC].a; b2Vec2 vC = data.velocities[m_indexC].v; float32 wC = data.velocities[m_indexC].w; float32 aD = data.positions[m_indexD].a; b2Vec2 vD = data.velocities[m_indexD].v; float32 wD = data.velocities[m_indexD].w; b2Rot qA(aA), qB(aB), qC(aC), qD(aD); m_mass = 0.0f; if (m_typeA == e_revoluteJoint) { m_JvAC.SetZero(); m_JwA = 1.0f; m_JwC = 1.0f; m_mass += m_iA + m_iC; } else { b2Vec2 u = b2Mul(qC, m_localAxisC); b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); m_JvAC = u; m_JwC = b2Cross(rC, u); m_JwA = b2Cross(rA, u); m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA; } if (m_typeB == e_revoluteJoint) { m_JvBD.SetZero(); m_JwB = m_ratio; m_JwD = m_ratio; m_mass += m_ratio * m_ratio * (m_iB + m_iD); } else { b2Vec2 u = b2Mul(qD, m_localAxisD); b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); m_JvBD = m_ratio * u; m_JwD = m_ratio * b2Cross(rD, u); m_JwB = m_ratio * b2Cross(rB, u); m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB; } // Compute effective mass. m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f; if (data.step.warmStarting) { vA += (m_mA * m_impulse) * m_JvAC; wA += m_iA * m_impulse * m_JwA; vB += (m_mB * m_impulse) * m_JvBD; wB += m_iB * m_impulse * m_JwB; vC -= (m_mC * m_impulse) * m_JvAC; wC -= m_iC * m_impulse * m_JwC; vD -= (m_mD * m_impulse) * m_JvBD; wD -= m_iD * m_impulse * m_JwD; } else { m_impulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; data.velocities[m_indexC].v = vC; data.velocities[m_indexC].w = wC; data.velocities[m_indexD].v = vD; data.velocities[m_indexD].w = wD; } void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Vec2 vC = data.velocities[m_indexC].v; float32 wC = data.velocities[m_indexC].w; b2Vec2 vD = data.velocities[m_indexD].v; float32 wD = data.velocities[m_indexD].w; float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD); Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD); float32 impulse = -m_mass * Cdot; m_impulse += impulse; vA += (m_mA * impulse) * m_JvAC; wA += m_iA * impulse * m_JwA; vB += (m_mB * impulse) * m_JvBD; wB += m_iB * impulse * m_JwB; vC -= (m_mC * impulse) * m_JvAC; wC -= m_iC * impulse * m_JwC; vD -= (m_mD * impulse) * m_JvBD; wD -= m_iD * impulse * m_JwD; data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; data.velocities[m_indexC].v = vC; data.velocities[m_indexC].w = wC; data.velocities[m_indexD].v = vD; data.velocities[m_indexD].w = wD; } bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data) { b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Vec2 cC = data.positions[m_indexC].c; float32 aC = data.positions[m_indexC].a; b2Vec2 cD = data.positions[m_indexD].c; float32 aD = data.positions[m_indexD].a; b2Rot qA(aA), qB(aB), qC(aC), qD(aD); float32 linearError = 0.0f; float32 coordinateA, coordinateB; b2Vec2 JvAC, JvBD; float32 JwA, JwB, JwC, JwD; float32 mass = 0.0f; if (m_typeA == e_revoluteJoint) { JvAC.SetZero(); JwA = 1.0f; JwC = 1.0f; mass += m_iA + m_iC; coordinateA = aA - aC - m_referenceAngleA; } else { b2Vec2 u = b2Mul(qC, m_localAxisC); b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC); b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA); JvAC = u; JwC = b2Cross(rC, u); JwA = b2Cross(rA, u); mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA; b2Vec2 pC = m_localAnchorC - m_lcC; b2Vec2 pA = b2MulT(qC, rA + (cA - cC)); coordinateA = b2Dot(pA - pC, m_localAxisC); } if (m_typeB == e_revoluteJoint) { JvBD.SetZero(); JwB = m_ratio; JwD = m_ratio; mass += m_ratio * m_ratio * (m_iB + m_iD); coordinateB = aB - aD - m_referenceAngleB; } else { b2Vec2 u = b2Mul(qD, m_localAxisD); b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB); JvBD = m_ratio * u; JwD = m_ratio * b2Cross(rD, u); JwB = m_ratio * b2Cross(rB, u); mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB; b2Vec2 pD = m_localAnchorD - m_lcD; b2Vec2 pB = b2MulT(qD, rB + (cB - cD)); coordinateB = b2Dot(pB - pD, m_localAxisD); } float32 C = (coordinateA + m_ratio * coordinateB) - m_constant; float32 impulse = 0.0f; if (mass > 0.0f) { impulse = -C / mass; } cA += m_mA * impulse * JvAC; aA += m_iA * impulse * JwA; cB += m_mB * impulse * JvBD; aB += m_iB * impulse * JwB; cC -= m_mC * impulse * JvAC; aC -= m_iC * impulse * JwC; cD -= m_mD * impulse * JvBD; aD -= m_iD * impulse * JwD; data.positions[m_indexA].c = cA; data.positions[m_indexA].a = aA; data.positions[m_indexB].c = cB; data.positions[m_indexB].a = aB; data.positions[m_indexC].c = cC; data.positions[m_indexC].a = aC; data.positions[m_indexD].c = cD; data.positions[m_indexD].a = aD; // TODO_ERIN not implemented return linearError < b2_linearSlop; } b2Vec2 b2GearJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2GearJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 P = m_impulse * m_JvAC; return inv_dt * P; } float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const { float32 L = m_impulse * m_JwA; return inv_dt * L; } void b2GearJoint::SetRatio(float32 ratio) { b2Assert(b2IsValid(ratio)); m_ratio = ratio; } float32 b2GearJoint::GetRatio() const { return m_ratio; } void b2GearJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; int32 index1 = m_joint1->m_index; int32 index2 = m_joint2->m_index; b2Log(" b2GearJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.joint1 = joints[%d];\n", index1); b2Log(" jd.joint2 = joints[%d];\n", index2); b2Log(" jd.ratio = %.15lef;\n", m_ratio); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2GearJoint.h000066400000000000000000000066071276457661000213460ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_GEAR_JOINT_H #define B2_GEAR_JOINT_H #include /// Gear joint definition. This definition requires two existing /// revolute or prismatic joints (any combination will work). struct b2GearJointDef : public b2JointDef { b2GearJointDef() { type = e_gearJoint; joint1 = NULL; joint2 = NULL; ratio = 1.0f; } /// The first revolute/prismatic joint attached to the gear joint. b2Joint* joint1; /// The second revolute/prismatic joint attached to the gear joint. b2Joint* joint2; /// The gear ratio. /// @see b2GearJoint for explanation. float32 ratio; }; /// A gear joint is used to connect two joints together. Either joint /// can be a revolute or prismatic joint. You specify a gear ratio /// to bind the motions together: /// coordinate1 + ratio * coordinate2 = constant /// The ratio can be negative or positive. If one joint is a revolute joint /// and the other joint is a prismatic joint, then the ratio will have units /// of length or units of 1/length. /// @warning You have to manually destroy the gear joint if joint1 or joint2 /// is destroyed. class b2GearJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// Get the first joint. b2Joint* GetJoint1() { return m_joint1; } /// Get the second joint. b2Joint* GetJoint2() { return m_joint2; } /// Set/Get the gear ratio. void SetRatio(float32 ratio); float32 GetRatio() const; /// Dump joint to dmLog void Dump(); protected: friend class b2Joint; b2GearJoint(const b2GearJointDef* data); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); b2Joint* m_joint1; b2Joint* m_joint2; b2JointType m_typeA; b2JointType m_typeB; // Body A is connected to body C // Body B is connected to body D b2Body* m_bodyC; b2Body* m_bodyD; // Solver shared b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; b2Vec2 m_localAnchorC; b2Vec2 m_localAnchorD; b2Vec2 m_localAxisC; b2Vec2 m_localAxisD; float32 m_referenceAngleA; float32 m_referenceAngleB; float32 m_constant; float32 m_ratio; float32 m_impulse; // Solver temp int32 m_indexA, m_indexB, m_indexC, m_indexD; b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD; float32 m_mA, m_mB, m_mC, m_mD; float32 m_iA, m_iB, m_iC, m_iD; b2Vec2 m_JvAC, m_JvBD; float32 m_JwA, m_JwB, m_JwC, m_JwD; float32 m_mass; }; #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2Joint.cpp000066400000000000000000000120361276457661000210730ustar00rootroot00000000000000/* * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator) { b2Joint* joint = NULL; switch (def->type) { case e_distanceJoint: { void* mem = allocator->Allocate(sizeof(b2DistanceJoint)); joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def); } break; case e_mouseJoint: { void* mem = allocator->Allocate(sizeof(b2MouseJoint)); joint = new (mem) b2MouseJoint((b2MouseJointDef*)def); } break; case e_prismaticJoint: { void* mem = allocator->Allocate(sizeof(b2PrismaticJoint)); joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def); } break; case e_revoluteJoint: { void* mem = allocator->Allocate(sizeof(b2RevoluteJoint)); joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def); } break; case e_pulleyJoint: { void* mem = allocator->Allocate(sizeof(b2PulleyJoint)); joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def); } break; case e_gearJoint: { void* mem = allocator->Allocate(sizeof(b2GearJoint)); joint = new (mem) b2GearJoint((b2GearJointDef*)def); } break; case e_wheelJoint: { void* mem = allocator->Allocate(sizeof(b2WheelJoint)); joint = new (mem) b2WheelJoint((b2WheelJointDef*)def); } break; case e_weldJoint: { void* mem = allocator->Allocate(sizeof(b2WeldJoint)); joint = new (mem) b2WeldJoint((b2WeldJointDef*)def); } break; case e_frictionJoint: { void* mem = allocator->Allocate(sizeof(b2FrictionJoint)); joint = new (mem) b2FrictionJoint((b2FrictionJointDef*)def); } break; case e_ropeJoint: { void* mem = allocator->Allocate(sizeof(b2RopeJoint)); joint = new (mem) b2RopeJoint((b2RopeJointDef*)def); } break; case e_motorJoint: { void* mem = allocator->Allocate(sizeof(b2MotorJoint)); joint = new (mem) b2MotorJoint((b2MotorJointDef*)def); } break; default: b2Assert(false); break; } return joint; } void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator) { joint->~b2Joint(); switch (joint->m_type) { case e_distanceJoint: allocator->Free(joint, sizeof(b2DistanceJoint)); break; case e_mouseJoint: allocator->Free(joint, sizeof(b2MouseJoint)); break; case e_prismaticJoint: allocator->Free(joint, sizeof(b2PrismaticJoint)); break; case e_revoluteJoint: allocator->Free(joint, sizeof(b2RevoluteJoint)); break; case e_pulleyJoint: allocator->Free(joint, sizeof(b2PulleyJoint)); break; case e_gearJoint: allocator->Free(joint, sizeof(b2GearJoint)); break; case e_wheelJoint: allocator->Free(joint, sizeof(b2WheelJoint)); break; case e_weldJoint: allocator->Free(joint, sizeof(b2WeldJoint)); break; case e_frictionJoint: allocator->Free(joint, sizeof(b2FrictionJoint)); break; case e_ropeJoint: allocator->Free(joint, sizeof(b2RopeJoint)); break; case e_motorJoint: allocator->Free(joint, sizeof(b2MotorJoint)); break; default: b2Assert(false); break; } } b2Joint::b2Joint(const b2JointDef* def) { b2Assert(def->bodyA != def->bodyB); m_type = def->type; m_prev = NULL; m_next = NULL; m_bodyA = def->bodyA; m_bodyB = def->bodyB; m_index = 0; m_collideConnected = def->collideConnected; m_islandFlag = false; m_userData = def->userData; m_edgeA.joint = NULL; m_edgeA.other = NULL; m_edgeA.prev = NULL; m_edgeA.next = NULL; m_edgeB.joint = NULL; m_edgeB.other = NULL; m_edgeB.prev = NULL; m_edgeB.next = NULL; } bool b2Joint::IsActive() const { return m_bodyA->IsActive() && m_bodyB->IsActive(); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2Joint.h000066400000000000000000000126031276457661000205400ustar00rootroot00000000000000/* * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_JOINT_H #define B2_JOINT_H #include class b2Body; class b2Joint; struct b2SolverData; class b2BlockAllocator; enum b2JointType { e_unknownJoint, e_revoluteJoint, e_prismaticJoint, e_distanceJoint, e_pulleyJoint, e_mouseJoint, e_gearJoint, e_wheelJoint, e_weldJoint, e_frictionJoint, e_ropeJoint, e_motorJoint }; enum b2LimitState { e_inactiveLimit, e_atLowerLimit, e_atUpperLimit, e_equalLimits }; struct b2Jacobian { b2Vec2 linear; float32 angularA; float32 angularB; }; /// A joint edge is used to connect bodies and joints together /// in a joint graph where each body is a node and each joint /// is an edge. A joint edge belongs to a doubly linked list /// maintained in each attached body. Each joint has two joint /// nodes, one for each attached body. struct b2JointEdge { b2Body* other; ///< provides quick access to the other body attached. b2Joint* joint; ///< the joint b2JointEdge* prev; ///< the previous joint edge in the body's joint list b2JointEdge* next; ///< the next joint edge in the body's joint list }; /// Joint definitions are used to construct joints. struct b2JointDef { b2JointDef() { type = e_unknownJoint; userData = NULL; bodyA = NULL; bodyB = NULL; collideConnected = false; } /// The joint type is set automatically for concrete joint types. b2JointType type; /// Use this to attach application specific data to your joints. void* userData; /// The first attached body. b2Body* bodyA; /// The second attached body. b2Body* bodyB; /// Set this flag to true if the attached bodies should collide. bool collideConnected; }; /// The base joint class. Joints are used to constraint two bodies together in /// various fashions. Some joints also feature limits and motors. class b2Joint { public: /// Get the type of the concrete joint. b2JointType GetType() const; /// Get the first body attached to this joint. b2Body* GetBodyA(); /// Get the second body attached to this joint. b2Body* GetBodyB(); /// Get the anchor point on bodyA in world coordinates. virtual b2Vec2 GetAnchorA() const = 0; /// Get the anchor point on bodyB in world coordinates. virtual b2Vec2 GetAnchorB() const = 0; /// Get the reaction force on bodyB at the joint anchor in Newtons. virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0; /// Get the reaction torque on bodyB in N*m. virtual float32 GetReactionTorque(float32 inv_dt) const = 0; /// Get the next joint the world joint list. b2Joint* GetNext(); const b2Joint* GetNext() const; /// Get the user data pointer. void* GetUserData() const; /// Set the user data pointer. void SetUserData(void* data); /// Short-cut function to determine if either body is inactive. bool IsActive() const; /// Get collide connected. /// Note: modifying the collide connect flag won't work correctly because /// the flag is only checked when fixture AABBs begin to overlap. bool GetCollideConnected() const; /// Dump this joint to the log file. virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); } /// Shift the origin for any points stored in world coordinates. virtual void ShiftOrigin(const b2Vec2& newOrigin) { B2_NOT_USED(newOrigin); } protected: friend class b2World; friend class b2Body; friend class b2Island; friend class b2GearJoint; static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator); static void Destroy(b2Joint* joint, b2BlockAllocator* allocator); b2Joint(const b2JointDef* def); virtual ~b2Joint() {} virtual void InitVelocityConstraints(const b2SolverData& data) = 0; virtual void SolveVelocityConstraints(const b2SolverData& data) = 0; // This returns true if the position errors are within tolerance. virtual bool SolvePositionConstraints(const b2SolverData& data) = 0; b2JointType m_type; b2Joint* m_prev; b2Joint* m_next; b2JointEdge m_edgeA; b2JointEdge m_edgeB; b2Body* m_bodyA; b2Body* m_bodyB; int32 m_index; bool m_islandFlag; bool m_collideConnected; void* m_userData; }; inline b2JointType b2Joint::GetType() const { return m_type; } inline b2Body* b2Joint::GetBodyA() { return m_bodyA; } inline b2Body* b2Joint::GetBodyB() { return m_bodyB; } inline b2Joint* b2Joint::GetNext() { return m_next; } inline const b2Joint* b2Joint::GetNext() const { return m_next; } inline void* b2Joint::GetUserData() const { return m_userData; } inline void b2Joint::SetUserData(void* data) { m_userData = data; } inline bool b2Joint::GetCollideConnected() const { return m_collideConnected; } #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2MotorJoint.cpp000066400000000000000000000172501276457661000221170ustar00rootroot00000000000000/* * Copyright (c) 2006-2012 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // Point-to-point constraint // Cdot = v2 - v1 // = v2 + cross(w2, r2) - v1 - cross(w1, r1) // J = [-I -r1_skew I r2_skew ] // Identity used: // w k % (rx i + ry j) = w * (-ry i + rx j) // Angle constraint // Cdot = w2 - w1 // J = [0 0 -1 0 0 1] // K = invI1 + invI2 void b2MotorJointDef::Initialize(b2Body* bA, b2Body* bB) { bodyA = bA; bodyB = bB; b2Vec2 xB = bodyB->GetPosition(); linearOffset = bodyA->GetLocalPoint(xB); float32 angleA = bodyA->GetAngle(); float32 angleB = bodyB->GetAngle(); angularOffset = angleB - angleA; } b2MotorJoint::b2MotorJoint(const b2MotorJointDef* def) : b2Joint(def) { m_linearOffset = def->linearOffset; m_angularOffset = def->angularOffset; m_linearImpulse.SetZero(); m_angularImpulse = 0.0f; m_maxForce = def->maxForce; m_maxTorque = def->maxTorque; m_correctionFactor = def->correctionFactor; } void b2MotorJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); // Compute the effective mass matrix. m_rA = b2Mul(qA, -m_localCenterA); m_rB = b2Mul(qB, -m_localCenterB); // J = [-I -r1_skew I r2_skew] // [ 0 -1 0 1] // r_skew = [-ry; rx] // Matlab // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; b2Mat22 K; K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y; K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y; K.ey.x = K.ex.y; K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x; m_linearMass = K.GetInverse(); m_angularMass = iA + iB; if (m_angularMass > 0.0f) { m_angularMass = 1.0f / m_angularMass; } m_linearError = cB + m_rB - cA - m_rA - b2Mul(qA, m_linearOffset); m_angularError = aB - aA - m_angularOffset; if (data.step.warmStarting) { // Scale impulses to support a variable time step. m_linearImpulse *= data.step.dtRatio; m_angularImpulse *= data.step.dtRatio; b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y); vA -= mA * P; wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse); vB += mB * P; wB += iB * (b2Cross(m_rB, P) + m_angularImpulse); } else { m_linearImpulse.SetZero(); m_angularImpulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2MotorJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; float32 h = data.step.dt; float32 inv_h = data.step.inv_dt; // Solve angular friction { float32 Cdot = wB - wA + inv_h * m_correctionFactor * m_angularError; float32 impulse = -m_angularMass * Cdot; float32 oldImpulse = m_angularImpulse; float32 maxImpulse = h * m_maxTorque; m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_angularImpulse - oldImpulse; wA -= iA * impulse; wB += iB * impulse; } // Solve linear friction { b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA) + inv_h * m_correctionFactor * m_linearError; b2Vec2 impulse = -b2Mul(m_linearMass, Cdot); b2Vec2 oldImpulse = m_linearImpulse; m_linearImpulse += impulse; float32 maxImpulse = h * m_maxForce; if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) { m_linearImpulse.Normalize(); m_linearImpulse *= maxImpulse; } impulse = m_linearImpulse - oldImpulse; vA -= mA * impulse; wA -= iA * b2Cross(m_rA, impulse); vB += mB * impulse; wB += iB * b2Cross(m_rB, impulse); } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2MotorJoint::SolvePositionConstraints(const b2SolverData& data) { B2_NOT_USED(data); return true; } b2Vec2 b2MotorJoint::GetAnchorA() const { return m_bodyA->GetPosition(); } b2Vec2 b2MotorJoint::GetAnchorB() const { return m_bodyB->GetPosition(); } b2Vec2 b2MotorJoint::GetReactionForce(float32 inv_dt) const { return inv_dt * m_linearImpulse; } float32 b2MotorJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * m_angularImpulse; } void b2MotorJoint::SetMaxForce(float32 force) { b2Assert(b2IsValid(force) && force >= 0.0f); m_maxForce = force; } float32 b2MotorJoint::GetMaxForce() const { return m_maxForce; } void b2MotorJoint::SetMaxTorque(float32 torque) { b2Assert(b2IsValid(torque) && torque >= 0.0f); m_maxTorque = torque; } float32 b2MotorJoint::GetMaxTorque() const { return m_maxTorque; } void b2MotorJoint::SetLinearOffset(const b2Vec2& linearOffset) { if (linearOffset.x != m_linearOffset.x || linearOffset.y != m_linearOffset.y) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_linearOffset = linearOffset; } } const b2Vec2& b2MotorJoint::GetLinearOffset() const { return m_linearOffset; } void b2MotorJoint::SetAngularOffset(float32 angularOffset) { if (angularOffset != m_angularOffset) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_angularOffset = angularOffset; } } float32 b2MotorJoint::GetAngularOffset() const { return m_angularOffset; } void b2MotorJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2MotorJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.linearOffset.Set(%.15lef, %.15lef);\n", m_linearOffset.x, m_linearOffset.y); b2Log(" jd.angularOffset = %.15lef;\n", m_angularOffset); b2Log(" jd.maxForce = %.15lef;\n", m_maxForce); b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque); b2Log(" jd.correctionFactor = %.15lef;\n", m_correctionFactor); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2MotorJoint.h000066400000000000000000000066441276457661000215710ustar00rootroot00000000000000/* * Copyright (c) 2006-2012 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_MOTOR_JOINT_H #define B2_MOTOR_JOINT_H #include /// Motor joint definition. struct b2MotorJointDef : public b2JointDef { b2MotorJointDef() { type = e_motorJoint; linearOffset.SetZero(); angularOffset = 0.0f; maxForce = 1.0f; maxTorque = 1.0f; correctionFactor = 0.3f; } /// Initialize the bodies and offsets using the current transforms. void Initialize(b2Body* bodyA, b2Body* bodyB); /// Position of bodyB minus the position of bodyA, in bodyA's frame, in meters. b2Vec2 linearOffset; /// The bodyB angle minus bodyA angle in radians. float32 angularOffset; /// The maximum motor force in N. float32 maxForce; /// The maximum motor torque in N-m. float32 maxTorque; /// Position correction factor in the range [0,1]. float32 correctionFactor; }; /// A motor joint is used to control the relative motion /// between two bodies. A typical usage is to control the movement /// of a dynamic body with respect to the ground. class b2MotorJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// Set/get the target linear offset, in frame A, in meters. void SetLinearOffset(const b2Vec2& linearOffset); const b2Vec2& GetLinearOffset() const; /// Set/get the target angular offset, in radians. void SetAngularOffset(float32 angularOffset); float32 GetAngularOffset() const; /// Set the maximum friction force in N. void SetMaxForce(float32 force); /// Get the maximum friction force in N. float32 GetMaxForce() const; /// Set the maximum friction torque in N*m. void SetMaxTorque(float32 torque); /// Get the maximum friction torque in N*m. float32 GetMaxTorque() const; /// Dump to b2Log void Dump(); protected: friend class b2Joint; b2MotorJoint(const b2MotorJointDef* def); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); // Solver shared b2Vec2 m_linearOffset; float32 m_angularOffset; b2Vec2 m_linearImpulse; float32 m_angularImpulse; float32 m_maxForce; float32 m_maxTorque; float32 m_correctionFactor; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_rA; b2Vec2 m_rB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; b2Vec2 m_linearError; float32 m_angularError; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; b2Mat22 m_linearMass; float32 m_angularMass; }; #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2MouseJoint.cpp000066400000000000000000000125401276457661000221040ustar00rootroot00000000000000/* * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // p = attached point, m = mouse point // C = p - m // Cdot = v // = v + cross(w, r) // J = [I r_skew] // Identity used: // w k % (rx i + ry j) = w * (-ry i + rx j) b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def) : b2Joint(def) { b2Assert(def->target.IsValid()); b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f); b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f); b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f); m_targetA = def->target; m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA); m_maxForce = def->maxForce; m_impulse.SetZero(); m_frequencyHz = def->frequencyHz; m_dampingRatio = def->dampingRatio; m_beta = 0.0f; m_gamma = 0.0f; } void b2MouseJoint::SetTarget(const b2Vec2& target) { if (m_bodyB->IsAwake() == false) { m_bodyB->SetAwake(true); } m_targetA = target; } const b2Vec2& b2MouseJoint::GetTarget() const { return m_targetA; } void b2MouseJoint::SetMaxForce(float32 force) { m_maxForce = force; } float32 b2MouseJoint::GetMaxForce() const { return m_maxForce; } void b2MouseJoint::SetFrequency(float32 hz) { m_frequencyHz = hz; } float32 b2MouseJoint::GetFrequency() const { return m_frequencyHz; } void b2MouseJoint::SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } float32 b2MouseJoint::GetDampingRatio() const { return m_dampingRatio; } void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexB = m_bodyB->m_islandIndex; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassB = m_bodyB->m_invMass; m_invIB = m_bodyB->m_invI; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qB(aB); float32 mass = m_bodyB->GetMass(); // Frequency float32 omega = 2.0f * b2_pi * m_frequencyHz; // Damping coefficient float32 d = 2.0f * mass * m_dampingRatio * omega; // Spring stiffness float32 k = mass * (omega * omega); // magic formulas // gamma has units of inverse mass. // beta has units of inverse time. float32 h = data.step.dt; b2Assert(d + h * k > b2_epsilon); m_gamma = h * (d + h * k); if (m_gamma != 0.0f) { m_gamma = 1.0f / m_gamma; } m_beta = h * k * m_gamma; // Compute the effective mass matrix. m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)] // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y] // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x] b2Mat22 K; K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma; K.ex.y = -m_invIB * m_rB.x * m_rB.y; K.ey.x = K.ex.y; K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma; m_mass = K.GetInverse(); m_C = cB + m_rB - m_targetA; m_C *= m_beta; // Cheat with some damping wB *= 0.98f; if (data.step.warmStarting) { m_impulse *= data.step.dtRatio; vB += m_invMassB * m_impulse; wB += m_invIB * b2Cross(m_rB, m_impulse); } else { m_impulse.SetZero(); } data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; // Cdot = v + cross(w, r) b2Vec2 Cdot = vB + b2Cross(wB, m_rB); b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse)); b2Vec2 oldImpulse = m_impulse; m_impulse += impulse; float32 maxImpulse = data.step.dt * m_maxForce; if (m_impulse.LengthSquared() > maxImpulse * maxImpulse) { m_impulse *= maxImpulse / m_impulse.Length(); } impulse = m_impulse - oldImpulse; vB += m_invMassB * impulse; wB += m_invIB * b2Cross(m_rB, impulse); data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data) { B2_NOT_USED(data); return true; } b2Vec2 b2MouseJoint::GetAnchorA() const { return m_targetA; } b2Vec2 b2MouseJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const { return inv_dt * m_impulse; } float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * 0.0f; } void b2MouseJoint::ShiftOrigin(const b2Vec2& newOrigin) { m_targetA -= newOrigin; } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2MouseJoint.h000066400000000000000000000071511276457661000215530ustar00rootroot00000000000000/* * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_MOUSE_JOINT_H #define B2_MOUSE_JOINT_H #include /// Mouse joint definition. This requires a world target point, /// tuning parameters, and the time step. struct b2MouseJointDef : public b2JointDef { b2MouseJointDef() { type = e_mouseJoint; target.Set(0.0f, 0.0f); maxForce = 0.0f; frequencyHz = 5.0f; dampingRatio = 0.7f; } /// The initial world target point. This is assumed /// to coincide with the body anchor initially. b2Vec2 target; /// The maximum constraint force that can be exerted /// to move the candidate body. Usually you will express /// as some multiple of the weight (multiplier * mass * gravity). float32 maxForce; /// The response speed. float32 frequencyHz; /// The damping ratio. 0 = no damping, 1 = critical damping. float32 dampingRatio; }; /// A mouse joint is used to make a point on a body track a /// specified world point. This a soft constraint with a maximum /// force. This allows the constraint to stretch and without /// applying huge forces. /// NOTE: this joint is not documented in the manual because it was /// developed to be used in the testbed. If you want to learn how to /// use the mouse joint, look at the testbed. class b2MouseJoint : public b2Joint { public: /// Implements b2Joint. b2Vec2 GetAnchorA() const; /// Implements b2Joint. b2Vec2 GetAnchorB() const; /// Implements b2Joint. b2Vec2 GetReactionForce(float32 inv_dt) const; /// Implements b2Joint. float32 GetReactionTorque(float32 inv_dt) const; /// Use this to update the target point. void SetTarget(const b2Vec2& target); const b2Vec2& GetTarget() const; /// Set/get the maximum force in Newtons. void SetMaxForce(float32 force); float32 GetMaxForce() const; /// Set/get the frequency in Hertz. void SetFrequency(float32 hz); float32 GetFrequency() const; /// Set/get the damping ratio (dimensionless). void SetDampingRatio(float32 ratio); float32 GetDampingRatio() const; /// The mouse joint does not support dumping. void Dump() { b2Log("Mouse joint dumping is not supported.\n"); } /// Implement b2Joint::ShiftOrigin void ShiftOrigin(const b2Vec2& newOrigin); protected: friend class b2Joint; b2MouseJoint(const b2MouseJointDef* def); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); b2Vec2 m_localAnchorB; b2Vec2 m_targetA; float32 m_frequencyHz; float32 m_dampingRatio; float32 m_beta; // Solver shared b2Vec2 m_impulse; float32 m_maxForce; float32 m_gamma; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_rB; b2Vec2 m_localCenterB; float32 m_invMassB; float32 m_invIB; b2Mat22 m_mass; b2Vec2 m_C; }; #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp000066400000000000000000000407211276457661000227510ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // Linear constraint (point-to-line) // d = p2 - p1 = x2 + r2 - x1 - r1 // C = dot(perp, d) // Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) // = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) // J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] // // Angular constraint // C = a2 - a1 + a_initial // Cdot = w2 - w1 // J = [0 0 -1 0 0 1] // // K = J * invM * JT // // J = [-a -s1 a s2] // [0 -1 0 1] // a = perp // s1 = cross(d + r1, a) = cross(p2 - x1, a) // s2 = cross(r2, a) = cross(p2 - x2, a) // Motor/Limit linear constraint // C = dot(ax1, d) // Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) // J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] // Block Solver // We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even // when the mass has poor distribution (leading to large torques about the joint anchor points). // // The Jacobian has 3 rows: // J = [-uT -s1 uT s2] // linear // [0 -1 0 1] // angular // [-vT -a1 vT a2] // limit // // u = perp // v = axis // s1 = cross(d + r1, u), s2 = cross(r2, u) // a1 = cross(d + r1, v), a2 = cross(r2, v) // M * (v2 - v1) = JT * df // J * v2 = bias // // v2 = v1 + invM * JT * df // J * (v1 + invM * JT * df) = bias // K * df = bias - J * v1 = -Cdot // K = J * invM * JT // Cdot = J * v1 - bias // // Now solve for f2. // df = f2 - f1 // K * (f2 - f1) = -Cdot // f2 = invK * (-Cdot) + f1 // // Clamp accumulated limit impulse. // lower: f2(3) = max(f2(3), 0) // upper: f2(3) = min(f2(3), 0) // // Solve for correct f2(1:2) // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 // = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2) // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) // // Now compute impulse to be applied: // df = f2 - f1 void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) { bodyA = bA; bodyB = bB; localAnchorA = bodyA->GetLocalPoint(anchor); localAnchorB = bodyB->GetLocalPoint(anchor); localAxisA = bodyA->GetLocalVector(axis); referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); } b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) : b2Joint(def) { m_localAnchorA = def->localAnchorA; m_localAnchorB = def->localAnchorB; m_localXAxisA = def->localAxisA; m_localXAxisA.Normalize(); m_localYAxisA = b2Cross(1.0f, m_localXAxisA); m_referenceAngle = def->referenceAngle; m_impulse.SetZero(); m_motorMass = 0.0f; m_motorImpulse = 0.0f; m_lowerTranslation = def->lowerTranslation; m_upperTranslation = def->upperTranslation; m_maxMotorForce = def->maxMotorForce; m_motorSpeed = def->motorSpeed; m_enableLimit = def->enableLimit; m_enableMotor = def->enableMotor; m_limitState = e_inactiveLimit; m_axis.SetZero(); m_perp.SetZero(); } void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); // Compute the effective masses. b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); b2Vec2 d = (cB - cA) + rB - rA; float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; // Compute motor Jacobian and effective mass. { m_axis = b2Mul(qA, m_localXAxisA); m_a1 = b2Cross(d + rA, m_axis); m_a2 = b2Cross(rB, m_axis); m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; if (m_motorMass > 0.0f) { m_motorMass = 1.0f / m_motorMass; } } // Prismatic constraint. { m_perp = b2Mul(qA, m_localYAxisA); m_s1 = b2Cross(d + rA, m_perp); m_s2 = b2Cross(rB, m_perp); float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2; float32 k12 = iA * m_s1 + iB * m_s2; float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2; float32 k22 = iA + iB; if (k22 == 0.0f) { // For bodies with fixed rotation. k22 = 1.0f; } float32 k23 = iA * m_a1 + iB * m_a2; float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; m_K.ex.Set(k11, k12, k13); m_K.ey.Set(k12, k22, k23); m_K.ez.Set(k13, k23, k33); } // Compute motor and limit terms. if (m_enableLimit) { float32 jointTranslation = b2Dot(m_axis, d); if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) { m_limitState = e_equalLimits; } else if (jointTranslation <= m_lowerTranslation) { if (m_limitState != e_atLowerLimit) { m_limitState = e_atLowerLimit; m_impulse.z = 0.0f; } } else if (jointTranslation >= m_upperTranslation) { if (m_limitState != e_atUpperLimit) { m_limitState = e_atUpperLimit; m_impulse.z = 0.0f; } } else { m_limitState = e_inactiveLimit; m_impulse.z = 0.0f; } } else { m_limitState = e_inactiveLimit; m_impulse.z = 0.0f; } if (m_enableMotor == false) { m_motorImpulse = 0.0f; } if (data.step.warmStarting) { // Account for variable time step. m_impulse *= data.step.dtRatio; m_motorImpulse *= data.step.dtRatio; b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } else { m_impulse.SetZero(); m_motorImpulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; // Solve linear motor constraint. if (m_enableMotor && m_limitState != e_equalLimits) { float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; float32 impulse = m_motorMass * (m_motorSpeed - Cdot); float32 oldImpulse = m_motorImpulse; float32 maxImpulse = data.step.dt * m_maxMotorForce; m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; b2Vec2 P = impulse * m_axis; float32 LA = impulse * m_a1; float32 LB = impulse * m_a2; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } b2Vec2 Cdot1; Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; Cdot1.y = wB - wA; if (m_enableLimit && m_limitState != e_inactiveLimit) { // Solve prismatic and limit constraint in block form. float32 Cdot2; Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); b2Vec3 f1 = m_impulse; b2Vec3 df = m_K.Solve33(-Cdot); m_impulse += df; if (m_limitState == e_atLowerLimit) { m_impulse.z = b2Max(m_impulse.z, 0.0f); } else if (m_limitState == e_atUpperLimit) { m_impulse.z = b2Min(m_impulse.z, 0.0f); } // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y); b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); m_impulse.x = f2r.x; m_impulse.y = f2r.y; df = m_impulse - f1; b2Vec2 P = df.x * m_perp + df.z * m_axis; float32 LA = df.x * m_s1 + df.y + df.z * m_a1; float32 LB = df.x * m_s2 + df.y + df.z * m_a2; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } else { // Limit is inactive, just solve the prismatic constraint in block form. b2Vec2 df = m_K.Solve22(-Cdot1); m_impulse.x += df.x; m_impulse.y += df.y; b2Vec2 P = df.x * m_perp; float32 LA = df.x * m_s1 + df.y; float32 LB = df.x * m_s2 + df.y; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data) { b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Rot qA(aA), qB(aB); float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; // Compute fresh Jacobians b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); b2Vec2 d = cB + rB - cA - rA; b2Vec2 axis = b2Mul(qA, m_localXAxisA); float32 a1 = b2Cross(d + rA, axis); float32 a2 = b2Cross(rB, axis); b2Vec2 perp = b2Mul(qA, m_localYAxisA); float32 s1 = b2Cross(d + rA, perp); float32 s2 = b2Cross(rB, perp); b2Vec3 impulse; b2Vec2 C1; C1.x = b2Dot(perp, d); C1.y = aB - aA - m_referenceAngle; float32 linearError = b2Abs(C1.x); float32 angularError = b2Abs(C1.y); bool active = false; float32 C2 = 0.0f; if (m_enableLimit) { float32 translation = b2Dot(axis, d); if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) { // Prevent large angular corrections C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); linearError = b2Max(linearError, b2Abs(translation)); active = true; } else if (translation <= m_lowerTranslation) { // Prevent large linear corrections and allow some slop. C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); linearError = b2Max(linearError, m_lowerTranslation - translation); active = true; } else if (translation >= m_upperTranslation) { // Prevent large linear corrections and allow some slop. C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); linearError = b2Max(linearError, translation - m_upperTranslation); active = true; } } if (active) { float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; float32 k12 = iA * s1 + iB * s2; float32 k13 = iA * s1 * a1 + iB * s2 * a2; float32 k22 = iA + iB; if (k22 == 0.0f) { // For fixed rotation k22 = 1.0f; } float32 k23 = iA * a1 + iB * a2; float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2; b2Mat33 K; K.ex.Set(k11, k12, k13); K.ey.Set(k12, k22, k23); K.ez.Set(k13, k23, k33); b2Vec3 C; C.x = C1.x; C.y = C1.y; C.z = C2; impulse = K.Solve33(-C); } else { float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; float32 k12 = iA * s1 + iB * s2; float32 k22 = iA + iB; if (k22 == 0.0f) { k22 = 1.0f; } b2Mat22 K; K.ex.Set(k11, k12); K.ey.Set(k12, k22); b2Vec2 impulse1 = K.Solve(-C1); impulse.x = impulse1.x; impulse.y = impulse1.y; impulse.z = 0.0f; } b2Vec2 P = impulse.x * perp + impulse.z * axis; float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1; float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2; cA -= mA * P; aA -= iA * LA; cB += mB * P; aB += iB * LB; data.positions[m_indexA].c = cA; data.positions[m_indexA].a = aA; data.positions[m_indexB].c = cB; data.positions[m_indexB].a = aB; return linearError <= b2_linearSlop && angularError <= b2_angularSlop; } b2Vec2 b2PrismaticJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2PrismaticJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const { return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); } float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * m_impulse.y; } float32 b2PrismaticJoint::GetJointTranslation() const { b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA); b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB); b2Vec2 d = pB - pA; b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA); float32 translation = b2Dot(d, axis); return translation; } float32 b2PrismaticJoint::GetJointSpeed() const { b2Body* bA = m_bodyA; b2Body* bB = m_bodyB; b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter); b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter); b2Vec2 p1 = bA->m_sweep.c + rA; b2Vec2 p2 = bB->m_sweep.c + rB; b2Vec2 d = p2 - p1; b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA); b2Vec2 vA = bA->m_linearVelocity; b2Vec2 vB = bB->m_linearVelocity; float32 wA = bA->m_angularVelocity; float32 wB = bB->m_angularVelocity; float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA)); return speed; } bool b2PrismaticJoint::IsLimitEnabled() const { return m_enableLimit; } void b2PrismaticJoint::EnableLimit(bool flag) { if (flag != m_enableLimit) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_enableLimit = flag; m_impulse.z = 0.0f; } } float32 b2PrismaticJoint::GetLowerLimit() const { return m_lowerTranslation; } float32 b2PrismaticJoint::GetUpperLimit() const { return m_upperTranslation; } void b2PrismaticJoint::SetLimits(float32 lower, float32 upper) { b2Assert(lower <= upper); if (lower != m_lowerTranslation || upper != m_upperTranslation) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_lowerTranslation = lower; m_upperTranslation = upper; m_impulse.z = 0.0f; } } bool b2PrismaticJoint::IsMotorEnabled() const { return m_enableMotor; } void b2PrismaticJoint::EnableMotor(bool flag) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_enableMotor = flag; } void b2PrismaticJoint::SetMotorSpeed(float32 speed) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_motorSpeed = speed; } void b2PrismaticJoint::SetMaxMotorForce(float32 force) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_maxMotorForce = force; } float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const { return inv_dt * m_motorImpulse; } void b2PrismaticJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2PrismaticJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation); b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation); b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2PrismaticJoint.h000066400000000000000000000134151276457661000224160ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_PRISMATIC_JOINT_H #define B2_PRISMATIC_JOINT_H #include /// Prismatic joint definition. This requires defining a line of /// motion using an axis and an anchor point. The definition uses local /// anchor points and a local axis so that the initial configuration /// can violate the constraint slightly. The joint translation is zero /// when the local anchor points coincide in world space. Using local /// anchors and a local axis helps when saving and loading a game. struct b2PrismaticJointDef : public b2JointDef { b2PrismaticJointDef() { type = e_prismaticJoint; localAnchorA.SetZero(); localAnchorB.SetZero(); localAxisA.Set(1.0f, 0.0f); referenceAngle = 0.0f; enableLimit = false; lowerTranslation = 0.0f; upperTranslation = 0.0f; enableMotor = false; maxMotorForce = 0.0f; motorSpeed = 0.0f; } /// Initialize the bodies, anchors, axis, and reference angle using the world /// anchor and unit world axis. void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); /// The local anchor point relative to bodyA's origin. b2Vec2 localAnchorA; /// The local anchor point relative to bodyB's origin. b2Vec2 localAnchorB; /// The local translation unit axis in bodyA. b2Vec2 localAxisA; /// The constrained angle between the bodies: bodyB_angle - bodyA_angle. float32 referenceAngle; /// Enable/disable the joint limit. bool enableLimit; /// The lower translation limit, usually in meters. float32 lowerTranslation; /// The upper translation limit, usually in meters. float32 upperTranslation; /// Enable/disable the joint motor. bool enableMotor; /// The maximum motor torque, usually in N-m. float32 maxMotorForce; /// The desired motor speed in radians per second. float32 motorSpeed; }; /// A prismatic joint. This joint provides one degree of freedom: translation /// along an axis fixed in bodyA. Relative rotation is prevented. You can /// use a joint limit to restrict the range of motion and a joint motor to /// drive the motion or to model joint friction. class b2PrismaticJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// The local anchor point relative to bodyA's origin. const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } /// The local anchor point relative to bodyB's origin. const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } /// The local joint axis relative to bodyA. const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } /// Get the reference angle. float32 GetReferenceAngle() const { return m_referenceAngle; } /// Get the current joint translation, usually in meters. float32 GetJointTranslation() const; /// Get the current joint translation speed, usually in meters per second. float32 GetJointSpeed() const; /// Is the joint limit enabled? bool IsLimitEnabled() const; /// Enable/disable the joint limit. void EnableLimit(bool flag); /// Get the lower joint limit, usually in meters. float32 GetLowerLimit() const; /// Get the upper joint limit, usually in meters. float32 GetUpperLimit() const; /// Set the joint limits, usually in meters. void SetLimits(float32 lower, float32 upper); /// Is the joint motor enabled? bool IsMotorEnabled() const; /// Enable/disable the joint motor. void EnableMotor(bool flag); /// Set the motor speed, usually in meters per second. void SetMotorSpeed(float32 speed); /// Get the motor speed, usually in meters per second. float32 GetMotorSpeed() const; /// Set the maximum motor force, usually in N. void SetMaxMotorForce(float32 force); float32 GetMaxMotorForce() const { return m_maxMotorForce; } /// Get the current motor force given the inverse time step, usually in N. float32 GetMotorForce(float32 inv_dt) const; /// Dump to b2Log void Dump(); protected: friend class b2Joint; friend class b2GearJoint; b2PrismaticJoint(const b2PrismaticJointDef* def); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); // Solver shared b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; b2Vec2 m_localXAxisA; b2Vec2 m_localYAxisA; float32 m_referenceAngle; b2Vec3 m_impulse; float32 m_motorImpulse; float32 m_lowerTranslation; float32 m_upperTranslation; float32 m_maxMotorForce; float32 m_motorSpeed; bool m_enableLimit; bool m_enableMotor; b2LimitState m_limitState; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; b2Vec2 m_axis, m_perp; float32 m_s1, m_s2; float32 m_a1, m_a2; b2Mat33 m_K; float32 m_motorMass; }; inline float32 b2PrismaticJoint::GetMotorSpeed() const { return m_motorSpeed; } #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2PulleyJoint.cpp000066400000000000000000000211541276457661000222670ustar00rootroot00000000000000/* * Copyright (c) 2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // Pulley: // length1 = norm(p1 - s1) // length2 = norm(p2 - s2) // C0 = (length1 + ratio * length2)_initial // C = C0 - (length1 + ratio * length2) // u1 = (p1 - s1) / norm(p1 - s1) // u2 = (p2 - s2) / norm(p2 - s2) // Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2)) // J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)] // K = J * invM * JT // = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2) void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& groundA, const b2Vec2& groundB, const b2Vec2& anchorA, const b2Vec2& anchorB, float32 r) { bodyA = bA; bodyB = bB; groundAnchorA = groundA; groundAnchorB = groundB; localAnchorA = bodyA->GetLocalPoint(anchorA); localAnchorB = bodyB->GetLocalPoint(anchorB); b2Vec2 dA = anchorA - groundA; lengthA = dA.Length(); b2Vec2 dB = anchorB - groundB; lengthB = dB.Length(); ratio = r; b2Assert(ratio > b2_epsilon); } b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def) : b2Joint(def) { m_groundAnchorA = def->groundAnchorA; m_groundAnchorB = def->groundAnchorB; m_localAnchorA = def->localAnchorA; m_localAnchorB = def->localAnchorB; m_lengthA = def->lengthA; m_lengthB = def->lengthB; b2Assert(def->ratio != 0.0f); m_ratio = def->ratio; m_constant = def->lengthA + m_ratio * def->lengthB; m_impulse = 0.0f; } void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); // Get the pulley axes. m_uA = cA + m_rA - m_groundAnchorA; m_uB = cB + m_rB - m_groundAnchorB; float32 lengthA = m_uA.Length(); float32 lengthB = m_uB.Length(); if (lengthA > 10.0f * b2_linearSlop) { m_uA *= 1.0f / lengthA; } else { m_uA.SetZero(); } if (lengthB > 10.0f * b2_linearSlop) { m_uB *= 1.0f / lengthB; } else { m_uB.SetZero(); } // Compute effective mass. float32 ruA = b2Cross(m_rA, m_uA); float32 ruB = b2Cross(m_rB, m_uB); float32 mA = m_invMassA + m_invIA * ruA * ruA; float32 mB = m_invMassB + m_invIB * ruB * ruB; m_mass = mA + m_ratio * m_ratio * mB; if (m_mass > 0.0f) { m_mass = 1.0f / m_mass; } if (data.step.warmStarting) { // Scale impulses to support variable time steps. m_impulse *= data.step.dtRatio; // Warm starting. b2Vec2 PA = -(m_impulse) * m_uA; b2Vec2 PB = (-m_ratio * m_impulse) * m_uB; vA += m_invMassA * PA; wA += m_invIA * b2Cross(m_rA, PA); vB += m_invMassB * PB; wB += m_invIB * b2Cross(m_rB, PB); } else { m_impulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Vec2 vpA = vA + b2Cross(wA, m_rA); b2Vec2 vpB = vB + b2Cross(wB, m_rB); float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB); float32 impulse = -m_mass * Cdot; m_impulse += impulse; b2Vec2 PA = -impulse * m_uA; b2Vec2 PB = -m_ratio * impulse * m_uB; vA += m_invMassA * PA; wA += m_invIA * b2Cross(m_rA, PA); vB += m_invMassB * PB; wB += m_invIB * b2Cross(m_rB, PB); data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data) { b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Rot qA(aA), qB(aB); b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); // Get the pulley axes. b2Vec2 uA = cA + rA - m_groundAnchorA; b2Vec2 uB = cB + rB - m_groundAnchorB; float32 lengthA = uA.Length(); float32 lengthB = uB.Length(); if (lengthA > 10.0f * b2_linearSlop) { uA *= 1.0f / lengthA; } else { uA.SetZero(); } if (lengthB > 10.0f * b2_linearSlop) { uB *= 1.0f / lengthB; } else { uB.SetZero(); } // Compute effective mass. float32 ruA = b2Cross(rA, uA); float32 ruB = b2Cross(rB, uB); float32 mA = m_invMassA + m_invIA * ruA * ruA; float32 mB = m_invMassB + m_invIB * ruB * ruB; float32 mass = mA + m_ratio * m_ratio * mB; if (mass > 0.0f) { mass = 1.0f / mass; } float32 C = m_constant - lengthA - m_ratio * lengthB; float32 linearError = b2Abs(C); float32 impulse = -mass * C; b2Vec2 PA = -impulse * uA; b2Vec2 PB = -m_ratio * impulse * uB; cA += m_invMassA * PA; aA += m_invIA * b2Cross(rA, PA); cB += m_invMassB * PB; aB += m_invIB * b2Cross(rB, PB); data.positions[m_indexA].c = cA; data.positions[m_indexA].a = aA; data.positions[m_indexB].c = cB; data.positions[m_indexB].a = aB; return linearError < b2_linearSlop; } b2Vec2 b2PulleyJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2PulleyJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 P = m_impulse * m_uB; return inv_dt * P; } float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const { B2_NOT_USED(inv_dt); return 0.0f; } b2Vec2 b2PulleyJoint::GetGroundAnchorA() const { return m_groundAnchorA; } b2Vec2 b2PulleyJoint::GetGroundAnchorB() const { return m_groundAnchorB; } float32 b2PulleyJoint::GetLengthA() const { return m_lengthA; } float32 b2PulleyJoint::GetLengthB() const { return m_lengthB; } float32 b2PulleyJoint::GetRatio() const { return m_ratio; } float32 b2PulleyJoint::GetCurrentLengthA() const { b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA); b2Vec2 s = m_groundAnchorA; b2Vec2 d = p - s; return d.Length(); } float32 b2PulleyJoint::GetCurrentLengthB() const { b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB); b2Vec2 s = m_groundAnchorB; b2Vec2 d = p - s; return d.Length(); } void b2PulleyJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2PulleyJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y); b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y); b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); b2Log(" jd.lengthA = %.15lef;\n", m_lengthA); b2Log(" jd.lengthB = %.15lef;\n", m_lengthB); b2Log(" jd.ratio = %.15lef;\n", m_ratio); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } void b2PulleyJoint::ShiftOrigin(const b2Vec2& newOrigin) { m_groundAnchorA -= newOrigin; m_groundAnchorB -= newOrigin; } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2PulleyJoint.h000066400000000000000000000105311276457661000217310ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_PULLEY_JOINT_H #define B2_PULLEY_JOINT_H #include const float32 b2_minPulleyLength = 2.0f; /// Pulley joint definition. This requires two ground anchors, /// two dynamic body anchor points, and a pulley ratio. struct b2PulleyJointDef : public b2JointDef { b2PulleyJointDef() { type = e_pulleyJoint; groundAnchorA.Set(-1.0f, 1.0f); groundAnchorB.Set(1.0f, 1.0f); localAnchorA.Set(-1.0f, 0.0f); localAnchorB.Set(1.0f, 0.0f); lengthA = 0.0f; lengthB = 0.0f; ratio = 1.0f; collideConnected = true; } /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB, const b2Vec2& anchorA, const b2Vec2& anchorB, float32 ratio); /// The first ground anchor in world coordinates. This point never moves. b2Vec2 groundAnchorA; /// The second ground anchor in world coordinates. This point never moves. b2Vec2 groundAnchorB; /// The local anchor point relative to bodyA's origin. b2Vec2 localAnchorA; /// The local anchor point relative to bodyB's origin. b2Vec2 localAnchorB; /// The a reference length for the segment attached to bodyA. float32 lengthA; /// The a reference length for the segment attached to bodyB. float32 lengthB; /// The pulley ratio, used to simulate a block-and-tackle. float32 ratio; }; /// The pulley joint is connected to two bodies and two fixed ground points. /// The pulley supports a ratio such that: /// length1 + ratio * length2 <= constant /// Yes, the force transmitted is scaled by the ratio. /// Warning: the pulley joint can get a bit squirrelly by itself. They often /// work better when combined with prismatic joints. You should also cover the /// the anchor points with static shapes to prevent one side from going to /// zero length. class b2PulleyJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// Get the first ground anchor. b2Vec2 GetGroundAnchorA() const; /// Get the second ground anchor. b2Vec2 GetGroundAnchorB() const; /// Get the current length of the segment attached to bodyA. float32 GetLengthA() const; /// Get the current length of the segment attached to bodyB. float32 GetLengthB() const; /// Get the pulley ratio. float32 GetRatio() const; /// Get the current length of the segment attached to bodyA. float32 GetCurrentLengthA() const; /// Get the current length of the segment attached to bodyB. float32 GetCurrentLengthB() const; /// Dump joint to dmLog void Dump(); /// Implement b2Joint::ShiftOrigin void ShiftOrigin(const b2Vec2& newOrigin); protected: friend class b2Joint; b2PulleyJoint(const b2PulleyJointDef* data); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); b2Vec2 m_groundAnchorA; b2Vec2 m_groundAnchorB; float32 m_lengthA; float32 m_lengthB; // Solver shared b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; float32 m_constant; float32 m_ratio; float32 m_impulse; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_uA; b2Vec2 m_uB; b2Vec2 m_rA; b2Vec2 m_rB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; float32 m_mass; }; #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp000066400000000000000000000314411276457661000226220ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // Point-to-point constraint // C = p2 - p1 // Cdot = v2 - v1 // = v2 + cross(w2, r2) - v1 - cross(w1, r1) // J = [-I -r1_skew I r2_skew ] // Identity used: // w k % (rx i + ry j) = w * (-ry i + rx j) // Motor constraint // Cdot = w2 - w1 // J = [0 0 -1 0 0 1] // K = invI1 + invI2 void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) { bodyA = bA; bodyB = bB; localAnchorA = bodyA->GetLocalPoint(anchor); localAnchorB = bodyB->GetLocalPoint(anchor); referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); } b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def) : b2Joint(def) { m_localAnchorA = def->localAnchorA; m_localAnchorB = def->localAnchorB; m_referenceAngle = def->referenceAngle; m_impulse.SetZero(); m_motorImpulse = 0.0f; m_lowerAngle = def->lowerAngle; m_upperAngle = def->upperAngle; m_maxMotorTorque = def->maxMotorTorque; m_motorSpeed = def->motorSpeed; m_enableLimit = def->enableLimit; m_enableMotor = def->enableMotor; m_limitState = e_inactiveLimit; } void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); // J = [-I -r1_skew I r2_skew] // [ 0 -1 0 1] // r_skew = [-ry; rx] // Matlab // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; bool fixedRotation = (iA + iB == 0.0f); m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB; m_mass.ex.y = m_mass.ey.x; m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; m_mass.ez.y = m_rA.x * iA + m_rB.x * iB; m_mass.ex.z = m_mass.ez.x; m_mass.ey.z = m_mass.ez.y; m_mass.ez.z = iA + iB; m_motorMass = iA + iB; if (m_motorMass > 0.0f) { m_motorMass = 1.0f / m_motorMass; } if (m_enableMotor == false || fixedRotation) { m_motorImpulse = 0.0f; } if (m_enableLimit && fixedRotation == false) { float32 jointAngle = aB - aA - m_referenceAngle; if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop) { m_limitState = e_equalLimits; } else if (jointAngle <= m_lowerAngle) { if (m_limitState != e_atLowerLimit) { m_impulse.z = 0.0f; } m_limitState = e_atLowerLimit; } else if (jointAngle >= m_upperAngle) { if (m_limitState != e_atUpperLimit) { m_impulse.z = 0.0f; } m_limitState = e_atUpperLimit; } else { m_limitState = e_inactiveLimit; m_impulse.z = 0.0f; } } else { m_limitState = e_inactiveLimit; } if (data.step.warmStarting) { // Scale impulses to support a variable time step. m_impulse *= data.step.dtRatio; m_motorImpulse *= data.step.dtRatio; b2Vec2 P(m_impulse.x, m_impulse.y); vA -= mA * P; wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z); vB += mB * P; wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z); } else { m_impulse.SetZero(); m_motorImpulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; bool fixedRotation = (iA + iB == 0.0f); // Solve motor constraint. if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false) { float32 Cdot = wB - wA - m_motorSpeed; float32 impulse = -m_motorMass * Cdot; float32 oldImpulse = m_motorImpulse; float32 maxImpulse = data.step.dt * m_maxMotorTorque; m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; wA -= iA * impulse; wB += iB * impulse; } // Solve limit constraint. if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) { b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); float32 Cdot2 = wB - wA; b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); b2Vec3 impulse = -m_mass.Solve33(Cdot); if (m_limitState == e_equalLimits) { m_impulse += impulse; } else if (m_limitState == e_atLowerLimit) { float32 newImpulse = m_impulse.z + impulse.z; if (newImpulse < 0.0f) { b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); b2Vec2 reduced = m_mass.Solve22(rhs); impulse.x = reduced.x; impulse.y = reduced.y; impulse.z = -m_impulse.z; m_impulse.x += reduced.x; m_impulse.y += reduced.y; m_impulse.z = 0.0f; } else { m_impulse += impulse; } } else if (m_limitState == e_atUpperLimit) { float32 newImpulse = m_impulse.z + impulse.z; if (newImpulse > 0.0f) { b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y); b2Vec2 reduced = m_mass.Solve22(rhs); impulse.x = reduced.x; impulse.y = reduced.y; impulse.z = -m_impulse.z; m_impulse.x += reduced.x; m_impulse.y += reduced.y; m_impulse.z = 0.0f; } else { m_impulse += impulse; } } b2Vec2 P(impulse.x, impulse.y); vA -= mA * P; wA -= iA * (b2Cross(m_rA, P) + impulse.z); vB += mB * P; wB += iB * (b2Cross(m_rB, P) + impulse.z); } else { // Solve point-to-point constraint b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); b2Vec2 impulse = m_mass.Solve22(-Cdot); m_impulse.x += impulse.x; m_impulse.y += impulse.y; vA -= mA * impulse; wA -= iA * b2Cross(m_rA, impulse); vB += mB * impulse; wB += iB * b2Cross(m_rB, impulse); } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data) { b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Rot qA(aA), qB(aB); float32 angularError = 0.0f; float32 positionError = 0.0f; bool fixedRotation = (m_invIA + m_invIB == 0.0f); // Solve angular limit constraint. if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false) { float32 angle = aB - aA - m_referenceAngle; float32 limitImpulse = 0.0f; if (m_limitState == e_equalLimits) { // Prevent large angular corrections float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection); limitImpulse = -m_motorMass * C; angularError = b2Abs(C); } else if (m_limitState == e_atLowerLimit) { float32 C = angle - m_lowerAngle; angularError = -C; // Prevent large angular corrections and allow some slop. C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f); limitImpulse = -m_motorMass * C; } else if (m_limitState == e_atUpperLimit) { float32 C = angle - m_upperAngle; angularError = C; // Prevent large angular corrections and allow some slop. C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection); limitImpulse = -m_motorMass * C; } aA -= m_invIA * limitImpulse; aB += m_invIB * limitImpulse; } // Solve point-to-point constraint. { qA.Set(aA); qB.Set(aB); b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); b2Vec2 C = cB + rB - cA - rA; positionError = C.Length(); float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; b2Mat22 K; K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y; K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y; K.ey.x = K.ex.y; K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x; b2Vec2 impulse = -K.Solve(C); cA -= mA * impulse; aA -= iA * b2Cross(rA, impulse); cB += mB * impulse; aB += iB * b2Cross(rB, impulse); } data.positions[m_indexA].c = cA; data.positions[m_indexA].a = aA; data.positions[m_indexB].c = cB; data.positions[m_indexB].a = aB; return positionError <= b2_linearSlop && angularError <= b2_angularSlop; } b2Vec2 b2RevoluteJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2RevoluteJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 P(m_impulse.x, m_impulse.y); return inv_dt * P; } float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * m_impulse.z; } float32 b2RevoluteJoint::GetJointAngle() const { b2Body* bA = m_bodyA; b2Body* bB = m_bodyB; return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle; } float32 b2RevoluteJoint::GetJointSpeed() const { b2Body* bA = m_bodyA; b2Body* bB = m_bodyB; return bB->m_angularVelocity - bA->m_angularVelocity; } bool b2RevoluteJoint::IsMotorEnabled() const { return m_enableMotor; } void b2RevoluteJoint::EnableMotor(bool flag) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_enableMotor = flag; } float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const { return inv_dt * m_motorImpulse; } void b2RevoluteJoint::SetMotorSpeed(float32 speed) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_motorSpeed = speed; } void b2RevoluteJoint::SetMaxMotorTorque(float32 torque) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_maxMotorTorque = torque; } bool b2RevoluteJoint::IsLimitEnabled() const { return m_enableLimit; } void b2RevoluteJoint::EnableLimit(bool flag) { if (flag != m_enableLimit) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_enableLimit = flag; m_impulse.z = 0.0f; } } float32 b2RevoluteJoint::GetLowerLimit() const { return m_lowerAngle; } float32 b2RevoluteJoint::GetUpperLimit() const { return m_upperAngle; } void b2RevoluteJoint::SetLimits(float32 lower, float32 upper) { b2Assert(lower <= upper); if (lower != m_lowerAngle || upper != m_upperAngle) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_impulse.z = 0.0f; m_lowerAngle = lower; m_upperAngle = upper; } } void b2RevoluteJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2RevoluteJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit); b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle); b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle); b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2RevoluteJoint.h000066400000000000000000000140521276457661000222660ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_REVOLUTE_JOINT_H #define B2_REVOLUTE_JOINT_H #include /// Revolute joint definition. This requires defining an /// anchor point where the bodies are joined. The definition /// uses local anchor points so that the initial configuration /// can violate the constraint slightly. You also need to /// specify the initial relative angle for joint limits. This /// helps when saving and loading a game. /// The local anchor points are measured from the body's origin /// rather than the center of mass because: /// 1. you might not know where the center of mass will be. /// 2. if you add/remove shapes from a body and recompute the mass, /// the joints will be broken. struct b2RevoluteJointDef : public b2JointDef { b2RevoluteJointDef() { type = e_revoluteJoint; localAnchorA.Set(0.0f, 0.0f); localAnchorB.Set(0.0f, 0.0f); referenceAngle = 0.0f; lowerAngle = 0.0f; upperAngle = 0.0f; maxMotorTorque = 0.0f; motorSpeed = 0.0f; enableLimit = false; enableMotor = false; } /// Initialize the bodies, anchors, and reference angle using a world /// anchor point. void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); /// The local anchor point relative to bodyA's origin. b2Vec2 localAnchorA; /// The local anchor point relative to bodyB's origin. b2Vec2 localAnchorB; /// The bodyB angle minus bodyA angle in the reference state (radians). float32 referenceAngle; /// A flag to enable joint limits. bool enableLimit; /// The lower angle for the joint limit (radians). float32 lowerAngle; /// The upper angle for the joint limit (radians). float32 upperAngle; /// A flag to enable the joint motor. bool enableMotor; /// The desired motor speed. Usually in radians per second. float32 motorSpeed; /// The maximum motor torque used to achieve the desired motor speed. /// Usually in N-m. float32 maxMotorTorque; }; /// A revolute joint constrains two bodies to share a common point while they /// are free to rotate about the point. The relative rotation about the shared /// point is the joint angle. You can limit the relative rotation with /// a joint limit that specifies a lower and upper angle. You can use a motor /// to drive the relative rotation about the shared point. A maximum motor torque /// is provided so that infinite forces are not generated. class b2RevoluteJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; /// The local anchor point relative to bodyA's origin. const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } /// The local anchor point relative to bodyB's origin. const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } /// Get the reference angle. float32 GetReferenceAngle() const { return m_referenceAngle; } /// Get the current joint angle in radians. float32 GetJointAngle() const; /// Get the current joint angle speed in radians per second. float32 GetJointSpeed() const; /// Is the joint limit enabled? bool IsLimitEnabled() const; /// Enable/disable the joint limit. void EnableLimit(bool flag); /// Get the lower joint limit in radians. float32 GetLowerLimit() const; /// Get the upper joint limit in radians. float32 GetUpperLimit() const; /// Set the joint limits in radians. void SetLimits(float32 lower, float32 upper); /// Is the joint motor enabled? bool IsMotorEnabled() const; /// Enable/disable the joint motor. void EnableMotor(bool flag); /// Set the motor speed in radians per second. void SetMotorSpeed(float32 speed); /// Get the motor speed in radians per second. float32 GetMotorSpeed() const; /// Set the maximum motor torque, usually in N-m. void SetMaxMotorTorque(float32 torque); float32 GetMaxMotorTorque() const { return m_maxMotorTorque; } /// Get the reaction force given the inverse time step. /// Unit is N. b2Vec2 GetReactionForce(float32 inv_dt) const; /// Get the reaction torque due to the joint limit given the inverse time step. /// Unit is N*m. float32 GetReactionTorque(float32 inv_dt) const; /// Get the current motor torque given the inverse time step. /// Unit is N*m. float32 GetMotorTorque(float32 inv_dt) const; /// Dump to b2Log. void Dump(); protected: friend class b2Joint; friend class b2GearJoint; b2RevoluteJoint(const b2RevoluteJointDef* def); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); // Solver shared b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; b2Vec3 m_impulse; float32 m_motorImpulse; bool m_enableMotor; float32 m_maxMotorTorque; float32 m_motorSpeed; bool m_enableLimit; float32 m_referenceAngle; float32 m_lowerAngle; float32 m_upperAngle; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_rA; b2Vec2 m_rB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; b2Mat33 m_mass; // effective mass for point-to-point constraint. float32 m_motorMass; // effective mass for motor/limit angular constraint. b2LimitState m_limitState; }; inline float32 b2RevoluteJoint::GetMotorSpeed() const { return m_motorSpeed; } #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2RopeJoint.cpp000066400000000000000000000143321276457661000217220ustar00rootroot00000000000000/* * Copyright (c) 2007-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // Limit: // C = norm(pB - pA) - L // u = (pB - pA) / norm(pB - pA) // Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA)) // J = [-u -cross(rA, u) u cross(rB, u)] // K = J * invM * JT // = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2 b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def) : b2Joint(def) { m_localAnchorA = def->localAnchorA; m_localAnchorB = def->localAnchorB; m_maxLength = def->maxLength; m_mass = 0.0f; m_impulse = 0.0f; m_state = e_inactiveLimit; m_length = 0.0f; } void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); m_u = cB + m_rB - cA - m_rA; m_length = m_u.Length(); float32 C = m_length - m_maxLength; if (C > 0.0f) { m_state = e_atUpperLimit; } else { m_state = e_inactiveLimit; } if (m_length > b2_linearSlop) { m_u *= 1.0f / m_length; } else { m_u.SetZero(); m_mass = 0.0f; m_impulse = 0.0f; return; } // Compute effective mass. float32 crA = b2Cross(m_rA, m_u); float32 crB = b2Cross(m_rB, m_u); float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB; m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; if (data.step.warmStarting) { // Scale the impulse to support a variable time step. m_impulse *= data.step.dtRatio; b2Vec2 P = m_impulse * m_u; vA -= m_invMassA * P; wA -= m_invIA * b2Cross(m_rA, P); vB += m_invMassB * P; wB += m_invIB * b2Cross(m_rB, P); } else { m_impulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; // Cdot = dot(u, v + cross(w, r)) b2Vec2 vpA = vA + b2Cross(wA, m_rA); b2Vec2 vpB = vB + b2Cross(wB, m_rB); float32 C = m_length - m_maxLength; float32 Cdot = b2Dot(m_u, vpB - vpA); // Predictive constraint. if (C < 0.0f) { Cdot += data.step.inv_dt * C; } float32 impulse = -m_mass * Cdot; float32 oldImpulse = m_impulse; m_impulse = b2Min(0.0f, m_impulse + impulse); impulse = m_impulse - oldImpulse; b2Vec2 P = impulse * m_u; vA -= m_invMassA * P; wA -= m_invIA * b2Cross(m_rA, P); vB += m_invMassB * P; wB += m_invIB * b2Cross(m_rB, P); data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data) { b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Rot qA(aA), qB(aB); b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); b2Vec2 u = cB + rB - cA - rA; float32 length = u.Normalize(); float32 C = length - m_maxLength; C = b2Clamp(C, 0.0f, b2_maxLinearCorrection); float32 impulse = -m_mass * C; b2Vec2 P = impulse * u; cA -= m_invMassA * P; aA -= m_invIA * b2Cross(rA, P); cB += m_invMassB * P; aB += m_invIB * b2Cross(rB, P); data.positions[m_indexA].c = cA; data.positions[m_indexA].a = aA; data.positions[m_indexB].c = cB; data.positions[m_indexB].a = aB; return length - m_maxLength < b2_linearSlop; } b2Vec2 b2RopeJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2RopeJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 F = (inv_dt * m_impulse) * m_u; return F; } float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const { B2_NOT_USED(inv_dt); return 0.0f; } float32 b2RopeJoint::GetMaxLength() const { return m_maxLength; } b2LimitState b2RopeJoint::GetLimitState() const { return m_state; } void b2RopeJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2RopeJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); b2Log(" jd.maxLength = %.15lef;\n", m_maxLength); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2RopeJoint.h000066400000000000000000000065371276457661000213770ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_ROPE_JOINT_H #define B2_ROPE_JOINT_H #include /// Rope joint definition. This requires two body anchor points and /// a maximum lengths. /// Note: by default the connected objects will not collide. /// see collideConnected in b2JointDef. struct b2RopeJointDef : public b2JointDef { b2RopeJointDef() { type = e_ropeJoint; localAnchorA.Set(-1.0f, 0.0f); localAnchorB.Set(1.0f, 0.0f); maxLength = 0.0f; } /// The local anchor point relative to bodyA's origin. b2Vec2 localAnchorA; /// The local anchor point relative to bodyB's origin. b2Vec2 localAnchorB; /// The maximum length of the rope. /// Warning: this must be larger than b2_linearSlop or /// the joint will have no effect. float32 maxLength; }; /// A rope joint enforces a maximum distance between two points /// on two bodies. It has no other effect. /// Warning: if you attempt to change the maximum length during /// the simulation you will get some non-physical behavior. /// A model that would allow you to dynamically modify the length /// would have some sponginess, so I chose not to implement it /// that way. See b2DistanceJoint if you want to dynamically /// control length. class b2RopeJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// The local anchor point relative to bodyA's origin. const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } /// The local anchor point relative to bodyB's origin. const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } /// Set/Get the maximum length of the rope. void SetMaxLength(float32 length) { m_maxLength = length; } float32 GetMaxLength() const; b2LimitState GetLimitState() const; /// Dump joint to dmLog void Dump(); protected: friend class b2Joint; b2RopeJoint(const b2RopeJointDef* data); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); // Solver shared b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; float32 m_maxLength; float32 m_length; float32 m_impulse; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_u; b2Vec2 m_rA; b2Vec2 m_rB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; float32 m_mass; b2LimitState m_state; }; #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2WeldJoint.cpp000066400000000000000000000207451276457661000217150ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // Point-to-point constraint // C = p2 - p1 // Cdot = v2 - v1 // = v2 + cross(w2, r2) - v1 - cross(w1, r1) // J = [-I -r1_skew I r2_skew ] // Identity used: // w k % (rx i + ry j) = w * (-ry i + rx j) // Angle constraint // C = angle2 - angle1 - referenceAngle // Cdot = w2 - w1 // J = [0 0 -1 0 0 1] // K = invI1 + invI2 void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) { bodyA = bA; bodyB = bB; localAnchorA = bodyA->GetLocalPoint(anchor); localAnchorB = bodyB->GetLocalPoint(anchor); referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); } b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def) : b2Joint(def) { m_localAnchorA = def->localAnchorA; m_localAnchorB = def->localAnchorB; m_referenceAngle = def->referenceAngle; m_frequencyHz = def->frequencyHz; m_dampingRatio = def->dampingRatio; m_impulse.SetZero(); } void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); // J = [-I -r1_skew I r2_skew] // [ 0 -1 0 1] // r_skew = [-ry; rx] // Matlab // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; b2Mat33 K; K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; K.ez.x = -m_rA.y * iA - m_rB.y * iB; K.ex.y = K.ey.x; K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; K.ez.y = m_rA.x * iA + m_rB.x * iB; K.ex.z = K.ez.x; K.ey.z = K.ez.y; K.ez.z = iA + iB; if (m_frequencyHz > 0.0f) { K.GetInverse22(&m_mass); float32 invM = iA + iB; float32 m = invM > 0.0f ? 1.0f / invM : 0.0f; float32 C = aB - aA - m_referenceAngle; // Frequency float32 omega = 2.0f * b2_pi * m_frequencyHz; // Damping coefficient float32 d = 2.0f * m * m_dampingRatio * omega; // Spring stiffness float32 k = m * omega * omega; // magic formulas float32 h = data.step.dt; m_gamma = h * (d + h * k); m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; m_bias = C * h * k * m_gamma; invM += m_gamma; m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f; } else { K.GetSymInverse33(&m_mass); m_gamma = 0.0f; m_bias = 0.0f; } if (data.step.warmStarting) { // Scale impulses to support a variable time step. m_impulse *= data.step.dtRatio; b2Vec2 P(m_impulse.x, m_impulse.y); vA -= mA * P; wA -= iA * (b2Cross(m_rA, P) + m_impulse.z); vB += mB * P; wB += iB * (b2Cross(m_rB, P) + m_impulse.z); } else { m_impulse.SetZero(); } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data) { b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; if (m_frequencyHz > 0.0f) { float32 Cdot2 = wB - wA; float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z); m_impulse.z += impulse2; wA -= iA * impulse2; wB += iB * impulse2; b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1); m_impulse.x += impulse1.x; m_impulse.y += impulse1.y; b2Vec2 P = impulse1; vA -= mA * P; wA -= iA * b2Cross(m_rA, P); vB += mB * P; wB += iB * b2Cross(m_rB, P); } else { b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); float32 Cdot2 = wB - wA; b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); b2Vec3 impulse = -b2Mul(m_mass, Cdot); m_impulse += impulse; b2Vec2 P(impulse.x, impulse.y); vA -= mA * P; wA -= iA * (b2Cross(m_rA, P) + impulse.z); vB += mB * P; wB += iB * (b2Cross(m_rB, P) + impulse.z); } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data) { b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Rot qA(aA), qB(aB); float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); float32 positionError, angularError; b2Mat33 K; K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB; K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB; K.ez.x = -rA.y * iA - rB.y * iB; K.ex.y = K.ey.x; K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB; K.ez.y = rA.x * iA + rB.x * iB; K.ex.z = K.ez.x; K.ey.z = K.ez.y; K.ez.z = iA + iB; if (m_frequencyHz > 0.0f) { b2Vec2 C1 = cB + rB - cA - rA; positionError = C1.Length(); angularError = 0.0f; b2Vec2 P = -K.Solve22(C1); cA -= mA * P; aA -= iA * b2Cross(rA, P); cB += mB * P; aB += iB * b2Cross(rB, P); } else { b2Vec2 C1 = cB + rB - cA - rA; float32 C2 = aB - aA - m_referenceAngle; positionError = C1.Length(); angularError = b2Abs(C2); b2Vec3 C(C1.x, C1.y, C2); b2Vec3 impulse = -K.Solve33(C); b2Vec2 P(impulse.x, impulse.y); cA -= mA * P; aA -= iA * (b2Cross(rA, P) + impulse.z); cB += mB * P; aB += iB * (b2Cross(rB, P) + impulse.z); } data.positions[m_indexA].c = cA; data.positions[m_indexA].a = aA; data.positions[m_indexB].c = cB; data.positions[m_indexB].a = aB; return positionError <= b2_linearSlop && angularError <= b2_angularSlop; } b2Vec2 b2WeldJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2WeldJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 P(m_impulse.x, m_impulse.y); return inv_dt * P; } float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * m_impulse.z; } void b2WeldJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2WeldJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2WeldJoint.h000066400000000000000000000072631276457661000213620ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_WELD_JOINT_H #define B2_WELD_JOINT_H #include /// Weld joint definition. You need to specify local anchor points /// where they are attached and the relative body angle. The position /// of the anchor points is important for computing the reaction torque. struct b2WeldJointDef : public b2JointDef { b2WeldJointDef() { type = e_weldJoint; localAnchorA.Set(0.0f, 0.0f); localAnchorB.Set(0.0f, 0.0f); referenceAngle = 0.0f; frequencyHz = 0.0f; dampingRatio = 0.0f; } /// Initialize the bodies, anchors, and reference angle using a world /// anchor point. void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor); /// The local anchor point relative to bodyA's origin. b2Vec2 localAnchorA; /// The local anchor point relative to bodyB's origin. b2Vec2 localAnchorB; /// The bodyB angle minus bodyA angle in the reference state (radians). float32 referenceAngle; /// The mass-spring-damper frequency in Hertz. Rotation only. /// Disable softness with a value of 0. float32 frequencyHz; /// The damping ratio. 0 = no damping, 1 = critical damping. float32 dampingRatio; }; /// A weld joint essentially glues two bodies together. A weld joint may /// distort somewhat because the island constraint solver is approximate. class b2WeldJoint : public b2Joint { public: b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// The local anchor point relative to bodyA's origin. const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } /// The local anchor point relative to bodyB's origin. const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } /// Get the reference angle. float32 GetReferenceAngle() const { return m_referenceAngle; } /// Set/get frequency in Hz. void SetFrequency(float32 hz) { m_frequencyHz = hz; } float32 GetFrequency() const { return m_frequencyHz; } /// Set/get damping ratio. void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; } float32 GetDampingRatio() const { return m_dampingRatio; } /// Dump to b2Log void Dump(); protected: friend class b2Joint; b2WeldJoint(const b2WeldJointDef* def); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); float32 m_frequencyHz; float32 m_dampingRatio; float32 m_bias; // Solver shared b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; float32 m_referenceAngle; float32 m_gamma; b2Vec3 m_impulse; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_rA; b2Vec2 m_rB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; b2Mat33 m_mass; }; #endif pybox2d-2.3.2/Box2D/Dynamics/Joints/b2WheelJoint.cpp000066400000000000000000000245131276457661000220630ustar00rootroot00000000000000/* * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include // Linear constraint (point-to-line) // d = pB - pA = xB + rB - xA - rA // C = dot(ay, d) // Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA)) // = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB) // J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)] // Spring linear constraint // C = dot(ax, d) // Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB) // J = [-ax -cross(d+rA, ax) ax cross(rB, ax)] // Motor rotational constraint // Cdot = wB - wA // J = [0 0 -1 0 0 1] void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) { bodyA = bA; bodyB = bB; localAnchorA = bodyA->GetLocalPoint(anchor); localAnchorB = bodyB->GetLocalPoint(anchor); localAxisA = bodyA->GetLocalVector(axis); } b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def) : b2Joint(def) { m_localAnchorA = def->localAnchorA; m_localAnchorB = def->localAnchorB; m_localXAxisA = def->localAxisA; m_localYAxisA = b2Cross(1.0f, m_localXAxisA); m_mass = 0.0f; m_impulse = 0.0f; m_motorMass = 0.0f; m_motorImpulse = 0.0f; m_springMass = 0.0f; m_springImpulse = 0.0f; m_maxMotorTorque = def->maxMotorTorque; m_motorSpeed = def->motorSpeed; m_enableMotor = def->enableMotor; m_frequencyHz = def->frequencyHz; m_dampingRatio = def->dampingRatio; m_bias = 0.0f; m_gamma = 0.0f; m_ax.SetZero(); m_ay.SetZero(); } void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data) { m_indexA = m_bodyA->m_islandIndex; m_indexB = m_bodyB->m_islandIndex; m_localCenterA = m_bodyA->m_sweep.localCenter; m_localCenterB = m_bodyB->m_sweep.localCenter; m_invMassA = m_bodyA->m_invMass; m_invMassB = m_bodyB->m_invMass; m_invIA = m_bodyA->m_invI; m_invIB = m_bodyB->m_invI; float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; b2Rot qA(aA), qB(aB); // Compute the effective masses. b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); b2Vec2 d = cB + rB - cA - rA; // Point to line constraint { m_ay = b2Mul(qA, m_localYAxisA); m_sAy = b2Cross(d + rA, m_ay); m_sBy = b2Cross(rB, m_ay); m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy; if (m_mass > 0.0f) { m_mass = 1.0f / m_mass; } } // Spring constraint m_springMass = 0.0f; m_bias = 0.0f; m_gamma = 0.0f; if (m_frequencyHz > 0.0f) { m_ax = b2Mul(qA, m_localXAxisA); m_sAx = b2Cross(d + rA, m_ax); m_sBx = b2Cross(rB, m_ax); float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx; if (invMass > 0.0f) { m_springMass = 1.0f / invMass; float32 C = b2Dot(d, m_ax); // Frequency float32 omega = 2.0f * b2_pi * m_frequencyHz; // Damping coefficient float32 d = 2.0f * m_springMass * m_dampingRatio * omega; // Spring stiffness float32 k = m_springMass * omega * omega; // magic formulas float32 h = data.step.dt; m_gamma = h * (d + h * k); if (m_gamma > 0.0f) { m_gamma = 1.0f / m_gamma; } m_bias = C * h * k * m_gamma; m_springMass = invMass + m_gamma; if (m_springMass > 0.0f) { m_springMass = 1.0f / m_springMass; } } } else { m_springImpulse = 0.0f; } // Rotational motor if (m_enableMotor) { m_motorMass = iA + iB; if (m_motorMass > 0.0f) { m_motorMass = 1.0f / m_motorMass; } } else { m_motorMass = 0.0f; m_motorImpulse = 0.0f; } if (data.step.warmStarting) { // Account for variable time step. m_impulse *= data.step.dtRatio; m_springImpulse *= data.step.dtRatio; m_motorImpulse *= data.step.dtRatio; b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax; float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse; float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse; vA -= m_invMassA * P; wA -= m_invIA * LA; vB += m_invMassB * P; wB += m_invIB * LB; } else { m_impulse = 0.0f; m_springImpulse = 0.0f; m_motorImpulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data) { float32 mA = m_invMassA, mB = m_invMassB; float32 iA = m_invIA, iB = m_invIB; b2Vec2 vA = data.velocities[m_indexA].v; float32 wA = data.velocities[m_indexA].w; b2Vec2 vB = data.velocities[m_indexB].v; float32 wB = data.velocities[m_indexB].w; // Solve spring constraint { float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA; float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse); m_springImpulse += impulse; b2Vec2 P = impulse * m_ax; float32 LA = impulse * m_sAx; float32 LB = impulse * m_sBx; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } // Solve rotational motor constraint { float32 Cdot = wB - wA - m_motorSpeed; float32 impulse = -m_motorMass * Cdot; float32 oldImpulse = m_motorImpulse; float32 maxImpulse = data.step.dt * m_maxMotorTorque; m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; wA -= iA * impulse; wB += iB * impulse; } // Solve point to line constraint { float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA; float32 impulse = -m_mass * Cdot; m_impulse += impulse; b2Vec2 P = impulse * m_ay; float32 LA = impulse * m_sAy; float32 LB = impulse * m_sBy; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; } bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data) { b2Vec2 cA = data.positions[m_indexA].c; float32 aA = data.positions[m_indexA].a; b2Vec2 cB = data.positions[m_indexB].c; float32 aB = data.positions[m_indexB].a; b2Rot qA(aA), qB(aB); b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); b2Vec2 d = (cB - cA) + rB - rA; b2Vec2 ay = b2Mul(qA, m_localYAxisA); float32 sAy = b2Cross(d + rA, ay); float32 sBy = b2Cross(rB, ay); float32 C = b2Dot(d, ay); float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy; float32 impulse; if (k != 0.0f) { impulse = - C / k; } else { impulse = 0.0f; } b2Vec2 P = impulse * ay; float32 LA = impulse * sAy; float32 LB = impulse * sBy; cA -= m_invMassA * P; aA -= m_invIA * LA; cB += m_invMassB * P; aB += m_invIB * LB; data.positions[m_indexA].c = cA; data.positions[m_indexA].a = aA; data.positions[m_indexB].c = cB; data.positions[m_indexB].a = aB; return b2Abs(C) <= b2_linearSlop; } b2Vec2 b2WheelJoint::GetAnchorA() const { return m_bodyA->GetWorldPoint(m_localAnchorA); } b2Vec2 b2WheelJoint::GetAnchorB() const { return m_bodyB->GetWorldPoint(m_localAnchorB); } b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const { return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax); } float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * m_motorImpulse; } float32 b2WheelJoint::GetJointTranslation() const { b2Body* bA = m_bodyA; b2Body* bB = m_bodyB; b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA); b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB); b2Vec2 d = pB - pA; b2Vec2 axis = bA->GetWorldVector(m_localXAxisA); float32 translation = b2Dot(d, axis); return translation; } float32 b2WheelJoint::GetJointSpeed() const { float32 wA = m_bodyA->m_angularVelocity; float32 wB = m_bodyB->m_angularVelocity; return wB - wA; } bool b2WheelJoint::IsMotorEnabled() const { return m_enableMotor; } void b2WheelJoint::EnableMotor(bool flag) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_enableMotor = flag; } void b2WheelJoint::SetMotorSpeed(float32 speed) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_motorSpeed = speed; } void b2WheelJoint::SetMaxMotorTorque(float32 torque) { m_bodyA->SetAwake(true); m_bodyB->SetAwake(true); m_maxMotorTorque = torque; } float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const { return inv_dt * m_motorImpulse; } void b2WheelJoint::Dump() { int32 indexA = m_bodyA->m_islandIndex; int32 indexB = m_bodyB->m_islandIndex; b2Log(" b2WheelJointDef jd;\n"); b2Log(" jd.bodyA = bodies[%d];\n", indexA); b2Log(" jd.bodyB = bodies[%d];\n", indexB); b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y); b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor); b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed); b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque); b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); } pybox2d-2.3.2/Box2D/Dynamics/Joints/b2WheelJoint.h000066400000000000000000000135131276457661000215260ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_WHEEL_JOINT_H #define B2_WHEEL_JOINT_H #include /// Wheel joint definition. This requires defining a line of /// motion using an axis and an anchor point. The definition uses local /// anchor points and a local axis so that the initial configuration /// can violate the constraint slightly. The joint translation is zero /// when the local anchor points coincide in world space. Using local /// anchors and a local axis helps when saving and loading a game. struct b2WheelJointDef : public b2JointDef { b2WheelJointDef() { type = e_wheelJoint; localAnchorA.SetZero(); localAnchorB.SetZero(); localAxisA.Set(1.0f, 0.0f); enableMotor = false; maxMotorTorque = 0.0f; motorSpeed = 0.0f; frequencyHz = 2.0f; dampingRatio = 0.7f; } /// Initialize the bodies, anchors, axis, and reference angle using the world /// anchor and world axis. void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis); /// The local anchor point relative to bodyA's origin. b2Vec2 localAnchorA; /// The local anchor point relative to bodyB's origin. b2Vec2 localAnchorB; /// The local translation axis in bodyA. b2Vec2 localAxisA; /// Enable/disable the joint motor. bool enableMotor; /// The maximum motor torque, usually in N-m. float32 maxMotorTorque; /// The desired motor speed in radians per second. float32 motorSpeed; /// Suspension frequency, zero indicates no suspension float32 frequencyHz; /// Suspension damping ratio, one indicates critical damping float32 dampingRatio; }; /// A wheel joint. This joint provides two degrees of freedom: translation /// along an axis fixed in bodyA and rotation in the plane. You can use a /// joint limit to restrict the range of motion and a joint motor to drive /// the rotation or to model rotational friction. /// This joint is designed for vehicle suspensions. class b2WheelJoint : public b2Joint { public: //void GetDefinition(b2WheelJointDef* def) const; b2Vec2 GetAnchorA() const; b2Vec2 GetAnchorB() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// The local anchor point relative to bodyA's origin. const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; } /// The local anchor point relative to bodyB's origin. const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; } /// The local joint axis relative to bodyA. const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; } /// Get the current joint translation, usually in meters. float32 GetJointTranslation() const; /// Get the current joint translation speed, usually in meters per second. float32 GetJointSpeed() const; /// Is the joint motor enabled? bool IsMotorEnabled() const; /// Enable/disable the joint motor. void EnableMotor(bool flag); /// Set the motor speed, usually in radians per second. void SetMotorSpeed(float32 speed); /// Get the motor speed, usually in radians per second. float32 GetMotorSpeed() const; /// Set/Get the maximum motor force, usually in N-m. void SetMaxMotorTorque(float32 torque); float32 GetMaxMotorTorque() const; /// Get the current motor torque given the inverse time step, usually in N-m. float32 GetMotorTorque(float32 inv_dt) const; /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring. void SetSpringFrequencyHz(float32 hz); float32 GetSpringFrequencyHz() const; /// Set/Get the spring damping ratio void SetSpringDampingRatio(float32 ratio); float32 GetSpringDampingRatio() const; /// Dump to b2Log void Dump(); protected: friend class b2Joint; b2WheelJoint(const b2WheelJointDef* def); void InitVelocityConstraints(const b2SolverData& data); void SolveVelocityConstraints(const b2SolverData& data); bool SolvePositionConstraints(const b2SolverData& data); float32 m_frequencyHz; float32 m_dampingRatio; // Solver shared b2Vec2 m_localAnchorA; b2Vec2 m_localAnchorB; b2Vec2 m_localXAxisA; b2Vec2 m_localYAxisA; float32 m_impulse; float32 m_motorImpulse; float32 m_springImpulse; float32 m_maxMotorTorque; float32 m_motorSpeed; bool m_enableMotor; // Solver temp int32 m_indexA; int32 m_indexB; b2Vec2 m_localCenterA; b2Vec2 m_localCenterB; float32 m_invMassA; float32 m_invMassB; float32 m_invIA; float32 m_invIB; b2Vec2 m_ax, m_ay; float32 m_sAx, m_sBx; float32 m_sAy, m_sBy; float32 m_mass; float32 m_motorMass; float32 m_springMass; float32 m_bias; float32 m_gamma; }; inline float32 b2WheelJoint::GetMotorSpeed() const { return m_motorSpeed; } inline float32 b2WheelJoint::GetMaxMotorTorque() const { return m_maxMotorTorque; } inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz) { m_frequencyHz = hz; } inline float32 b2WheelJoint::GetSpringFrequencyHz() const { return m_frequencyHz; } inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio) { m_dampingRatio = ratio; } inline float32 b2WheelJoint::GetSpringDampingRatio() const { return m_dampingRatio; } #endif pybox2d-2.3.2/Box2D/Dynamics/b2Body.cpp000066400000000000000000000273201276457661000174410ustar00rootroot00000000000000/* * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include b2Body::b2Body(const b2BodyDef* bd, b2World* world) { b2Assert(bd->position.IsValid()); b2Assert(bd->linearVelocity.IsValid()); b2Assert(b2IsValid(bd->angle)); b2Assert(b2IsValid(bd->angularVelocity)); b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f); b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f); m_flags = 0; if (bd->bullet) { m_flags |= e_bulletFlag; } if (bd->fixedRotation) { m_flags |= e_fixedRotationFlag; } if (bd->allowSleep) { m_flags |= e_autoSleepFlag; } if (bd->awake) { m_flags |= e_awakeFlag; } if (bd->active) { m_flags |= e_activeFlag; } m_world = world; m_xf.p = bd->position; m_xf.q.Set(bd->angle); m_sweep.localCenter.SetZero(); m_sweep.c0 = m_xf.p; m_sweep.c = m_xf.p; m_sweep.a0 = bd->angle; m_sweep.a = bd->angle; m_sweep.alpha0 = 0.0f; m_jointList = NULL; m_contactList = NULL; m_prev = NULL; m_next = NULL; m_linearVelocity = bd->linearVelocity; m_angularVelocity = bd->angularVelocity; m_linearDamping = bd->linearDamping; m_angularDamping = bd->angularDamping; m_gravityScale = bd->gravityScale; m_force.SetZero(); m_torque = 0.0f; m_sleepTime = 0.0f; m_type = bd->type; if (m_type == b2_dynamicBody) { m_mass = 1.0f; m_invMass = 1.0f; } else { m_mass = 0.0f; m_invMass = 0.0f; } m_I = 0.0f; m_invI = 0.0f; m_userData = bd->userData; m_fixtureList = NULL; m_fixtureCount = 0; } b2Body::~b2Body() { // shapes and joints are destroyed in b2World::Destroy } void b2Body::SetType(b2BodyType type) { b2Assert(m_world->IsLocked() == false); if (m_world->IsLocked() == true) { return; } if (m_type == type) { return; } m_type = type; ResetMassData(); if (m_type == b2_staticBody) { m_linearVelocity.SetZero(); m_angularVelocity = 0.0f; m_sweep.a0 = m_sweep.a; m_sweep.c0 = m_sweep.c; SynchronizeFixtures(); } SetAwake(true); m_force.SetZero(); m_torque = 0.0f; // Delete the attached contacts. b2ContactEdge* ce = m_contactList; while (ce) { b2ContactEdge* ce0 = ce; ce = ce->next; m_world->m_contactManager.Destroy(ce0->contact); } m_contactList = NULL; // Touch the proxies so that new contacts will be created (when appropriate) b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; for (b2Fixture* f = m_fixtureList; f; f = f->m_next) { int32 proxyCount = f->m_proxyCount; for (int32 i = 0; i < proxyCount; ++i) { broadPhase->TouchProxy(f->m_proxies[i].proxyId); } } } b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def) { b2Assert(m_world->IsLocked() == false); if (m_world->IsLocked() == true) { return NULL; } b2BlockAllocator* allocator = &m_world->m_blockAllocator; void* memory = allocator->Allocate(sizeof(b2Fixture)); b2Fixture* fixture = new (memory) b2Fixture; fixture->Create(allocator, this, def); if (m_flags & e_activeFlag) { b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; fixture->CreateProxies(broadPhase, m_xf); } fixture->m_next = m_fixtureList; m_fixtureList = fixture; ++m_fixtureCount; fixture->m_body = this; // Adjust mass properties if needed. if (fixture->m_density > 0.0f) { ResetMassData(); } // Let the world know we have a new fixture. This will cause new contacts // to be created at the beginning of the next time step. m_world->m_flags |= b2World::e_newFixture; return fixture; } b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density) { b2FixtureDef def; def.shape = shape; def.density = density; return CreateFixture(&def); } void b2Body::DestroyFixture(b2Fixture* fixture) { b2Assert(m_world->IsLocked() == false); if (m_world->IsLocked() == true) { return; } b2Assert(fixture->m_body == this); // Remove the fixture from this body's singly linked list. b2Assert(m_fixtureCount > 0); b2Fixture** node = &m_fixtureList; bool found = false; while (*node != NULL) { if (*node == fixture) { *node = fixture->m_next; found = true; break; } node = &(*node)->m_next; } // You tried to remove a shape that is not attached to this body. b2Assert(found); // Destroy any contacts associated with the fixture. b2ContactEdge* edge = m_contactList; while (edge) { b2Contact* c = edge->contact; edge = edge->next; b2Fixture* fixtureA = c->GetFixtureA(); b2Fixture* fixtureB = c->GetFixtureB(); if (fixture == fixtureA || fixture == fixtureB) { // This destroys the contact and removes it from // this body's contact list. m_world->m_contactManager.Destroy(c); } } b2BlockAllocator* allocator = &m_world->m_blockAllocator; if (m_flags & e_activeFlag) { b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; fixture->DestroyProxies(broadPhase); } fixture->Destroy(allocator); fixture->m_body = NULL; fixture->m_next = NULL; fixture->~b2Fixture(); allocator->Free(fixture, sizeof(b2Fixture)); --m_fixtureCount; // Reset the mass data. ResetMassData(); } void b2Body::ResetMassData() { // Compute mass data from shapes. Each shape has its own density. m_mass = 0.0f; m_invMass = 0.0f; m_I = 0.0f; m_invI = 0.0f; m_sweep.localCenter.SetZero(); // Static and kinematic bodies have zero mass. if (m_type == b2_staticBody || m_type == b2_kinematicBody) { m_sweep.c0 = m_xf.p; m_sweep.c = m_xf.p; m_sweep.a0 = m_sweep.a; return; } b2Assert(m_type == b2_dynamicBody); // Accumulate mass over all fixtures. b2Vec2 localCenter = b2Vec2_zero; for (b2Fixture* f = m_fixtureList; f; f = f->m_next) { if (f->m_density == 0.0f) { continue; } b2MassData massData; f->GetMassData(&massData); m_mass += massData.mass; localCenter += massData.mass * massData.center; m_I += massData.I; } // Compute center of mass. if (m_mass > 0.0f) { m_invMass = 1.0f / m_mass; localCenter *= m_invMass; } else { // Force all dynamic bodies to have a positive mass. m_mass = 1.0f; m_invMass = 1.0f; } if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) { // Center the inertia about the center of mass. m_I -= m_mass * b2Dot(localCenter, localCenter); b2Assert(m_I > 0.0f); m_invI = 1.0f / m_I; } else { m_I = 0.0f; m_invI = 0.0f; } // Move center of mass. b2Vec2 oldCenter = m_sweep.c; m_sweep.localCenter = localCenter; m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); // Update center of mass velocity. m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); } void b2Body::SetMassData(const b2MassData* massData) { b2Assert(m_world->IsLocked() == false); if (m_world->IsLocked() == true) { return; } if (m_type != b2_dynamicBody) { return; } m_invMass = 0.0f; m_I = 0.0f; m_invI = 0.0f; m_mass = massData->mass; if (m_mass <= 0.0f) { m_mass = 1.0f; } m_invMass = 1.0f / m_mass; if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) { m_I = massData->I - m_mass * b2Dot(massData->center, massData->center); b2Assert(m_I > 0.0f); m_invI = 1.0f / m_I; } // Move center of mass. b2Vec2 oldCenter = m_sweep.c; m_sweep.localCenter = massData->center; m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); // Update center of mass velocity. m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); } bool b2Body::ShouldCollide(const b2Body* other) const { // At least one body should be dynamic. if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody) { return false; } // Does a joint prevent collision? for (b2JointEdge* jn = m_jointList; jn; jn = jn->next) { if (jn->other == other) { if (jn->joint->m_collideConnected == false) { return false; } } } return true; } void b2Body::SetTransform(const b2Vec2& position, float32 angle) { b2Assert(m_world->IsLocked() == false); if (m_world->IsLocked() == true) { return; } m_xf.q.Set(angle); m_xf.p = position; m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); m_sweep.a = angle; m_sweep.c0 = m_sweep.c; m_sweep.a0 = angle; b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; for (b2Fixture* f = m_fixtureList; f; f = f->m_next) { f->Synchronize(broadPhase, m_xf, m_xf); } m_world->m_contactManager.FindNewContacts(); } void b2Body::SynchronizeFixtures() { b2Transform xf1; xf1.q.Set(m_sweep.a0); xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter); b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; for (b2Fixture* f = m_fixtureList; f; f = f->m_next) { f->Synchronize(broadPhase, xf1, m_xf); } } void b2Body::SetActive(bool flag) { b2Assert(m_world->IsLocked() == false); if (flag == IsActive()) { return; } if (flag) { m_flags |= e_activeFlag; // Create all proxies. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; for (b2Fixture* f = m_fixtureList; f; f = f->m_next) { f->CreateProxies(broadPhase, m_xf); } // Contacts are created the next time step. } else { m_flags &= ~e_activeFlag; // Destroy all proxies. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; for (b2Fixture* f = m_fixtureList; f; f = f->m_next) { f->DestroyProxies(broadPhase); } // Destroy the attached contacts. b2ContactEdge* ce = m_contactList; while (ce) { b2ContactEdge* ce0 = ce; ce = ce->next; m_world->m_contactManager.Destroy(ce0->contact); } m_contactList = NULL; } } void b2Body::SetFixedRotation(bool flag) { bool status = (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; if (status == flag) { return; } if (flag) { m_flags |= e_fixedRotationFlag; } else { m_flags &= ~e_fixedRotationFlag; } m_angularVelocity = 0.0f; ResetMassData(); } void b2Body::Dump() { int32 bodyIndex = m_islandIndex; b2Log("{\n"); b2Log(" b2BodyDef bd;\n"); b2Log(" bd.type = b2BodyType(%d);\n", m_type); b2Log(" bd.position.Set(%.15lef, %.15lef);\n", m_xf.p.x, m_xf.p.y); b2Log(" bd.angle = %.15lef;\n", m_sweep.a); b2Log(" bd.linearVelocity.Set(%.15lef, %.15lef);\n", m_linearVelocity.x, m_linearVelocity.y); b2Log(" bd.angularVelocity = %.15lef;\n", m_angularVelocity); b2Log(" bd.linearDamping = %.15lef;\n", m_linearDamping); b2Log(" bd.angularDamping = %.15lef;\n", m_angularDamping); b2Log(" bd.allowSleep = bool(%d);\n", m_flags & e_autoSleepFlag); b2Log(" bd.awake = bool(%d);\n", m_flags & e_awakeFlag); b2Log(" bd.fixedRotation = bool(%d);\n", m_flags & e_fixedRotationFlag); b2Log(" bd.bullet = bool(%d);\n", m_flags & e_bulletFlag); b2Log(" bd.active = bool(%d);\n", m_flags & e_activeFlag); b2Log(" bd.gravityScale = %.15lef;\n", m_gravityScale); b2Log(" bodies[%d] = m_world->CreateBody(&bd);\n", m_islandIndex); b2Log("\n"); for (b2Fixture* f = m_fixtureList; f; f = f->m_next) { b2Log(" {\n"); f->Dump(bodyIndex); b2Log(" }\n"); } b2Log("}\n"); } pybox2d-2.3.2/Box2D/Dynamics/b2Body.h000066400000000000000000000543071276457661000171130ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_BODY_H #define B2_BODY_H #include #include #include class b2Fixture; class b2Joint; class b2Contact; class b2Controller; class b2World; struct b2FixtureDef; struct b2JointEdge; struct b2ContactEdge; /// The body type. /// static: zero mass, zero velocity, may be manually moved /// kinematic: zero mass, non-zero velocity set by user, moved by solver /// dynamic: positive mass, non-zero velocity determined by forces, moved by solver enum b2BodyType { b2_staticBody = 0, b2_kinematicBody, b2_dynamicBody // TODO_ERIN //b2_bulletBody, }; /// A body definition holds all the data needed to construct a rigid body. /// You can safely re-use body definitions. Shapes are added to a body after construction. struct b2BodyDef { /// This constructor sets the body definition default values. b2BodyDef() { userData = NULL; position.Set(0.0f, 0.0f); angle = 0.0f; linearVelocity.Set(0.0f, 0.0f); angularVelocity = 0.0f; linearDamping = 0.0f; angularDamping = 0.0f; allowSleep = true; awake = true; fixedRotation = false; bullet = false; type = b2_staticBody; active = true; gravityScale = 1.0f; } /// The body type: static, kinematic, or dynamic. /// Note: if a dynamic body would have zero mass, the mass is set to one. b2BodyType type; /// The world position of the body. Avoid creating bodies at the origin /// since this can lead to many overlapping shapes. b2Vec2 position; /// The world angle of the body in radians. float32 angle; /// The linear velocity of the body's origin in world co-ordinates. b2Vec2 linearVelocity; /// The angular velocity of the body. float32 angularVelocity; /// Linear damping is use to reduce the linear velocity. The damping parameter /// can be larger than 1.0f but the damping effect becomes sensitive to the /// time step when the damping parameter is large. float32 linearDamping; /// Angular damping is use to reduce the angular velocity. The damping parameter /// can be larger than 1.0f but the damping effect becomes sensitive to the /// time step when the damping parameter is large. float32 angularDamping; /// Set this flag to false if this body should never fall asleep. Note that /// this increases CPU usage. bool allowSleep; /// Is this body initially awake or sleeping? bool awake; /// Should this body be prevented from rotating? Useful for characters. bool fixedRotation; /// Is this a fast moving body that should be prevented from tunneling through /// other moving bodies? Note that all bodies are prevented from tunneling through /// kinematic and static bodies. This setting is only considered on dynamic bodies. /// @warning You should use this flag sparingly since it increases processing time. bool bullet; /// Does this body start out active? bool active; /// Use this to store application specific body data. void* userData; /// Scale the gravity applied to this body. float32 gravityScale; }; /// A rigid body. These are created via b2World::CreateBody. class b2Body { public: /// Creates a fixture and attach it to this body. Use this function if you need /// to set some fixture parameters, like friction. Otherwise you can create the /// fixture directly from a shape. /// If the density is non-zero, this function automatically updates the mass of the body. /// Contacts are not created until the next time step. /// @param def the fixture definition. /// @warning This function is locked during callbacks. b2Fixture* CreateFixture(const b2FixtureDef* def); /// Creates a fixture from a shape and attach it to this body. /// This is a convenience function. Use b2FixtureDef if you need to set parameters /// like friction, restitution, user data, or filtering. /// If the density is non-zero, this function automatically updates the mass of the body. /// @param shape the shape to be cloned. /// @param density the shape density (set to zero for static bodies). /// @warning This function is locked during callbacks. b2Fixture* CreateFixture(const b2Shape* shape, float32 density); /// Destroy a fixture. This removes the fixture from the broad-phase and /// destroys all contacts associated with this fixture. This will /// automatically adjust the mass of the body if the body is dynamic and the /// fixture has positive density. /// All fixtures attached to a body are implicitly destroyed when the body is destroyed. /// @param fixture the fixture to be removed. /// @warning This function is locked during callbacks. void DestroyFixture(b2Fixture* fixture); /// Set the position of the body's origin and rotation. /// This breaks any contacts and wakes the other bodies. /// Manipulating a body's transform may cause non-physical behavior. /// @param position the world position of the body's local origin. /// @param angle the world rotation in radians. void SetTransform(const b2Vec2& position, float32 angle); /// Get the body transform for the body's origin. /// @return the world transform of the body's origin. const b2Transform& GetTransform() const; /// Get the world body origin position. /// @return the world position of the body's origin. const b2Vec2& GetPosition() const; /// Get the angle in radians. /// @return the current world rotation angle in radians. float32 GetAngle() const; /// Get the world position of the center of mass. const b2Vec2& GetWorldCenter() const; /// Get the local position of the center of mass. const b2Vec2& GetLocalCenter() const; /// Set the linear velocity of the center of mass. /// @param v the new linear velocity of the center of mass. void SetLinearVelocity(const b2Vec2& v); /// Get the linear velocity of the center of mass. /// @return the linear velocity of the center of mass. const b2Vec2& GetLinearVelocity() const; /// Set the angular velocity. /// @param omega the new angular velocity in radians/second. void SetAngularVelocity(float32 omega); /// Get the angular velocity. /// @return the angular velocity in radians/second. float32 GetAngularVelocity() const; /// Apply a force at a world point. If the force is not /// applied at the center of mass, it will generate a torque and /// affect the angular velocity. This wakes up the body. /// @param force the world force vector, usually in Newtons (N). /// @param point the world position of the point of application. /// @param wake also wake up the body void ApplyForce(const b2Vec2& force, const b2Vec2& point, bool wake); /// Apply a force to the center of mass. This wakes up the body. /// @param force the world force vector, usually in Newtons (N). /// @param wake also wake up the body void ApplyForceToCenter(const b2Vec2& force, bool wake); /// Apply a torque. This affects the angular velocity /// without affecting the linear velocity of the center of mass. /// This wakes up the body. /// @param torque about the z-axis (out of the screen), usually in N-m. /// @param wake also wake up the body void ApplyTorque(float32 torque, bool wake); /// Apply an impulse at a point. This immediately modifies the velocity. /// It also modifies the angular velocity if the point of application /// is not at the center of mass. This wakes up the body. /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. /// @param point the world position of the point of application. /// @param wake also wake up the body void ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point, bool wake); /// Apply an angular impulse. /// @param impulse the angular impulse in units of kg*m*m/s /// @param wake also wake up the body void ApplyAngularImpulse(float32 impulse, bool wake); /// Get the total mass of the body. /// @return the mass, usually in kilograms (kg). float32 GetMass() const; /// Get the rotational inertia of the body about the local origin. /// @return the rotational inertia, usually in kg-m^2. float32 GetInertia() const; /// Get the mass data of the body. /// @return a struct containing the mass, inertia and center of the body. void GetMassData(b2MassData* data) const; /// Set the mass properties to override the mass properties of the fixtures. /// Note that this changes the center of mass position. /// Note that creating or destroying fixtures can also alter the mass. /// This function has no effect if the body isn't dynamic. /// @param massData the mass properties. void SetMassData(const b2MassData* data); /// This resets the mass properties to the sum of the mass properties of the fixtures. /// This normally does not need to be called unless you called SetMassData to override /// the mass and you later want to reset the mass. void ResetMassData(); /// Get the world coordinates of a point given the local coordinates. /// @param localPoint a point on the body measured relative the the body's origin. /// @return the same point expressed in world coordinates. b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const; /// Get the world coordinates of a vector given the local coordinates. /// @param localVector a vector fixed in the body. /// @return the same vector expressed in world coordinates. b2Vec2 GetWorldVector(const b2Vec2& localVector) const; /// Gets a local point relative to the body's origin given a world point. /// @param a point in world coordinates. /// @return the corresponding local point relative to the body's origin. b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const; /// Gets a local vector given a world vector. /// @param a vector in world coordinates. /// @return the corresponding local vector. b2Vec2 GetLocalVector(const b2Vec2& worldVector) const; /// Get the world linear velocity of a world point attached to this body. /// @param a point in world coordinates. /// @return the world velocity of a point. b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const; /// Get the world velocity of a local point. /// @param a point in local coordinates. /// @return the world velocity of a point. b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const; /// Get the linear damping of the body. float32 GetLinearDamping() const; /// Set the linear damping of the body. void SetLinearDamping(float32 linearDamping); /// Get the angular damping of the body. float32 GetAngularDamping() const; /// Set the angular damping of the body. void SetAngularDamping(float32 angularDamping); /// Get the gravity scale of the body. float32 GetGravityScale() const; /// Set the gravity scale of the body. void SetGravityScale(float32 scale); /// Set the type of this body. This may alter the mass and velocity. void SetType(b2BodyType type); /// Get the type of this body. b2BodyType GetType() const; /// Should this body be treated like a bullet for continuous collision detection? void SetBullet(bool flag); /// Is this body treated like a bullet for continuous collision detection? bool IsBullet() const; /// You can disable sleeping on this body. If you disable sleeping, the /// body will be woken. void SetSleepingAllowed(bool flag); /// Is this body allowed to sleep bool IsSleepingAllowed() const; /// Set the sleep state of the body. A sleeping body has very /// low CPU cost. /// @param flag set to true to wake the body, false to put it to sleep. void SetAwake(bool flag); /// Get the sleeping state of this body. /// @return true if the body is sleeping. bool IsAwake() const; /// Set the active state of the body. An inactive body is not /// simulated and cannot be collided with or woken up. /// If you pass a flag of true, all fixtures will be added to the /// broad-phase. /// If you pass a flag of false, all fixtures will be removed from /// the broad-phase and all contacts will be destroyed. /// Fixtures and joints are otherwise unaffected. You may continue /// to create/destroy fixtures and joints on inactive bodies. /// Fixtures on an inactive body are implicitly inactive and will /// not participate in collisions, ray-casts, or queries. /// Joints connected to an inactive body are implicitly inactive. /// An inactive body is still owned by a b2World object and remains /// in the body list. void SetActive(bool flag); /// Get the active state of the body. bool IsActive() const; /// Set this body to have fixed rotation. This causes the mass /// to be reset. void SetFixedRotation(bool flag); /// Does this body have fixed rotation? bool IsFixedRotation() const; /// Get the list of all fixtures attached to this body. b2Fixture* GetFixtureList(); const b2Fixture* GetFixtureList() const; /// Get the list of all joints attached to this body. b2JointEdge* GetJointList(); const b2JointEdge* GetJointList() const; /// Get the list of all contacts attached to this body. /// @warning this list changes during the time step and you may /// miss some collisions if you don't use b2ContactListener. b2ContactEdge* GetContactList(); const b2ContactEdge* GetContactList() const; /// Get the next body in the world's body list. b2Body* GetNext(); const b2Body* GetNext() const; /// Get the user data pointer that was provided in the body definition. void* GetUserData() const; /// Set the user data. Use this to store your application specific data. void SetUserData(void* data); /// Get the parent world of this body. b2World* GetWorld(); const b2World* GetWorld() const; /// Dump this body to a log file void Dump(); private: friend class b2World; friend class b2Island; friend class b2ContactManager; friend class b2ContactSolver; friend class b2Contact; friend class b2DistanceJoint; friend class b2FrictionJoint; friend class b2GearJoint; friend class b2MotorJoint; friend class b2MouseJoint; friend class b2PrismaticJoint; friend class b2PulleyJoint; friend class b2RevoluteJoint; friend class b2RopeJoint; friend class b2WeldJoint; friend class b2WheelJoint; // m_flags enum { e_islandFlag = 0x0001, e_awakeFlag = 0x0002, e_autoSleepFlag = 0x0004, e_bulletFlag = 0x0008, e_fixedRotationFlag = 0x0010, e_activeFlag = 0x0020, e_toiFlag = 0x0040 }; b2Body(const b2BodyDef* bd, b2World* world); ~b2Body(); void SynchronizeFixtures(); void SynchronizeTransform(); // This is used to prevent connected bodies from colliding. // It may lie, depending on the collideConnected flag. bool ShouldCollide(const b2Body* other) const; void Advance(float32 t); b2BodyType m_type; uint16 m_flags; int32 m_islandIndex; b2Transform m_xf; // the body origin transform b2Sweep m_sweep; // the swept motion for CCD b2Vec2 m_linearVelocity; float32 m_angularVelocity; b2Vec2 m_force; float32 m_torque; b2World* m_world; b2Body* m_prev; b2Body* m_next; b2Fixture* m_fixtureList; int32 m_fixtureCount; b2JointEdge* m_jointList; b2ContactEdge* m_contactList; float32 m_mass, m_invMass; // Rotational inertia about the center of mass. float32 m_I, m_invI; float32 m_linearDamping; float32 m_angularDamping; float32 m_gravityScale; float32 m_sleepTime; void* m_userData; }; inline b2BodyType b2Body::GetType() const { return m_type; } inline const b2Transform& b2Body::GetTransform() const { return m_xf; } inline const b2Vec2& b2Body::GetPosition() const { return m_xf.p; } inline float32 b2Body::GetAngle() const { return m_sweep.a; } inline const b2Vec2& b2Body::GetWorldCenter() const { return m_sweep.c; } inline const b2Vec2& b2Body::GetLocalCenter() const { return m_sweep.localCenter; } inline void b2Body::SetLinearVelocity(const b2Vec2& v) { if (m_type == b2_staticBody) { return; } if (b2Dot(v,v) > 0.0f) { SetAwake(true); } m_linearVelocity = v; } inline const b2Vec2& b2Body::GetLinearVelocity() const { return m_linearVelocity; } inline void b2Body::SetAngularVelocity(float32 w) { if (m_type == b2_staticBody) { return; } if (w * w > 0.0f) { SetAwake(true); } m_angularVelocity = w; } inline float32 b2Body::GetAngularVelocity() const { return m_angularVelocity; } inline float32 b2Body::GetMass() const { return m_mass; } inline float32 b2Body::GetInertia() const { return m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); } inline void b2Body::GetMassData(b2MassData* data) const { data->mass = m_mass; data->I = m_I + m_mass * b2Dot(m_sweep.localCenter, m_sweep.localCenter); data->center = m_sweep.localCenter; } inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const { return b2Mul(m_xf, localPoint); } inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const { return b2Mul(m_xf.q, localVector); } inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const { return b2MulT(m_xf, worldPoint); } inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const { return b2MulT(m_xf.q, worldVector); } inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const { return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c); } inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const { return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); } inline float32 b2Body::GetLinearDamping() const { return m_linearDamping; } inline void b2Body::SetLinearDamping(float32 linearDamping) { m_linearDamping = linearDamping; } inline float32 b2Body::GetAngularDamping() const { return m_angularDamping; } inline void b2Body::SetAngularDamping(float32 angularDamping) { m_angularDamping = angularDamping; } inline float32 b2Body::GetGravityScale() const { return m_gravityScale; } inline void b2Body::SetGravityScale(float32 scale) { m_gravityScale = scale; } inline void b2Body::SetBullet(bool flag) { if (flag) { m_flags |= e_bulletFlag; } else { m_flags &= ~e_bulletFlag; } } inline bool b2Body::IsBullet() const { return (m_flags & e_bulletFlag) == e_bulletFlag; } inline void b2Body::SetAwake(bool flag) { if (flag) { if ((m_flags & e_awakeFlag) == 0) { m_flags |= e_awakeFlag; m_sleepTime = 0.0f; } } else { m_flags &= ~e_awakeFlag; m_sleepTime = 0.0f; m_linearVelocity.SetZero(); m_angularVelocity = 0.0f; m_force.SetZero(); m_torque = 0.0f; } } inline bool b2Body::IsAwake() const { return (m_flags & e_awakeFlag) == e_awakeFlag; } inline bool b2Body::IsActive() const { return (m_flags & e_activeFlag) == e_activeFlag; } inline bool b2Body::IsFixedRotation() const { return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; } inline void b2Body::SetSleepingAllowed(bool flag) { if (flag) { m_flags |= e_autoSleepFlag; } else { m_flags &= ~e_autoSleepFlag; SetAwake(true); } } inline bool b2Body::IsSleepingAllowed() const { return (m_flags & e_autoSleepFlag) == e_autoSleepFlag; } inline b2Fixture* b2Body::GetFixtureList() { return m_fixtureList; } inline const b2Fixture* b2Body::GetFixtureList() const { return m_fixtureList; } inline b2JointEdge* b2Body::GetJointList() { return m_jointList; } inline const b2JointEdge* b2Body::GetJointList() const { return m_jointList; } inline b2ContactEdge* b2Body::GetContactList() { return m_contactList; } inline const b2ContactEdge* b2Body::GetContactList() const { return m_contactList; } inline b2Body* b2Body::GetNext() { return m_next; } inline const b2Body* b2Body::GetNext() const { return m_next; } inline void b2Body::SetUserData(void* data) { m_userData = data; } inline void* b2Body::GetUserData() const { return m_userData; } inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point, bool wake) { if (m_type != b2_dynamicBody) { return; } if (wake && (m_flags & e_awakeFlag) == 0) { SetAwake(true); } // Don't accumulate a force if the body is sleeping. if (m_flags & e_awakeFlag) { m_force += force; m_torque += b2Cross(point - m_sweep.c, force); } } inline void b2Body::ApplyForceToCenter(const b2Vec2& force, bool wake) { if (m_type != b2_dynamicBody) { return; } if (wake && (m_flags & e_awakeFlag) == 0) { SetAwake(true); } // Don't accumulate a force if the body is sleeping if (m_flags & e_awakeFlag) { m_force += force; } } inline void b2Body::ApplyTorque(float32 torque, bool wake) { if (m_type != b2_dynamicBody) { return; } if (wake && (m_flags & e_awakeFlag) == 0) { SetAwake(true); } // Don't accumulate a force if the body is sleeping if (m_flags & e_awakeFlag) { m_torque += torque; } } inline void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point, bool wake) { if (m_type != b2_dynamicBody) { return; } if (wake && (m_flags & e_awakeFlag) == 0) { SetAwake(true); } // Don't accumulate velocity if the body is sleeping if (m_flags & e_awakeFlag) { m_linearVelocity += m_invMass * impulse; m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse); } } inline void b2Body::ApplyAngularImpulse(float32 impulse, bool wake) { if (m_type != b2_dynamicBody) { return; } if (wake && (m_flags & e_awakeFlag) == 0) { SetAwake(true); } // Don't accumulate velocity if the body is sleeping if (m_flags & e_awakeFlag) { m_angularVelocity += m_invI * impulse; } } inline void b2Body::SynchronizeTransform() { m_xf.q.Set(m_sweep.a); m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); } inline void b2Body::Advance(float32 alpha) { // Advance to the new safe time. This doesn't sync the broad-phase. m_sweep.Advance(alpha); m_sweep.c = m_sweep.c0; m_sweep.a = m_sweep.a0; m_xf.q.Set(m_sweep.a); m_xf.p = m_sweep.c - b2Mul(m_xf.q, m_sweep.localCenter); } inline b2World* b2Body::GetWorld() { return m_world; } inline const b2World* b2Body::GetWorld() const { return m_world; } #endif pybox2d-2.3.2/Box2D/Dynamics/b2ContactManager.cpp000066400000000000000000000156301276457661000214330ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include b2ContactFilter b2_defaultFilter; b2ContactListener b2_defaultListener; b2ContactManager::b2ContactManager() { m_contactList = NULL; m_contactCount = 0; m_contactFilter = &b2_defaultFilter; m_contactListener = &b2_defaultListener; m_allocator = NULL; } void b2ContactManager::Destroy(b2Contact* c) { b2Fixture* fixtureA = c->GetFixtureA(); b2Fixture* fixtureB = c->GetFixtureB(); b2Body* bodyA = fixtureA->GetBody(); b2Body* bodyB = fixtureB->GetBody(); if (m_contactListener && c->IsTouching()) { m_contactListener->EndContact(c); } // Remove from the world. if (c->m_prev) { c->m_prev->m_next = c->m_next; } if (c->m_next) { c->m_next->m_prev = c->m_prev; } if (c == m_contactList) { m_contactList = c->m_next; } // Remove from body 1 if (c->m_nodeA.prev) { c->m_nodeA.prev->next = c->m_nodeA.next; } if (c->m_nodeA.next) { c->m_nodeA.next->prev = c->m_nodeA.prev; } if (&c->m_nodeA == bodyA->m_contactList) { bodyA->m_contactList = c->m_nodeA.next; } // Remove from body 2 if (c->m_nodeB.prev) { c->m_nodeB.prev->next = c->m_nodeB.next; } if (c->m_nodeB.next) { c->m_nodeB.next->prev = c->m_nodeB.prev; } if (&c->m_nodeB == bodyB->m_contactList) { bodyB->m_contactList = c->m_nodeB.next; } // Call the factory. b2Contact::Destroy(c, m_allocator); --m_contactCount; } // This is the top level collision call for the time step. Here // all the narrow phase collision is processed for the world // contact list. void b2ContactManager::Collide() { // Update awake contacts. b2Contact* c = m_contactList; while (c) { b2Fixture* fixtureA = c->GetFixtureA(); b2Fixture* fixtureB = c->GetFixtureB(); int32 indexA = c->GetChildIndexA(); int32 indexB = c->GetChildIndexB(); b2Body* bodyA = fixtureA->GetBody(); b2Body* bodyB = fixtureB->GetBody(); // Is this contact flagged for filtering? if (c->m_flags & b2Contact::e_filterFlag) { // Should these bodies collide? if (bodyB->ShouldCollide(bodyA) == false) { b2Contact* cNuke = c; c = cNuke->GetNext(); Destroy(cNuke); continue; } // Check user filtering. if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) { b2Contact* cNuke = c; c = cNuke->GetNext(); Destroy(cNuke); continue; } // Clear the filtering flag. c->m_flags &= ~b2Contact::e_filterFlag; } bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody; bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody; // At least one body must be awake and it must be dynamic or kinematic. if (activeA == false && activeB == false) { c = c->GetNext(); continue; } int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId; int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId; bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); // Here we destroy contacts that cease to overlap in the broad-phase. if (overlap == false) { b2Contact* cNuke = c; c = cNuke->GetNext(); Destroy(cNuke); continue; } // The contact persists. c->Update(m_contactListener); c = c->GetNext(); } } void b2ContactManager::FindNewContacts() { m_broadPhase.UpdatePairs(this); } void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB) { b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA; b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB; b2Fixture* fixtureA = proxyA->fixture; b2Fixture* fixtureB = proxyB->fixture; int32 indexA = proxyA->childIndex; int32 indexB = proxyB->childIndex; b2Body* bodyA = fixtureA->GetBody(); b2Body* bodyB = fixtureB->GetBody(); // Are the fixtures on the same body? if (bodyA == bodyB) { return; } // TODO_ERIN use a hash table to remove a potential bottleneck when both // bodies have a lot of contacts. // Does a contact already exist? b2ContactEdge* edge = bodyB->GetContactList(); while (edge) { if (edge->other == bodyA) { b2Fixture* fA = edge->contact->GetFixtureA(); b2Fixture* fB = edge->contact->GetFixtureB(); int32 iA = edge->contact->GetChildIndexA(); int32 iB = edge->contact->GetChildIndexB(); if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) { // A contact already exists. return; } if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) { // A contact already exists. return; } } edge = edge->next; } // Does a joint override collision? Is at least one body dynamic? if (bodyB->ShouldCollide(bodyA) == false) { return; } // Check user filtering. if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) { return; } // Call the factory. b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator); if (c == NULL) { return; } // Contact creation may swap fixtures. fixtureA = c->GetFixtureA(); fixtureB = c->GetFixtureB(); indexA = c->GetChildIndexA(); indexB = c->GetChildIndexB(); bodyA = fixtureA->GetBody(); bodyB = fixtureB->GetBody(); // Insert into the world. c->m_prev = NULL; c->m_next = m_contactList; if (m_contactList != NULL) { m_contactList->m_prev = c; } m_contactList = c; // Connect to island graph. // Connect to body A c->m_nodeA.contact = c; c->m_nodeA.other = bodyB; c->m_nodeA.prev = NULL; c->m_nodeA.next = bodyA->m_contactList; if (bodyA->m_contactList != NULL) { bodyA->m_contactList->prev = &c->m_nodeA; } bodyA->m_contactList = &c->m_nodeA; // Connect to body B c->m_nodeB.contact = c; c->m_nodeB.other = bodyA; c->m_nodeB.prev = NULL; c->m_nodeB.next = bodyB->m_contactList; if (bodyB->m_contactList != NULL) { bodyB->m_contactList->prev = &c->m_nodeB; } bodyB->m_contactList = &c->m_nodeB; // Wake up the bodies if (fixtureA->IsSensor() == false && fixtureB->IsSensor() == false) { bodyA->SetAwake(true); bodyB->SetAwake(true); } ++m_contactCount; } pybox2d-2.3.2/Box2D/Dynamics/b2ContactManager.h000066400000000000000000000030001276457661000210640ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CONTACT_MANAGER_H #define B2_CONTACT_MANAGER_H #include class b2Contact; class b2ContactFilter; class b2ContactListener; class b2BlockAllocator; // Delegate of b2World. class b2ContactManager { public: b2ContactManager(); // Broad-phase callback. void AddPair(void* proxyUserDataA, void* proxyUserDataB); void FindNewContacts(); void Destroy(b2Contact* c); void Collide(); b2BroadPhase m_broadPhase; b2Contact* m_contactList; int32 m_contactCount; b2ContactFilter* m_contactFilter; b2ContactListener* m_contactListener; b2BlockAllocator* m_allocator; }; #endif pybox2d-2.3.2/Box2D/Dynamics/b2Fixture.cpp000066400000000000000000000200731276457661000201700ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #include #include #include #include b2Fixture::b2Fixture() { m_userData = NULL; m_body = NULL; m_next = NULL; m_proxies = NULL; m_proxyCount = 0; m_shape = NULL; m_density = 0.0f; } void b2Fixture::Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def) { m_userData = def->userData; m_friction = def->friction; m_restitution = def->restitution; m_body = body; m_next = NULL; m_filter = def->filter; m_isSensor = def->isSensor; m_shape = def->shape->Clone(allocator); // Reserve proxy space int32 childCount = m_shape->GetChildCount(); m_proxies = (b2FixtureProxy*)allocator->Allocate(childCount * sizeof(b2FixtureProxy)); for (int32 i = 0; i < childCount; ++i) { m_proxies[i].fixture = NULL; m_proxies[i].proxyId = b2BroadPhase::e_nullProxy; } m_proxyCount = 0; m_density = def->density; } void b2Fixture::Destroy(b2BlockAllocator* allocator) { // The proxies must be destroyed before calling this. b2Assert(m_proxyCount == 0); // Free the proxy array. int32 childCount = m_shape->GetChildCount(); allocator->Free(m_proxies, childCount * sizeof(b2FixtureProxy)); m_proxies = NULL; // Free the child shape. switch (m_shape->m_type) { case b2Shape::e_circle: { b2CircleShape* s = (b2CircleShape*)m_shape; s->~b2CircleShape(); allocator->Free(s, sizeof(b2CircleShape)); } break; case b2Shape::e_edge: { b2EdgeShape* s = (b2EdgeShape*)m_shape; s->~b2EdgeShape(); allocator->Free(s, sizeof(b2EdgeShape)); } break; case b2Shape::e_polygon: { b2PolygonShape* s = (b2PolygonShape*)m_shape; s->~b2PolygonShape(); allocator->Free(s, sizeof(b2PolygonShape)); } break; case b2Shape::e_chain: { b2ChainShape* s = (b2ChainShape*)m_shape; s->~b2ChainShape(); allocator->Free(s, sizeof(b2ChainShape)); } break; default: b2Assert(false); break; } m_shape = NULL; } void b2Fixture::CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf) { b2Assert(m_proxyCount == 0); // Create proxies in the broad-phase. m_proxyCount = m_shape->GetChildCount(); for (int32 i = 0; i < m_proxyCount; ++i) { b2FixtureProxy* proxy = m_proxies + i; m_shape->ComputeAABB(&proxy->aabb, xf, i); proxy->proxyId = broadPhase->CreateProxy(proxy->aabb, proxy); proxy->fixture = this; proxy->childIndex = i; } } void b2Fixture::DestroyProxies(b2BroadPhase* broadPhase) { // Destroy proxies in the broad-phase. for (int32 i = 0; i < m_proxyCount; ++i) { b2FixtureProxy* proxy = m_proxies + i; broadPhase->DestroyProxy(proxy->proxyId); proxy->proxyId = b2BroadPhase::e_nullProxy; } m_proxyCount = 0; } void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transform1, const b2Transform& transform2) { if (m_proxyCount == 0) { return; } for (int32 i = 0; i < m_proxyCount; ++i) { b2FixtureProxy* proxy = m_proxies + i; // Compute an AABB that covers the swept shape (may miss some rotation effect). b2AABB aabb1, aabb2; m_shape->ComputeAABB(&aabb1, transform1, proxy->childIndex); m_shape->ComputeAABB(&aabb2, transform2, proxy->childIndex); proxy->aabb.Combine(aabb1, aabb2); b2Vec2 displacement = transform2.p - transform1.p; broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement); } } void b2Fixture::SetFilterData(const b2Filter& filter) { m_filter = filter; Refilter(); } void b2Fixture::Refilter() { if (m_body == NULL) { return; } // Flag associated contacts for filtering. b2ContactEdge* edge = m_body->GetContactList(); while (edge) { b2Contact* contact = edge->contact; b2Fixture* fixtureA = contact->GetFixtureA(); b2Fixture* fixtureB = contact->GetFixtureB(); if (fixtureA == this || fixtureB == this) { contact->FlagForFiltering(); } edge = edge->next; } b2World* world = m_body->GetWorld(); if (world == NULL) { return; } // Touch each proxy so that new pairs may be created b2BroadPhase* broadPhase = &world->m_contactManager.m_broadPhase; for (int32 i = 0; i < m_proxyCount; ++i) { broadPhase->TouchProxy(m_proxies[i].proxyId); } } void b2Fixture::SetSensor(bool sensor) { if (sensor != m_isSensor) { m_body->SetAwake(true); m_isSensor = sensor; } } void b2Fixture::Dump(int32 bodyIndex) { b2Log(" b2FixtureDef fd;\n"); b2Log(" fd.friction = %.15lef;\n", m_friction); b2Log(" fd.restitution = %.15lef;\n", m_restitution); b2Log(" fd.density = %.15lef;\n", m_density); b2Log(" fd.isSensor = bool(%d);\n", m_isSensor); b2Log(" fd.filter.categoryBits = uint16(%d);\n", m_filter.categoryBits); b2Log(" fd.filter.maskBits = uint16(%d);\n", m_filter.maskBits); b2Log(" fd.filter.groupIndex = int16(%d);\n", m_filter.groupIndex); switch (m_shape->m_type) { case b2Shape::e_circle: { b2CircleShape* s = (b2CircleShape*)m_shape; b2Log(" b2CircleShape shape;\n"); b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); b2Log(" shape.m_p.Set(%.15lef, %.15lef);\n", s->m_p.x, s->m_p.y); } break; case b2Shape::e_edge: { b2EdgeShape* s = (b2EdgeShape*)m_shape; b2Log(" b2EdgeShape shape;\n"); b2Log(" shape.m_radius = %.15lef;\n", s->m_radius); b2Log(" shape.m_vertex0.Set(%.15lef, %.15lef);\n", s->m_vertex0.x, s->m_vertex0.y); b2Log(" shape.m_vertex1.Set(%.15lef, %.15lef);\n", s->m_vertex1.x, s->m_vertex1.y); b2Log(" shape.m_vertex2.Set(%.15lef, %.15lef);\n", s->m_vertex2.x, s->m_vertex2.y); b2Log(" shape.m_vertex3.Set(%.15lef, %.15lef);\n", s->m_vertex3.x, s->m_vertex3.y); b2Log(" shape.m_hasVertex0 = bool(%d);\n", s->m_hasVertex0); b2Log(" shape.m_hasVertex3 = bool(%d);\n", s->m_hasVertex3); } break; case b2Shape::e_polygon: { b2PolygonShape* s = (b2PolygonShape*)m_shape; b2Log(" b2PolygonShape shape;\n"); b2Log(" b2Vec2 vs[%d];\n", b2_maxPolygonVertices); for (int32 i = 0; i < s->m_count; ++i) { b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); } b2Log(" shape.Set(vs, %d);\n", s->m_count); } break; case b2Shape::e_chain: { b2ChainShape* s = (b2ChainShape*)m_shape; b2Log(" b2ChainShape shape;\n"); b2Log(" b2Vec2 vs[%d];\n", s->m_count); for (int32 i = 0; i < s->m_count; ++i) { b2Log(" vs[%d].Set(%.15lef, %.15lef);\n", i, s->m_vertices[i].x, s->m_vertices[i].y); } b2Log(" shape.CreateChain(vs, %d);\n", s->m_count); b2Log(" shape.m_prevVertex.Set(%.15lef, %.15lef);\n", s->m_prevVertex.x, s->m_prevVertex.y); b2Log(" shape.m_nextVertex.Set(%.15lef, %.15lef);\n", s->m_nextVertex.x, s->m_nextVertex.y); b2Log(" shape.m_hasPrevVertex = bool(%d);\n", s->m_hasPrevVertex); b2Log(" shape.m_hasNextVertex = bool(%d);\n", s->m_hasNextVertex); } break; default: return; } b2Log("\n"); b2Log(" fd.shape = &shape;\n"); b2Log("\n"); b2Log(" bodies[%d]->CreateFixture(&fd);\n", bodyIndex); } pybox2d-2.3.2/Box2D/Dynamics/b2Fixture.h000066400000000000000000000220221276457661000176310ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_FIXTURE_H #define B2_FIXTURE_H #include #include #include class b2BlockAllocator; class b2Body; class b2BroadPhase; class b2Fixture; /// This holds contact filtering data. struct b2Filter { b2Filter() { categoryBits = 0x0001; maskBits = 0xFFFF; groupIndex = 0; } /// The collision category bits. Normally you would just set one bit. uint16 categoryBits; /// The collision mask bits. This states the categories that this /// shape would accept for collision. uint16 maskBits; /// Collision groups allow a certain group of objects to never collide (negative) /// or always collide (positive). Zero means no collision group. Non-zero group /// filtering always wins against the mask bits. int16 groupIndex; }; /// A fixture definition is used to create a fixture. This class defines an /// abstract fixture definition. You can reuse fixture definitions safely. struct b2FixtureDef { /// The constructor sets the default fixture definition values. b2FixtureDef() { shape = NULL; userData = NULL; friction = 0.2f; restitution = 0.0f; density = 0.0f; isSensor = false; } /// The shape, this must be set. The shape will be cloned, so you /// can create the shape on the stack. const b2Shape* shape; /// Use this to store application specific fixture data. void* userData; /// The friction coefficient, usually in the range [0,1]. float32 friction; /// The restitution (elasticity) usually in the range [0,1]. float32 restitution; /// The density, usually in kg/m^2. float32 density; /// A sensor shape collects contact information but never generates a collision /// response. bool isSensor; /// Contact filtering data. b2Filter filter; }; /// This proxy is used internally to connect fixtures to the broad-phase. struct b2FixtureProxy { b2AABB aabb; b2Fixture* fixture; int32 childIndex; int32 proxyId; }; /// A fixture is used to attach a shape to a body for collision detection. A fixture /// inherits its transform from its parent. Fixtures hold additional non-geometric data /// such as friction, collision filters, etc. /// Fixtures are created via b2Body::CreateFixture. /// @warning you cannot reuse fixtures. class b2Fixture { public: /// Get the type of the child shape. You can use this to down cast to the concrete shape. /// @return the shape type. b2Shape::Type GetType() const; /// Get the child shape. You can modify the child shape, however you should not change the /// number of vertices because this will crash some collision caching mechanisms. /// Manipulating the shape may lead to non-physical behavior. b2Shape* GetShape(); const b2Shape* GetShape() const; /// Set if this fixture is a sensor. void SetSensor(bool sensor); /// Is this fixture a sensor (non-solid)? /// @return the true if the shape is a sensor. bool IsSensor() const; /// Set the contact filtering data. This will not update contacts until the next time /// step when either parent body is active and awake. /// This automatically calls Refilter. void SetFilterData(const b2Filter& filter); /// Get the contact filtering data. const b2Filter& GetFilterData() const; /// Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide. void Refilter(); /// Get the parent body of this fixture. This is NULL if the fixture is not attached. /// @return the parent body. b2Body* GetBody(); const b2Body* GetBody() const; /// Get the next fixture in the parent body's fixture list. /// @return the next shape. b2Fixture* GetNext(); const b2Fixture* GetNext() const; /// Get the user data that was assigned in the fixture definition. Use this to /// store your application specific data. void* GetUserData() const; /// Set the user data. Use this to store your application specific data. void SetUserData(void* data); /// Test a point for containment in this fixture. /// @param p a point in world coordinates. bool TestPoint(const b2Vec2& p) const; /// Cast a ray against this shape. /// @param output the ray-cast results. /// @param input the ray-cast input parameters. bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const; /// Get the mass data for this fixture. The mass data is based on the density and /// the shape. The rotational inertia is about the shape's origin. This operation /// may be expensive. void GetMassData(b2MassData* massData) const; /// Set the density of this fixture. This will _not_ automatically adjust the mass /// of the body. You must call b2Body::ResetMassData to update the body's mass. void SetDensity(float32 density); /// Get the density of this fixture. float32 GetDensity() const; /// Get the coefficient of friction. float32 GetFriction() const; /// Set the coefficient of friction. This will _not_ change the friction of /// existing contacts. void SetFriction(float32 friction); /// Get the coefficient of restitution. float32 GetRestitution() const; /// Set the coefficient of restitution. This will _not_ change the restitution of /// existing contacts. void SetRestitution(float32 restitution); /// Get the fixture's AABB. This AABB may be enlarge and/or stale. /// If you need a more accurate AABB, compute it using the shape and /// the body transform. const b2AABB& GetAABB(int32 childIndex) const; /// Dump this fixture to the log file. void Dump(int32 bodyIndex); protected: friend class b2Body; friend class b2World; friend class b2Contact; friend class b2ContactManager; b2Fixture(); // We need separation create/destroy functions from the constructor/destructor because // the destructor cannot access the allocator (no destructor arguments allowed by C++). void Create(b2BlockAllocator* allocator, b2Body* body, const b2FixtureDef* def); void Destroy(b2BlockAllocator* allocator); // These support body activation/deactivation. void CreateProxies(b2BroadPhase* broadPhase, const b2Transform& xf); void DestroyProxies(b2BroadPhase* broadPhase); void Synchronize(b2BroadPhase* broadPhase, const b2Transform& xf1, const b2Transform& xf2); float32 m_density; b2Fixture* m_next; b2Body* m_body; b2Shape* m_shape; float32 m_friction; float32 m_restitution; b2FixtureProxy* m_proxies; int32 m_proxyCount; b2Filter m_filter; bool m_isSensor; void* m_userData; }; inline b2Shape::Type b2Fixture::GetType() const { return m_shape->GetType(); } inline b2Shape* b2Fixture::GetShape() { return m_shape; } inline const b2Shape* b2Fixture::GetShape() const { return m_shape; } inline bool b2Fixture::IsSensor() const { return m_isSensor; } inline const b2Filter& b2Fixture::GetFilterData() const { return m_filter; } inline void* b2Fixture::GetUserData() const { return m_userData; } inline void b2Fixture::SetUserData(void* data) { m_userData = data; } inline b2Body* b2Fixture::GetBody() { return m_body; } inline const b2Body* b2Fixture::GetBody() const { return m_body; } inline b2Fixture* b2Fixture::GetNext() { return m_next; } inline const b2Fixture* b2Fixture::GetNext() const { return m_next; } inline void b2Fixture::SetDensity(float32 density) { b2Assert(b2IsValid(density) && density >= 0.0f); m_density = density; } inline float32 b2Fixture::GetDensity() const { return m_density; } inline float32 b2Fixture::GetFriction() const { return m_friction; } inline void b2Fixture::SetFriction(float32 friction) { m_friction = friction; } inline float32 b2Fixture::GetRestitution() const { return m_restitution; } inline void b2Fixture::SetRestitution(float32 restitution) { m_restitution = restitution; } inline bool b2Fixture::TestPoint(const b2Vec2& p) const { return m_shape->TestPoint(m_body->GetTransform(), p); } inline bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input, int32 childIndex) const { return m_shape->RayCast(output, input, m_body->GetTransform(), childIndex); } inline void b2Fixture::GetMassData(b2MassData* massData) const { m_shape->ComputeMass(massData, m_density); } inline const b2AABB& b2Fixture::GetAABB(int32 childIndex) const { b2Assert(0 <= childIndex && childIndex < m_proxyCount); return m_proxies[childIndex].aabb; } #endif pybox2d-2.3.2/Box2D/Dynamics/b2Island.cpp000066400000000000000000000403511276457661000177550ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #include #include #include #include /* Position Correction Notes ========================= I tried the several algorithms for position correction of the 2D revolute joint. I looked at these systems: - simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s. - suspension bridge with 30 1m long planks of length 1m. - multi-link chain with 30 1m long links. Here are the algorithms: Baumgarte - A fraction of the position error is added to the velocity error. There is no separate position solver. Pseudo Velocities - After the velocity solver and position integration, the position error, Jacobian, and effective mass are recomputed. Then the velocity constraints are solved with pseudo velocities and a fraction of the position error is added to the pseudo velocity error. The pseudo velocities are initialized to zero and there is no warm-starting. After the position solver, the pseudo velocities are added to the positions. This is also called the First Order World method or the Position LCP method. Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the position error is re-computed for each constraint and the positions are updated after the constraint is solved. The radius vectors (aka Jacobians) are re-computed too (otherwise the algorithm has horrible instability). The pseudo velocity states are not needed because they are effectively zero at the beginning of each iteration. Since we have the current position error, we allow the iterations to terminate early if the error becomes smaller than b2_linearSlop. Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed each time a constraint is solved. Here are the results: Baumgarte - this is the cheapest algorithm but it has some stability problems, especially with the bridge. The chain links separate easily close to the root and they jitter as they struggle to pull together. This is one of the most common methods in the field. The big drawback is that the position correction artificially affects the momentum, thus leading to instabilities and false bounce. I used a bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller factor makes joints and contacts more spongy. Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is stable. However, joints still separate with large angular velocities. Drag the simple pendulum in a circle quickly and the joint will separate. The chain separates easily and does not recover. I used a bias factor of 0.2. A larger value lead to the bridge collapsing when a heavy cube drops on it. Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo Velocities, but in other ways it is worse. The bridge and chain are much more stable, but the simple pendulum goes unstable at high angular velocities. Full NGS - stable in all tests. The joints display good stiffness. The bridge still sags, but this is better than infinite forces. Recommendations Pseudo Velocities are not really worthwhile because the bridge and chain cannot recover from joint separation. In other cases the benefit over Baumgarte is small. Modified NGS is not a robust method for the revolute joint due to the violent instability seen in the simple pendulum. Perhaps it is viable with other constraint types, especially scalar constraints where the effective mass is a scalar. This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities and is very fast. I don't think we can escape Baumgarte, especially in highly demanding cases where high constraint fidelity is not needed. Full NGS is robust and easy on the eyes. I recommend this as an option for higher fidelity simulation and certainly for suspension bridges and long chains. Full NGS might be a good choice for ragdolls, especially motorized ragdolls where joint separation can be problematic. The number of NGS iterations can be reduced for better performance without harming robustness much. Each joint in a can be handled differently in the position solver. So I recommend a system where the user can select the algorithm on a per joint basis. I would probably default to the slower Full NGS and let the user select the faster Baumgarte method in performance critical scenarios. */ /* Cache Performance The Box2D solvers are dominated by cache misses. Data structures are designed to increase the number of cache hits. Much of misses are due to random access to body data. The constraint structures are iterated over linearly, which leads to few cache misses. The bodies are not accessed during iteration. Instead read only data, such as the mass values are stored with the constraints. The mutable data are the constraint impulses and the bodies velocities/positions. The impulses are held inside the constraint structures. The body velocities/positions are held in compact, temporary arrays to increase the number of cache hits. Linear and angular velocity are stored in a single array since multiple arrays lead to multiple misses. */ /* 2D Rotation R = [cos(theta) -sin(theta)] [sin(theta) cos(theta) ] thetaDot = omega Let q1 = cos(theta), q2 = sin(theta). R = [q1 -q2] [q2 q1] q1Dot = -thetaDot * q2 q2Dot = thetaDot * q1 q1_new = q1_old - dt * w * q2 q2_new = q2_old + dt * w * q1 then normalize. This might be faster than computing sin+cos. However, we can compute sin+cos of the same angle fast. */ b2Island::b2Island( int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, b2StackAllocator* allocator, b2ContactListener* listener) { m_bodyCapacity = bodyCapacity; m_contactCapacity = contactCapacity; m_jointCapacity = jointCapacity; m_bodyCount = 0; m_contactCount = 0; m_jointCount = 0; m_allocator = allocator; m_listener = listener; m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*)); m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*)); m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*)); m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity)); m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position)); } b2Island::~b2Island() { // Warning: the order should reverse the constructor order. m_allocator->Free(m_positions); m_allocator->Free(m_velocities); m_allocator->Free(m_joints); m_allocator->Free(m_contacts); m_allocator->Free(m_bodies); } void b2Island::Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep) { b2Timer timer; float32 h = step.dt; // Integrate velocities and apply damping. Initialize the body state. for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; b2Vec2 c = b->m_sweep.c; float32 a = b->m_sweep.a; b2Vec2 v = b->m_linearVelocity; float32 w = b->m_angularVelocity; // Store positions for continuous collision. b->m_sweep.c0 = b->m_sweep.c; b->m_sweep.a0 = b->m_sweep.a; if (b->m_type == b2_dynamicBody) { // Integrate velocities. v += h * (b->m_gravityScale * gravity + b->m_invMass * b->m_force); w += h * b->m_invI * b->m_torque; // Apply damping. // ODE: dv/dt + c * v = 0 // Solution: v(t) = v0 * exp(-c * t) // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt) // v2 = exp(-c * dt) * v1 // Taylor expansion: // v2 = (1.0f - c * dt) * v1 v *= b2Clamp(1.0f - h * b->m_linearDamping, 0.0f, 1.0f); w *= b2Clamp(1.0f - h * b->m_angularDamping, 0.0f, 1.0f); } m_positions[i].c = c; m_positions[i].a = a; m_velocities[i].v = v; m_velocities[i].w = w; } timer.Reset(); // Solver data b2SolverData solverData; solverData.step = step; solverData.positions = m_positions; solverData.velocities = m_velocities; // Initialize velocity constraints. b2ContactSolverDef contactSolverDef; contactSolverDef.step = step; contactSolverDef.contacts = m_contacts; contactSolverDef.count = m_contactCount; contactSolverDef.positions = m_positions; contactSolverDef.velocities = m_velocities; contactSolverDef.allocator = m_allocator; b2ContactSolver contactSolver(&contactSolverDef); contactSolver.InitializeVelocityConstraints(); if (step.warmStarting) { contactSolver.WarmStart(); } for (int32 i = 0; i < m_jointCount; ++i) { m_joints[i]->InitVelocityConstraints(solverData); } profile->solveInit = timer.GetMilliseconds(); // Solve velocity constraints timer.Reset(); for (int32 i = 0; i < step.velocityIterations; ++i) { for (int32 j = 0; j < m_jointCount; ++j) { m_joints[j]->SolveVelocityConstraints(solverData); } contactSolver.SolveVelocityConstraints(); } // Store impulses for warm starting contactSolver.StoreImpulses(); profile->solveVelocity = timer.GetMilliseconds(); // Integrate positions for (int32 i = 0; i < m_bodyCount; ++i) { b2Vec2 c = m_positions[i].c; float32 a = m_positions[i].a; b2Vec2 v = m_velocities[i].v; float32 w = m_velocities[i].w; // Check for large velocities b2Vec2 translation = h * v; if (b2Dot(translation, translation) > b2_maxTranslationSquared) { float32 ratio = b2_maxTranslation / translation.Length(); v *= ratio; } float32 rotation = h * w; if (rotation * rotation > b2_maxRotationSquared) { float32 ratio = b2_maxRotation / b2Abs(rotation); w *= ratio; } // Integrate c += h * v; a += h * w; m_positions[i].c = c; m_positions[i].a = a; m_velocities[i].v = v; m_velocities[i].w = w; } // Solve position constraints timer.Reset(); bool positionSolved = false; for (int32 i = 0; i < step.positionIterations; ++i) { bool contactsOkay = contactSolver.SolvePositionConstraints(); bool jointsOkay = true; for (int32 i = 0; i < m_jointCount; ++i) { bool jointOkay = m_joints[i]->SolvePositionConstraints(solverData); jointsOkay = jointsOkay && jointOkay; } if (contactsOkay && jointsOkay) { // Exit early if the position errors are small. positionSolved = true; break; } } // Copy state buffers back to the bodies for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* body = m_bodies[i]; body->m_sweep.c = m_positions[i].c; body->m_sweep.a = m_positions[i].a; body->m_linearVelocity = m_velocities[i].v; body->m_angularVelocity = m_velocities[i].w; body->SynchronizeTransform(); } profile->solvePosition = timer.GetMilliseconds(); Report(contactSolver.m_velocityConstraints); if (allowSleep) { float32 minSleepTime = b2_maxFloat; const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance; const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance; for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; if (b->GetType() == b2_staticBody) { continue; } if ((b->m_flags & b2Body::e_autoSleepFlag) == 0 || b->m_angularVelocity * b->m_angularVelocity > angTolSqr || b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr) { b->m_sleepTime = 0.0f; minSleepTime = 0.0f; } else { b->m_sleepTime += h; minSleepTime = b2Min(minSleepTime, b->m_sleepTime); } } if (minSleepTime >= b2_timeToSleep && positionSolved) { for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; b->SetAwake(false); } } } } void b2Island::SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB) { b2Assert(toiIndexA < m_bodyCount); b2Assert(toiIndexB < m_bodyCount); // Initialize the body state. for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; m_positions[i].c = b->m_sweep.c; m_positions[i].a = b->m_sweep.a; m_velocities[i].v = b->m_linearVelocity; m_velocities[i].w = b->m_angularVelocity; } b2ContactSolverDef contactSolverDef; contactSolverDef.contacts = m_contacts; contactSolverDef.count = m_contactCount; contactSolverDef.allocator = m_allocator; contactSolverDef.step = subStep; contactSolverDef.positions = m_positions; contactSolverDef.velocities = m_velocities; b2ContactSolver contactSolver(&contactSolverDef); // Solve position constraints. for (int32 i = 0; i < subStep.positionIterations; ++i) { bool contactsOkay = contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB); if (contactsOkay) { break; } } #if 0 // Is the new position really safe? for (int32 i = 0; i < m_contactCount; ++i) { b2Contact* c = m_contacts[i]; b2Fixture* fA = c->GetFixtureA(); b2Fixture* fB = c->GetFixtureB(); b2Body* bA = fA->GetBody(); b2Body* bB = fB->GetBody(); int32 indexA = c->GetChildIndexA(); int32 indexB = c->GetChildIndexB(); b2DistanceInput input; input.proxyA.Set(fA->GetShape(), indexA); input.proxyB.Set(fB->GetShape(), indexB); input.transformA = bA->GetTransform(); input.transformB = bB->GetTransform(); input.useRadii = false; b2DistanceOutput output; b2SimplexCache cache; cache.count = 0; b2Distance(&output, &cache, &input); if (output.distance == 0 || cache.count == 3) { cache.count += 0; } } #endif // Leap of faith to new safe state. m_bodies[toiIndexA]->m_sweep.c0 = m_positions[toiIndexA].c; m_bodies[toiIndexA]->m_sweep.a0 = m_positions[toiIndexA].a; m_bodies[toiIndexB]->m_sweep.c0 = m_positions[toiIndexB].c; m_bodies[toiIndexB]->m_sweep.a0 = m_positions[toiIndexB].a; // No warm starting is needed for TOI events because warm // starting impulses were applied in the discrete solver. contactSolver.InitializeVelocityConstraints(); // Solve velocity constraints. for (int32 i = 0; i < subStep.velocityIterations; ++i) { contactSolver.SolveVelocityConstraints(); } // Don't store the TOI contact forces for warm starting // because they can be quite large. float32 h = subStep.dt; // Integrate positions for (int32 i = 0; i < m_bodyCount; ++i) { b2Vec2 c = m_positions[i].c; float32 a = m_positions[i].a; b2Vec2 v = m_velocities[i].v; float32 w = m_velocities[i].w; // Check for large velocities b2Vec2 translation = h * v; if (b2Dot(translation, translation) > b2_maxTranslationSquared) { float32 ratio = b2_maxTranslation / translation.Length(); v *= ratio; } float32 rotation = h * w; if (rotation * rotation > b2_maxRotationSquared) { float32 ratio = b2_maxRotation / b2Abs(rotation); w *= ratio; } // Integrate c += h * v; a += h * w; m_positions[i].c = c; m_positions[i].a = a; m_velocities[i].v = v; m_velocities[i].w = w; // Sync bodies b2Body* body = m_bodies[i]; body->m_sweep.c = c; body->m_sweep.a = a; body->m_linearVelocity = v; body->m_angularVelocity = w; body->SynchronizeTransform(); } Report(contactSolver.m_velocityConstraints); } void b2Island::Report(const b2ContactVelocityConstraint* constraints) { if (m_listener == NULL) { return; } for (int32 i = 0; i < m_contactCount; ++i) { b2Contact* c = m_contacts[i]; const b2ContactVelocityConstraint* vc = constraints + i; b2ContactImpulse impulse; impulse.count = vc->pointCount; for (int32 j = 0; j < vc->pointCount; ++j) { impulse.normalImpulses[j] = vc->points[j].normalImpulse; impulse.tangentImpulses[j] = vc->points[j].tangentImpulse; } m_listener->PostSolve(c, &impulse); } } pybox2d-2.3.2/Box2D/Dynamics/b2Island.h000066400000000000000000000046151276457661000174250ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_ISLAND_H #define B2_ISLAND_H #include #include #include class b2Contact; class b2Joint; class b2StackAllocator; class b2ContactListener; struct b2ContactVelocityConstraint; struct b2Profile; /// This is an internal class. class b2Island { public: b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, b2StackAllocator* allocator, b2ContactListener* listener); ~b2Island(); void Clear() { m_bodyCount = 0; m_contactCount = 0; m_jointCount = 0; } void Solve(b2Profile* profile, const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep); void SolveTOI(const b2TimeStep& subStep, int32 toiIndexA, int32 toiIndexB); void Add(b2Body* body) { b2Assert(m_bodyCount < m_bodyCapacity); body->m_islandIndex = m_bodyCount; m_bodies[m_bodyCount] = body; ++m_bodyCount; } void Add(b2Contact* contact) { b2Assert(m_contactCount < m_contactCapacity); m_contacts[m_contactCount++] = contact; } void Add(b2Joint* joint) { b2Assert(m_jointCount < m_jointCapacity); m_joints[m_jointCount++] = joint; } void Report(const b2ContactVelocityConstraint* constraints); b2StackAllocator* m_allocator; b2ContactListener* m_listener; b2Body** m_bodies; b2Contact** m_contacts; b2Joint** m_joints; b2Position* m_positions; b2Velocity* m_velocities; int32 m_bodyCount; int32 m_jointCount; int32 m_contactCount; int32 m_bodyCapacity; int32 m_contactCapacity; int32 m_jointCapacity; }; #endif pybox2d-2.3.2/Box2D/Dynamics/b2TimeStep.h000066400000000000000000000033101276457661000177340ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_TIME_STEP_H #define B2_TIME_STEP_H #include /// Profiling data. Times are in milliseconds. struct b2Profile { float32 step; float32 collide; float32 solve; float32 solveInit; float32 solveVelocity; float32 solvePosition; float32 broadphase; float32 solveTOI; }; /// This is an internal structure. struct b2TimeStep { float32 dt; // time step float32 inv_dt; // inverse time step (0 if dt == 0). float32 dtRatio; // dt * inv_dt0 int32 velocityIterations; int32 positionIterations; bool warmStarting; }; /// This is an internal structure. struct b2Position { b2Vec2 c; float32 a; }; /// This is an internal structure. struct b2Velocity { b2Vec2 v; float32 w; }; /// Solver Data struct b2SolverData { b2TimeStep step; b2Position* positions; b2Velocity* velocities; }; #endif pybox2d-2.3.2/Box2D/Dynamics/b2World.cpp000066400000000000000000000720101276457661000176270ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include b2World::b2World(const b2Vec2& gravity) { m_destructionListener = NULL; m_debugDraw = NULL; m_bodyList = NULL; m_jointList = NULL; m_bodyCount = 0; m_jointCount = 0; m_warmStarting = true; m_continuousPhysics = true; m_subStepping = false; m_stepComplete = true; m_allowSleep = true; m_gravity = gravity; m_flags = e_clearForces; m_inv_dt0 = 0.0f; m_contactManager.m_allocator = &m_blockAllocator; memset(&m_profile, 0, sizeof(b2Profile)); } b2World::~b2World() { // Some shapes allocate using b2Alloc. b2Body* b = m_bodyList; while (b) { b2Body* bNext = b->m_next; b2Fixture* f = b->m_fixtureList; while (f) { b2Fixture* fNext = f->m_next; f->m_proxyCount = 0; f->Destroy(&m_blockAllocator); f = fNext; } b = bNext; } } void b2World::SetDestructionListener(b2DestructionListener* listener) { m_destructionListener = listener; } void b2World::SetContactFilter(b2ContactFilter* filter) { m_contactManager.m_contactFilter = filter; } void b2World::SetContactListener(b2ContactListener* listener) { m_contactManager.m_contactListener = listener; } void b2World::SetDebugDraw(b2Draw* debugDraw) { m_debugDraw = debugDraw; } b2Body* b2World::CreateBody(const b2BodyDef* def) { b2Assert(IsLocked() == false); if (IsLocked()) { return NULL; } void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); b2Body* b = new (mem) b2Body(def, this); // Add to world doubly linked list. b->m_prev = NULL; b->m_next = m_bodyList; if (m_bodyList) { m_bodyList->m_prev = b; } m_bodyList = b; ++m_bodyCount; return b; } void b2World::DestroyBody(b2Body* b) { b2Assert(m_bodyCount > 0); b2Assert(IsLocked() == false); if (IsLocked()) { return; } // Delete the attached joints. b2JointEdge* je = b->m_jointList; while (je) { b2JointEdge* je0 = je; je = je->next; if (m_destructionListener) { m_destructionListener->SayGoodbye(je0->joint); } DestroyJoint(je0->joint); b->m_jointList = je; } b->m_jointList = NULL; // Delete the attached contacts. b2ContactEdge* ce = b->m_contactList; while (ce) { b2ContactEdge* ce0 = ce; ce = ce->next; m_contactManager.Destroy(ce0->contact); } b->m_contactList = NULL; // Delete the attached fixtures. This destroys broad-phase proxies. b2Fixture* f = b->m_fixtureList; while (f) { b2Fixture* f0 = f; f = f->m_next; if (m_destructionListener) { m_destructionListener->SayGoodbye(f0); } f0->DestroyProxies(&m_contactManager.m_broadPhase); f0->Destroy(&m_blockAllocator); f0->~b2Fixture(); m_blockAllocator.Free(f0, sizeof(b2Fixture)); b->m_fixtureList = f; b->m_fixtureCount -= 1; } b->m_fixtureList = NULL; b->m_fixtureCount = 0; // Remove world body list. if (b->m_prev) { b->m_prev->m_next = b->m_next; } if (b->m_next) { b->m_next->m_prev = b->m_prev; } if (b == m_bodyList) { m_bodyList = b->m_next; } --m_bodyCount; b->~b2Body(); m_blockAllocator.Free(b, sizeof(b2Body)); } b2Joint* b2World::CreateJoint(const b2JointDef* def) { b2Assert(IsLocked() == false); if (IsLocked()) { return NULL; } b2Joint* j = b2Joint::Create(def, &m_blockAllocator); // Connect to the world list. j->m_prev = NULL; j->m_next = m_jointList; if (m_jointList) { m_jointList->m_prev = j; } m_jointList = j; ++m_jointCount; // Connect to the bodies' doubly linked lists. j->m_edgeA.joint = j; j->m_edgeA.other = j->m_bodyB; j->m_edgeA.prev = NULL; j->m_edgeA.next = j->m_bodyA->m_jointList; if (j->m_bodyA->m_jointList) j->m_bodyA->m_jointList->prev = &j->m_edgeA; j->m_bodyA->m_jointList = &j->m_edgeA; j->m_edgeB.joint = j; j->m_edgeB.other = j->m_bodyA; j->m_edgeB.prev = NULL; j->m_edgeB.next = j->m_bodyB->m_jointList; if (j->m_bodyB->m_jointList) j->m_bodyB->m_jointList->prev = &j->m_edgeB; j->m_bodyB->m_jointList = &j->m_edgeB; b2Body* bodyA = def->bodyA; b2Body* bodyB = def->bodyB; // If the joint prevents collisions, then flag any contacts for filtering. if (def->collideConnected == false) { b2ContactEdge* edge = bodyB->GetContactList(); while (edge) { if (edge->other == bodyA) { // Flag the contact for filtering at the next time step (where either // body is awake). edge->contact->FlagForFiltering(); } edge = edge->next; } } // Note: creating a joint doesn't wake the bodies. return j; } void b2World::DestroyJoint(b2Joint* j) { b2Assert(IsLocked() == false); if (IsLocked()) { return; } bool collideConnected = j->m_collideConnected; // Remove from the doubly linked list. if (j->m_prev) { j->m_prev->m_next = j->m_next; } if (j->m_next) { j->m_next->m_prev = j->m_prev; } if (j == m_jointList) { m_jointList = j->m_next; } // Disconnect from island graph. b2Body* bodyA = j->m_bodyA; b2Body* bodyB = j->m_bodyB; // Wake up connected bodies. bodyA->SetAwake(true); bodyB->SetAwake(true); // Remove from body 1. if (j->m_edgeA.prev) { j->m_edgeA.prev->next = j->m_edgeA.next; } if (j->m_edgeA.next) { j->m_edgeA.next->prev = j->m_edgeA.prev; } if (&j->m_edgeA == bodyA->m_jointList) { bodyA->m_jointList = j->m_edgeA.next; } j->m_edgeA.prev = NULL; j->m_edgeA.next = NULL; // Remove from body 2 if (j->m_edgeB.prev) { j->m_edgeB.prev->next = j->m_edgeB.next; } if (j->m_edgeB.next) { j->m_edgeB.next->prev = j->m_edgeB.prev; } if (&j->m_edgeB == bodyB->m_jointList) { bodyB->m_jointList = j->m_edgeB.next; } j->m_edgeB.prev = NULL; j->m_edgeB.next = NULL; b2Joint::Destroy(j, &m_blockAllocator); b2Assert(m_jointCount > 0); --m_jointCount; // If the joint prevents collisions, then flag any contacts for filtering. if (collideConnected == false) { b2ContactEdge* edge = bodyB->GetContactList(); while (edge) { if (edge->other == bodyA) { // Flag the contact for filtering at the next time step (where either // body is awake). edge->contact->FlagForFiltering(); } edge = edge->next; } } } // void b2World::SetAllowSleeping(bool flag) { if (flag == m_allowSleep) { return; } m_allowSleep = flag; if (m_allowSleep == false) { for (b2Body* b = m_bodyList; b; b = b->m_next) { b->SetAwake(true); } } } // Find islands, integrate and solve constraints, solve position constraints void b2World::Solve(const b2TimeStep& step) { m_profile.solveInit = 0.0f; m_profile.solveVelocity = 0.0f; m_profile.solvePosition = 0.0f; // Size the island for the worst case. b2Island island(m_bodyCount, m_contactManager.m_contactCount, m_jointCount, &m_stackAllocator, m_contactManager.m_contactListener); // Clear all the island flags. for (b2Body* b = m_bodyList; b; b = b->m_next) { b->m_flags &= ~b2Body::e_islandFlag; } for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) { c->m_flags &= ~b2Contact::e_islandFlag; } for (b2Joint* j = m_jointList; j; j = j->m_next) { j->m_islandFlag = false; } // Build and simulate all awake islands. int32 stackSize = m_bodyCount; b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*)); for (b2Body* seed = m_bodyList; seed; seed = seed->m_next) { if (seed->m_flags & b2Body::e_islandFlag) { continue; } if (seed->IsAwake() == false || seed->IsActive() == false) { continue; } // The seed can be dynamic or kinematic. if (seed->GetType() == b2_staticBody) { continue; } // Reset island and stack. island.Clear(); int32 stackCount = 0; stack[stackCount++] = seed; seed->m_flags |= b2Body::e_islandFlag; // Perform a depth first search (DFS) on the constraint graph. while (stackCount > 0) { // Grab the next body off the stack and add it to the island. b2Body* b = stack[--stackCount]; b2Assert(b->IsActive() == true); island.Add(b); // Make sure the body is awake. b->SetAwake(true); // To keep islands as small as possible, we don't // propagate islands across static bodies. if (b->GetType() == b2_staticBody) { continue; } // Search all contacts connected to this body. for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next) { b2Contact* contact = ce->contact; // Has this contact already been added to an island? if (contact->m_flags & b2Contact::e_islandFlag) { continue; } // Is this contact solid and touching? if (contact->IsEnabled() == false || contact->IsTouching() == false) { continue; } // Skip sensors. bool sensorA = contact->m_fixtureA->m_isSensor; bool sensorB = contact->m_fixtureB->m_isSensor; if (sensorA || sensorB) { continue; } island.Add(contact); contact->m_flags |= b2Contact::e_islandFlag; b2Body* other = ce->other; // Was the other body already added to this island? if (other->m_flags & b2Body::e_islandFlag) { continue; } b2Assert(stackCount < stackSize); stack[stackCount++] = other; other->m_flags |= b2Body::e_islandFlag; } // Search all joints connect to this body. for (b2JointEdge* je = b->m_jointList; je; je = je->next) { if (je->joint->m_islandFlag == true) { continue; } b2Body* other = je->other; // Don't simulate joints connected to inactive bodies. if (other->IsActive() == false) { continue; } island.Add(je->joint); je->joint->m_islandFlag = true; if (other->m_flags & b2Body::e_islandFlag) { continue; } b2Assert(stackCount < stackSize); stack[stackCount++] = other; other->m_flags |= b2Body::e_islandFlag; } } b2Profile profile; island.Solve(&profile, step, m_gravity, m_allowSleep); m_profile.solveInit += profile.solveInit; m_profile.solveVelocity += profile.solveVelocity; m_profile.solvePosition += profile.solvePosition; // Post solve cleanup. for (int32 i = 0; i < island.m_bodyCount; ++i) { // Allow static bodies to participate in other islands. b2Body* b = island.m_bodies[i]; if (b->GetType() == b2_staticBody) { b->m_flags &= ~b2Body::e_islandFlag; } } } m_stackAllocator.Free(stack); { b2Timer timer; // Synchronize fixtures, check for out of range bodies. for (b2Body* b = m_bodyList; b; b = b->GetNext()) { // If a body was not in an island then it did not move. if ((b->m_flags & b2Body::e_islandFlag) == 0) { continue; } if (b->GetType() == b2_staticBody) { continue; } // Update fixtures (for broad-phase). b->SynchronizeFixtures(); } // Look for new contacts. m_contactManager.FindNewContacts(); m_profile.broadphase = timer.GetMilliseconds(); } } // Find TOI contacts and solve them. void b2World::SolveTOI(const b2TimeStep& step) { b2Island island(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, &m_stackAllocator, m_contactManager.m_contactListener); if (m_stepComplete) { for (b2Body* b = m_bodyList; b; b = b->m_next) { b->m_flags &= ~b2Body::e_islandFlag; b->m_sweep.alpha0 = 0.0f; } for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) { // Invalidate TOI c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); c->m_toiCount = 0; c->m_toi = 1.0f; } } // Find TOI events and solve them. for (;;) { // Find the first TOI. b2Contact* minContact = NULL; float32 minAlpha = 1.0f; for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) { // Is this contact disabled? if (c->IsEnabled() == false) { continue; } // Prevent excessive sub-stepping. if (c->m_toiCount > b2_maxSubSteps) { continue; } float32 alpha = 1.0f; if (c->m_flags & b2Contact::e_toiFlag) { // This contact has a valid cached TOI. alpha = c->m_toi; } else { b2Fixture* fA = c->GetFixtureA(); b2Fixture* fB = c->GetFixtureB(); // Is there a sensor? if (fA->IsSensor() || fB->IsSensor()) { continue; } b2Body* bA = fA->GetBody(); b2Body* bB = fB->GetBody(); b2BodyType typeA = bA->m_type; b2BodyType typeB = bB->m_type; b2Assert(typeA == b2_dynamicBody || typeB == b2_dynamicBody); bool activeA = bA->IsAwake() && typeA != b2_staticBody; bool activeB = bB->IsAwake() && typeB != b2_staticBody; // Is at least one body active (awake and dynamic or kinematic)? if (activeA == false && activeB == false) { continue; } bool collideA = bA->IsBullet() || typeA != b2_dynamicBody; bool collideB = bB->IsBullet() || typeB != b2_dynamicBody; // Are these two non-bullet dynamic bodies? if (collideA == false && collideB == false) { continue; } // Compute the TOI for this contact. // Put the sweeps onto the same time interval. float32 alpha0 = bA->m_sweep.alpha0; if (bA->m_sweep.alpha0 < bB->m_sweep.alpha0) { alpha0 = bB->m_sweep.alpha0; bA->m_sweep.Advance(alpha0); } else if (bB->m_sweep.alpha0 < bA->m_sweep.alpha0) { alpha0 = bA->m_sweep.alpha0; bB->m_sweep.Advance(alpha0); } b2Assert(alpha0 < 1.0f); int32 indexA = c->GetChildIndexA(); int32 indexB = c->GetChildIndexB(); // Compute the time of impact in interval [0, minTOI] b2TOIInput input; input.proxyA.Set(fA->GetShape(), indexA); input.proxyB.Set(fB->GetShape(), indexB); input.sweepA = bA->m_sweep; input.sweepB = bB->m_sweep; input.tMax = 1.0f; b2TOIOutput output; b2TimeOfImpact(&output, &input); // Beta is the fraction of the remaining portion of the . float32 beta = output.t; if (output.state == b2TOIOutput::e_touching) { alpha = b2Min(alpha0 + (1.0f - alpha0) * beta, 1.0f); } else { alpha = 1.0f; } c->m_toi = alpha; c->m_flags |= b2Contact::e_toiFlag; } if (alpha < minAlpha) { // This is the minimum TOI found so far. minContact = c; minAlpha = alpha; } } if (minContact == NULL || 1.0f - 10.0f * b2_epsilon < minAlpha) { // No more TOI events. Done! m_stepComplete = true; break; } // Advance the bodies to the TOI. b2Fixture* fA = minContact->GetFixtureA(); b2Fixture* fB = minContact->GetFixtureB(); b2Body* bA = fA->GetBody(); b2Body* bB = fB->GetBody(); b2Sweep backup1 = bA->m_sweep; b2Sweep backup2 = bB->m_sweep; bA->Advance(minAlpha); bB->Advance(minAlpha); // The TOI contact likely has some new contact points. minContact->Update(m_contactManager.m_contactListener); minContact->m_flags &= ~b2Contact::e_toiFlag; ++minContact->m_toiCount; // Is the contact solid? if (minContact->IsEnabled() == false || minContact->IsTouching() == false) { // Restore the sweeps. minContact->SetEnabled(false); bA->m_sweep = backup1; bB->m_sweep = backup2; bA->SynchronizeTransform(); bB->SynchronizeTransform(); continue; } bA->SetAwake(true); bB->SetAwake(true); // Build the island island.Clear(); island.Add(bA); island.Add(bB); island.Add(minContact); bA->m_flags |= b2Body::e_islandFlag; bB->m_flags |= b2Body::e_islandFlag; minContact->m_flags |= b2Contact::e_islandFlag; // Get contacts on bodyA and bodyB. b2Body* bodies[2] = {bA, bB}; for (int32 i = 0; i < 2; ++i) { b2Body* body = bodies[i]; if (body->m_type == b2_dynamicBody) { for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) { if (island.m_bodyCount == island.m_bodyCapacity) { break; } if (island.m_contactCount == island.m_contactCapacity) { break; } b2Contact* contact = ce->contact; // Has this contact already been added to the island? if (contact->m_flags & b2Contact::e_islandFlag) { continue; } // Only add static, kinematic, or bullet bodies. b2Body* other = ce->other; if (other->m_type == b2_dynamicBody && body->IsBullet() == false && other->IsBullet() == false) { continue; } // Skip sensors. bool sensorA = contact->m_fixtureA->m_isSensor; bool sensorB = contact->m_fixtureB->m_isSensor; if (sensorA || sensorB) { continue; } // Tentatively advance the body to the TOI. b2Sweep backup = other->m_sweep; if ((other->m_flags & b2Body::e_islandFlag) == 0) { other->Advance(minAlpha); } // Update the contact points contact->Update(m_contactManager.m_contactListener); // Was the contact disabled by the user? if (contact->IsEnabled() == false) { other->m_sweep = backup; other->SynchronizeTransform(); continue; } // Are there contact points? if (contact->IsTouching() == false) { other->m_sweep = backup; other->SynchronizeTransform(); continue; } // Add the contact to the island contact->m_flags |= b2Contact::e_islandFlag; island.Add(contact); // Has the other body already been added to the island? if (other->m_flags & b2Body::e_islandFlag) { continue; } // Add the other body to the island. other->m_flags |= b2Body::e_islandFlag; if (other->m_type != b2_staticBody) { other->SetAwake(true); } island.Add(other); } } } b2TimeStep subStep; subStep.dt = (1.0f - minAlpha) * step.dt; subStep.inv_dt = 1.0f / subStep.dt; subStep.dtRatio = 1.0f; subStep.positionIterations = 20; subStep.velocityIterations = step.velocityIterations; subStep.warmStarting = false; island.SolveTOI(subStep, bA->m_islandIndex, bB->m_islandIndex); // Reset island flags and synchronize broad-phase proxies. for (int32 i = 0; i < island.m_bodyCount; ++i) { b2Body* body = island.m_bodies[i]; body->m_flags &= ~b2Body::e_islandFlag; if (body->m_type != b2_dynamicBody) { continue; } body->SynchronizeFixtures(); // Invalidate all contact TOIs on this displaced body. for (b2ContactEdge* ce = body->m_contactList; ce; ce = ce->next) { ce->contact->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); } } // Commit fixture proxy movements to the broad-phase so that new contacts are created. // Also, some contacts can be destroyed. m_contactManager.FindNewContacts(); if (m_subStepping) { m_stepComplete = false; break; } } } void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations) { b2Timer stepTimer; // If new fixtures were added, we need to find the new contacts. if (m_flags & e_newFixture) { m_contactManager.FindNewContacts(); m_flags &= ~e_newFixture; } m_flags |= e_locked; b2TimeStep step; step.dt = dt; step.velocityIterations = velocityIterations; step.positionIterations = positionIterations; if (dt > 0.0f) { step.inv_dt = 1.0f / dt; } else { step.inv_dt = 0.0f; } step.dtRatio = m_inv_dt0 * dt; step.warmStarting = m_warmStarting; // Update contacts. This is where some contacts are destroyed. { b2Timer timer; m_contactManager.Collide(); m_profile.collide = timer.GetMilliseconds(); } // Integrate velocities, solve velocity constraints, and integrate positions. if (m_stepComplete && step.dt > 0.0f) { b2Timer timer; Solve(step); m_profile.solve = timer.GetMilliseconds(); } // Handle TOI events. if (m_continuousPhysics && step.dt > 0.0f) { b2Timer timer; SolveTOI(step); m_profile.solveTOI = timer.GetMilliseconds(); } if (step.dt > 0.0f) { m_inv_dt0 = step.inv_dt; } if (m_flags & e_clearForces) { ClearForces(); } m_flags &= ~e_locked; m_profile.step = stepTimer.GetMilliseconds(); } void b2World::ClearForces() { for (b2Body* body = m_bodyList; body; body = body->GetNext()) { body->m_force.SetZero(); body->m_torque = 0.0f; } } struct b2WorldQueryWrapper { bool QueryCallback(int32 proxyId) { b2FixtureProxy* proxy = (b2FixtureProxy*)broadPhase->GetUserData(proxyId); return callback->ReportFixture(proxy->fixture); } const b2BroadPhase* broadPhase; b2QueryCallback* callback; }; void b2World::QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const { b2WorldQueryWrapper wrapper; wrapper.broadPhase = &m_contactManager.m_broadPhase; wrapper.callback = callback; m_contactManager.m_broadPhase.Query(&wrapper, aabb); } struct b2WorldRayCastWrapper { float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) { void* userData = broadPhase->GetUserData(proxyId); b2FixtureProxy* proxy = (b2FixtureProxy*)userData; b2Fixture* fixture = proxy->fixture; int32 index = proxy->childIndex; b2RayCastOutput output; bool hit = fixture->RayCast(&output, input, index); if (hit) { float32 fraction = output.fraction; b2Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2; return callback->ReportFixture(fixture, point, output.normal, fraction); } return input.maxFraction; } const b2BroadPhase* broadPhase; b2RayCastCallback* callback; }; void b2World::RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const { b2WorldRayCastWrapper wrapper; wrapper.broadPhase = &m_contactManager.m_broadPhase; wrapper.callback = callback; b2RayCastInput input; input.maxFraction = 1.0f; input.p1 = point1; input.p2 = point2; m_contactManager.m_broadPhase.RayCast(&wrapper, input); } void b2World::DrawShape(b2Fixture* fixture, const b2Transform& xf, const b2Color& color) { switch (fixture->GetType()) { case b2Shape::e_circle: { b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); b2Vec2 center = b2Mul(xf, circle->m_p); float32 radius = circle->m_radius; b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f)); m_debugDraw->DrawSolidCircle(center, radius, axis, color); } break; case b2Shape::e_edge: { b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape(); b2Vec2 v1 = b2Mul(xf, edge->m_vertex1); b2Vec2 v2 = b2Mul(xf, edge->m_vertex2); m_debugDraw->DrawSegment(v1, v2, color); } break; case b2Shape::e_chain: { b2ChainShape* chain = (b2ChainShape*)fixture->GetShape(); int32 count = chain->m_count; const b2Vec2* vertices = chain->m_vertices; b2Vec2 v1 = b2Mul(xf, vertices[0]); for (int32 i = 1; i < count; ++i) { b2Vec2 v2 = b2Mul(xf, vertices[i]); m_debugDraw->DrawSegment(v1, v2, color); m_debugDraw->DrawCircle(v1, 0.05f, color); v1 = v2; } } break; case b2Shape::e_polygon: { b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); int32 vertexCount = poly->m_count; b2Assert(vertexCount <= b2_maxPolygonVertices); b2Vec2 vertices[b2_maxPolygonVertices]; for (int32 i = 0; i < vertexCount; ++i) { vertices[i] = b2Mul(xf, poly->m_vertices[i]); } m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color); } break; default: break; } } void b2World::DrawJoint(b2Joint* joint) { b2Body* bodyA = joint->GetBodyA(); b2Body* bodyB = joint->GetBodyB(); const b2Transform& xf1 = bodyA->GetTransform(); const b2Transform& xf2 = bodyB->GetTransform(); b2Vec2 x1 = xf1.p; b2Vec2 x2 = xf2.p; b2Vec2 p1 = joint->GetAnchorA(); b2Vec2 p2 = joint->GetAnchorB(); b2Color color(0.5f, 0.8f, 0.8f); switch (joint->GetType()) { case e_distanceJoint: m_debugDraw->DrawSegment(p1, p2, color); break; case e_pulleyJoint: { b2PulleyJoint* pulley = (b2PulleyJoint*)joint; b2Vec2 s1 = pulley->GetGroundAnchorA(); b2Vec2 s2 = pulley->GetGroundAnchorB(); m_debugDraw->DrawSegment(s1, p1, color); m_debugDraw->DrawSegment(s2, p2, color); m_debugDraw->DrawSegment(s1, s2, color); } break; case e_mouseJoint: // don't draw this break; default: m_debugDraw->DrawSegment(x1, p1, color); m_debugDraw->DrawSegment(p1, p2, color); m_debugDraw->DrawSegment(x2, p2, color); } } void b2World::DrawDebugData() { if (m_debugDraw == NULL) { return; } uint32 flags = m_debugDraw->GetFlags(); if (flags & b2Draw::e_shapeBit) { for (b2Body* b = m_bodyList; b; b = b->GetNext()) { const b2Transform& xf = b->GetTransform(); for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) { if (b->IsActive() == false) { DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.3f)); } else if (b->GetType() == b2_staticBody) { DrawShape(f, xf, b2Color(0.5f, 0.9f, 0.5f)); } else if (b->GetType() == b2_kinematicBody) { DrawShape(f, xf, b2Color(0.5f, 0.5f, 0.9f)); } else if (b->IsAwake() == false) { DrawShape(f, xf, b2Color(0.6f, 0.6f, 0.6f)); } else { DrawShape(f, xf, b2Color(0.9f, 0.7f, 0.7f)); } } } } if (flags & b2Draw::e_jointBit) { for (b2Joint* j = m_jointList; j; j = j->GetNext()) { DrawJoint(j); } } if (flags & b2Draw::e_pairBit) { b2Color color(0.3f, 0.9f, 0.9f); for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext()) { //b2Fixture* fixtureA = c->GetFixtureA(); //b2Fixture* fixtureB = c->GetFixtureB(); //b2Vec2 cA = fixtureA->GetAABB().GetCenter(); //b2Vec2 cB = fixtureB->GetAABB().GetCenter(); //m_debugDraw->DrawSegment(cA, cB, color); } } if (flags & b2Draw::e_aabbBit) { b2Color color(0.9f, 0.3f, 0.9f); b2BroadPhase* bp = &m_contactManager.m_broadPhase; for (b2Body* b = m_bodyList; b; b = b->GetNext()) { if (b->IsActive() == false) { continue; } for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) { for (int32 i = 0; i < f->m_proxyCount; ++i) { b2FixtureProxy* proxy = f->m_proxies + i; b2AABB aabb = bp->GetFatAABB(proxy->proxyId); b2Vec2 vs[4]; vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); m_debugDraw->DrawPolygon(vs, 4, color); } } } } if (flags & b2Draw::e_centerOfMassBit) { for (b2Body* b = m_bodyList; b; b = b->GetNext()) { b2Transform xf = b->GetTransform(); xf.p = b->GetWorldCenter(); m_debugDraw->DrawTransform(xf); } } } int32 b2World::GetProxyCount() const { return m_contactManager.m_broadPhase.GetProxyCount(); } int32 b2World::GetTreeHeight() const { return m_contactManager.m_broadPhase.GetTreeHeight(); } int32 b2World::GetTreeBalance() const { return m_contactManager.m_broadPhase.GetTreeBalance(); } float32 b2World::GetTreeQuality() const { return m_contactManager.m_broadPhase.GetTreeQuality(); } void b2World::ShiftOrigin(const b2Vec2& newOrigin) { b2Assert((m_flags & e_locked) == 0); if ((m_flags & e_locked) == e_locked) { return; } for (b2Body* b = m_bodyList; b; b = b->m_next) { b->m_xf.p -= newOrigin; b->m_sweep.c0 -= newOrigin; b->m_sweep.c -= newOrigin; } for (b2Joint* j = m_jointList; j; j = j->m_next) { j->ShiftOrigin(newOrigin); } m_contactManager.m_broadPhase.ShiftOrigin(newOrigin); } void b2World::Dump() { if ((m_flags & e_locked) == e_locked) { return; } b2Log("b2Vec2 g(%.15lef, %.15lef);\n", m_gravity.x, m_gravity.y); b2Log("m_world->SetGravity(g);\n"); b2Log("b2Body** bodies = (b2Body**)b2Alloc(%d * sizeof(b2Body*));\n", m_bodyCount); b2Log("b2Joint** joints = (b2Joint**)b2Alloc(%d * sizeof(b2Joint*));\n", m_jointCount); int32 i = 0; for (b2Body* b = m_bodyList; b; b = b->m_next) { b->m_islandIndex = i; b->Dump(); ++i; } i = 0; for (b2Joint* j = m_jointList; j; j = j->m_next) { j->m_index = i; ++i; } // First pass on joints, skip gear joints. for (b2Joint* j = m_jointList; j; j = j->m_next) { if (j->m_type == e_gearJoint) { continue; } b2Log("{\n"); j->Dump(); b2Log("}\n"); } // Second pass on joints, only gear joints. for (b2Joint* j = m_jointList; j; j = j->m_next) { if (j->m_type != e_gearJoint) { continue; } b2Log("{\n"); j->Dump(); b2Log("}\n"); } b2Log("b2Free(joints);\n"); b2Log("b2Free(bodies);\n"); b2Log("joints = NULL;\n"); b2Log("bodies = NULL;\n"); } pybox2d-2.3.2/Box2D/Dynamics/b2World.h000066400000000000000000000251161276457661000173010ustar00rootroot00000000000000/* * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_WORLD_H #define B2_WORLD_H #include #include #include #include #include #include struct b2AABB; struct b2BodyDef; struct b2Color; struct b2JointDef; class b2Body; class b2Draw; class b2Fixture; class b2Joint; /// The world class manages all physics entities, dynamic simulation, /// and asynchronous queries. The world also contains efficient memory /// management facilities. class b2World { public: /// Construct a world object. /// @param gravity the world gravity vector. b2World(const b2Vec2& gravity); /// Destruct the world. All physics entities are destroyed and all heap memory is released. ~b2World(); /// Register a destruction listener. The listener is owned by you and must /// remain in scope. void SetDestructionListener(b2DestructionListener* listener); /// Register a contact filter to provide specific control over collision. /// Otherwise the default filter is used (b2_defaultFilter). The listener is /// owned by you and must remain in scope. void SetContactFilter(b2ContactFilter* filter); /// Register a contact event listener. The listener is owned by you and must /// remain in scope. void SetContactListener(b2ContactListener* listener); /// Register a routine for debug drawing. The debug draw functions are called /// inside with b2World::DrawDebugData method. The debug draw object is owned /// by you and must remain in scope. void SetDebugDraw(b2Draw* debugDraw); /// Create a rigid body given a definition. No reference to the definition /// is retained. /// @warning This function is locked during callbacks. b2Body* CreateBody(const b2BodyDef* def); /// Destroy a rigid body given a definition. No reference to the definition /// is retained. This function is locked during callbacks. /// @warning This automatically deletes all associated shapes and joints. /// @warning This function is locked during callbacks. void DestroyBody(b2Body* body); /// Create a joint to constrain bodies together. No reference to the definition /// is retained. This may cause the connected bodies to cease colliding. /// @warning This function is locked during callbacks. b2Joint* CreateJoint(const b2JointDef* def); /// Destroy a joint. This may cause the connected bodies to begin colliding. /// @warning This function is locked during callbacks. void DestroyJoint(b2Joint* joint); /// Take a time step. This performs collision detection, integration, /// and constraint solution. /// @param timeStep the amount of time to simulate, this should not vary. /// @param velocityIterations for the velocity constraint solver. /// @param positionIterations for the position constraint solver. void Step( float32 timeStep, int32 velocityIterations, int32 positionIterations); /// Manually clear the force buffer on all bodies. By default, forces are cleared automatically /// after each call to Step. The default behavior is modified by calling SetAutoClearForces. /// The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain /// a fixed sized time step under a variable frame-rate. /// When you perform sub-stepping you will disable auto clearing of forces and instead call /// ClearForces after all sub-steps are complete in one pass of your game loop. /// @see SetAutoClearForces void ClearForces(); /// Call this to draw shapes and other debug draw data. void DrawDebugData(); /// Query the world for all fixtures that potentially overlap the /// provided AABB. /// @param callback a user implemented callback class. /// @param aabb the query box. void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const; /// Ray-cast the world for all fixtures in the path of the ray. Your callback /// controls whether you get the closest point, any point, or n-points. /// The ray-cast ignores shapes that contain the starting point. /// @param callback a user implemented callback class. /// @param point1 the ray starting point /// @param point2 the ray ending point void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const; /// Get the world body list. With the returned body, use b2Body::GetNext to get /// the next body in the world list. A NULL body indicates the end of the list. /// @return the head of the world body list. b2Body* GetBodyList(); const b2Body* GetBodyList() const; /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get /// the next joint in the world list. A NULL joint indicates the end of the list. /// @return the head of the world joint list. b2Joint* GetJointList(); const b2Joint* GetJointList() const; /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get /// the next contact in the world list. A NULL contact indicates the end of the list. /// @return the head of the world contact list. /// @warning contacts are created and destroyed in the middle of a time step. /// Use b2ContactListener to avoid missing contacts. b2Contact* GetContactList(); const b2Contact* GetContactList() const; /// Enable/disable sleep. void SetAllowSleeping(bool flag); bool GetAllowSleeping() const { return m_allowSleep; } /// Enable/disable warm starting. For testing. void SetWarmStarting(bool flag) { m_warmStarting = flag; } bool GetWarmStarting() const { return m_warmStarting; } /// Enable/disable continuous physics. For testing. void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } bool GetContinuousPhysics() const { return m_continuousPhysics; } /// Enable/disable single stepped continuous physics. For testing. void SetSubStepping(bool flag) { m_subStepping = flag; } bool GetSubStepping() const { return m_subStepping; } /// Get the number of broad-phase proxies. int32 GetProxyCount() const; /// Get the number of bodies. int32 GetBodyCount() const; /// Get the number of joints. int32 GetJointCount() const; /// Get the number of contacts (each may have 0 or more contact points). int32 GetContactCount() const; /// Get the height of the dynamic tree. int32 GetTreeHeight() const; /// Get the balance of the dynamic tree. int32 GetTreeBalance() const; /// Get the quality metric of the dynamic tree. The smaller the better. /// The minimum is 1. float32 GetTreeQuality() const; /// Change the global gravity vector. void SetGravity(const b2Vec2& gravity); /// Get the global gravity vector. b2Vec2 GetGravity() const; /// Is the world locked (in the middle of a time step). bool IsLocked() const; /// Set flag to control automatic clearing of forces after each time step. void SetAutoClearForces(bool flag); /// Get the flag that controls automatic clearing of forces after each time step. bool GetAutoClearForces() const; /// Shift the world origin. Useful for large worlds. /// The body shift formula is: position -= newOrigin /// @param newOrigin the new origin with respect to the old origin void ShiftOrigin(const b2Vec2& newOrigin); /// Get the contact manager for testing. const b2ContactManager& GetContactManager() const; /// Get the current profile. const b2Profile& GetProfile() const; /// Dump the world into the log file. /// @warning this should be called outside of a time step. void Dump(); private: // m_flags enum { e_newFixture = 0x0001, e_locked = 0x0002, e_clearForces = 0x0004 }; friend class b2Body; friend class b2Fixture; friend class b2ContactManager; friend class b2Controller; void Solve(const b2TimeStep& step); void SolveTOI(const b2TimeStep& step); void DrawJoint(b2Joint* joint); void DrawShape(b2Fixture* shape, const b2Transform& xf, const b2Color& color); b2BlockAllocator m_blockAllocator; b2StackAllocator m_stackAllocator; int32 m_flags; b2ContactManager m_contactManager; b2Body* m_bodyList; b2Joint* m_jointList; int32 m_bodyCount; int32 m_jointCount; b2Vec2 m_gravity; bool m_allowSleep; b2DestructionListener* m_destructionListener; b2Draw* m_debugDraw; // This is used to compute the time step ratio to // support a variable time step. float32 m_inv_dt0; // These are for debugging the solver. bool m_warmStarting; bool m_continuousPhysics; bool m_subStepping; bool m_stepComplete; b2Profile m_profile; }; inline b2Body* b2World::GetBodyList() { return m_bodyList; } inline const b2Body* b2World::GetBodyList() const { return m_bodyList; } inline b2Joint* b2World::GetJointList() { return m_jointList; } inline const b2Joint* b2World::GetJointList() const { return m_jointList; } inline b2Contact* b2World::GetContactList() { return m_contactManager.m_contactList; } inline const b2Contact* b2World::GetContactList() const { return m_contactManager.m_contactList; } inline int32 b2World::GetBodyCount() const { return m_bodyCount; } inline int32 b2World::GetJointCount() const { return m_jointCount; } inline int32 b2World::GetContactCount() const { return m_contactManager.m_contactCount; } inline void b2World::SetGravity(const b2Vec2& gravity) { m_gravity = gravity; } inline b2Vec2 b2World::GetGravity() const { return m_gravity; } inline bool b2World::IsLocked() const { return (m_flags & e_locked) == e_locked; } inline void b2World::SetAutoClearForces(bool flag) { if (flag) { m_flags |= e_clearForces; } else { m_flags &= ~e_clearForces; } } /// Get the flag that controls automatic clearing of forces after each time step. inline bool b2World::GetAutoClearForces() const { return (m_flags & e_clearForces) == e_clearForces; } inline const b2ContactManager& b2World::GetContactManager() const { return m_contactManager; } inline const b2Profile& b2World::GetProfile() const { return m_profile; } #endif pybox2d-2.3.2/Box2D/Dynamics/b2WorldCallbacks.cpp000066400000000000000000000030751276457661000214340ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include // Return true if contact calculations should be performed between these two shapes. // If you implement your own collision filter you may want to build from this implementation. bool b2ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB) { const b2Filter& filterA = fixtureA->GetFilterData(); const b2Filter& filterB = fixtureB->GetFilterData(); if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0) { return filterA.groupIndex > 0; } bool collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0; return collide; } pybox2d-2.3.2/Box2D/Dynamics/b2WorldCallbacks.h000066400000000000000000000133041276457661000210750ustar00rootroot00000000000000/* * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_WORLD_CALLBACKS_H #define B2_WORLD_CALLBACKS_H #include struct b2Vec2; struct b2Transform; class b2Fixture; class b2Body; class b2Joint; class b2Contact; struct b2ContactResult; struct b2Manifold; /// Joints and fixtures are destroyed when their associated /// body is destroyed. Implement this listener so that you /// may nullify references to these joints and shapes. class b2DestructionListener { public: virtual ~b2DestructionListener() {} /// Called when any joint is about to be destroyed due /// to the destruction of one of its attached bodies. virtual void SayGoodbye(b2Joint* joint) = 0; /// Called when any fixture is about to be destroyed due /// to the destruction of its parent body. virtual void SayGoodbye(b2Fixture* fixture) = 0; }; /// Implement this class to provide collision filtering. In other words, you can implement /// this class if you want finer control over contact creation. class b2ContactFilter { public: virtual ~b2ContactFilter() {} /// Return true if contact calculations should be performed between these two shapes. /// @warning for performance reasons this is only called when the AABBs begin to overlap. virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB); }; /// Contact impulses for reporting. Impulses are used instead of forces because /// sub-step forces may approach infinity for rigid body collisions. These /// match up one-to-one with the contact points in b2Manifold. struct b2ContactImpulse { float32 normalImpulses[b2_maxManifoldPoints]; float32 tangentImpulses[b2_maxManifoldPoints]; int32 count; }; /// Implement this class to get contact information. You can use these results for /// things like sounds and game logic. You can also get contact results by /// traversing the contact lists after the time step. However, you might miss /// some contacts because continuous physics leads to sub-stepping. /// Additionally you may receive multiple callbacks for the same contact in a /// single time step. /// You should strive to make your callbacks efficient because there may be /// many callbacks per time step. /// @warning You cannot create/destroy Box2D entities inside these callbacks. class b2ContactListener { public: virtual ~b2ContactListener() {} /// Called when two fixtures begin to touch. virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } /// Called when two fixtures cease to touch. virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } /// This is called after a contact is updated. This allows you to inspect a /// contact before it goes to the solver. If you are careful, you can modify the /// contact manifold (e.g. disable contact). /// A copy of the old manifold is provided so that you can detect changes. /// Note: this is called only for awake bodies. /// Note: this is called even when the number of contact points is zero. /// Note: this is not called for sensors. /// Note: if you set the number of contact points to zero, you will not /// get an EndContact callback. However, you may get a BeginContact callback /// the next step. virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { B2_NOT_USED(contact); B2_NOT_USED(oldManifold); } /// This lets you inspect a contact after the solver is finished. This is useful /// for inspecting impulses. /// Note: the contact manifold does not include time of impact impulses, which can be /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly /// in a separate data structure. /// Note: this is only called for contacts that are touching, solid, and awake. virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) { B2_NOT_USED(contact); B2_NOT_USED(impulse); } }; /// Callback class for AABB queries. /// See b2World::Query class b2QueryCallback { public: virtual ~b2QueryCallback() {} /// Called for each fixture found in the query AABB. /// @return false to terminate the query. virtual bool ReportFixture(b2Fixture* fixture) = 0; }; /// Callback class for ray casts. /// See b2World::RayCast class b2RayCastCallback { public: virtual ~b2RayCastCallback() {} /// Called for each fixture found in the query. You control how the ray cast /// proceeds by returning a float: /// return -1: ignore this fixture and continue /// return 0: terminate the ray cast /// return fraction: clip the ray to this point /// return 1: don't clip the ray and continue /// @param fixture the fixture hit by the ray /// @param point the point of initial intersection /// @param normal the normal vector at the point of intersection /// @return -1 to filter, 0 to terminate, fraction to clip the ray for /// closest hit, 1 to continue virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float32 fraction) = 0; }; #endif pybox2d-2.3.2/Box2D/pybox2d_license_header.txt000066400000000000000000000017351276457661000212110ustar00rootroot00000000000000#!/usr/bin/python # # C++ version copyright 2010 Erin Catto http://www.gphysics.com # Python version copyright 2010 Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # pybox2d-2.3.2/INSTALL.md000066400000000000000000000114441276457661000145570ustar00rootroot00000000000000### Install pre-built conda package (it's easy!) ------------------------------------------------ 1. Install miniconda3. Download it from [here](http://conda.pydata.org/miniconda.html) 2. Create a new environment (named py34 here) and activate it: ```bash $ conda create -n py34 python=3.4 $ source activate py34 ``` 3. Install Box2D from my channel ```bash $ conda install -c https://conda.anaconda.org/kne pybox2d ``` Recent builds should be available for Windows, Linux, and OS X, with Python 2.7, 3.3, 3.4 and 3.5. 4. Alternatively, you can build pybox2d from its source code. You should only really do this if you want the latest features not available in the release or if you want to help contribute to pybox2d. See the section below corresponding to your operating system for more instructions on how to do this. ### The testbed examples ------------------------ 1. If using the conda packages, install a backend such as pygame to use as a renderer. I have packages for pygame and pygame_sdl2, the latter of which works better on OS X currently. ```bash $ source activate py34 $ conda install -c https://conda.anaconda.org/kne pygame_sdl2 ``` | Backend | Install | Homepage | | ------------- | ------------------------------------------------------------- | ------------------------------------ | | pygame | `conda install -c https://conda.anaconda.org/kne pygame` | http://pygame.org | | pygame_sdl2 | `conda install -c https://conda.anaconda.org/kne pygame_sdl2` | https://github.com/renpy/pygame_sdl2 | | pyqt4 | `conda install pyqt4` | https://www.riverbankcomputing.com/ | | pyglet | `pip install pyglet` | http://pyglet.org | | opencv | `pip install opencv` | http://opencv.org | 2. Download the latest release to get the examples: [releases](https://github.com/pybox2d/pybox2d/releases) Alternatively, if you have git installed, clone it instead: ```bash # The 2.3.1 release $ git clone https://github.com/pybox2d/pybox2d -b 2.3.1 # Or the latest development master branch $ git clone https://github.com/pybox2d/pybox2d ``` 3. Run an example with the desired backend: ```bash $ cd pybox2d # List all of the examples available: $ ls examples/*.py # Try the web example: $ python -m examples.web --backend=pygame ``` ### Building from source: Linux -------------------------------- 1. Download and install the latest version of SWIG (preferably 3.0+) with your package manager. If you are using Ubuntu, you can install it via Synaptic Package Manager (package name 'swig'). You will also need to install the python-dev package, and build-essential. Finally, you'll need python-pygame if you want to run the testbed. ```bash $ sudo apt-get install build-essential python-dev swig python-pygame git ``` 2. Clone the git repository ```bash $ git clone https://github.com/pybox2d/pybox2d ``` 3. Build and install the pybox2d library ```bash $ python setup.py build # Assuming everything goes well... $ sudo python setup.py install ``` ### Building from source: Windows ----------- 1. Install MinGW and then MSYS so that you can compile Box2D and pybox2d. Alternatively, install the correct version of Microsoft Visual Studio for your version of Python. 2. Install SWIG for making the Python wrapper. Install it in a location in your PATH, or add the SWIG directory to your PATH. 3. Clone the source from the git repository: ```bash $ git clone https://github.com/pybox2d/pybox2d ``` 4. Run MSYS and locate your pybox2d directory ```bash $ cd /c/path/to/pybox2d ``` 5. Build and install pybox2d ```bash $ python setup.py build $ python setup.py install ``` ### Building from source: OS X -------- 1. Install homebrew from http://brew.sh/ 2. Install SWIG, which wraps the C++ library. From a terminal window: ```bash $ brew install swig ``` 3. Clone the source from the git repository: ```bash $ git clone https://github.com/pybox2d/pybox2d pybox2d_dev $ cd pybox2d_dev ``` 4. Build and install pybox2d ```bash $ python setup.py build # Assuming you're using either Python from conda or brew Python, # you should be able to install without superuser privileges: $ python setup.py install # For development purposes, it may be more convenient to do a develop # install instead $ python setup.py develop ``` pybox2d-2.3.2/LICENSE000066400000000000000000000020711276457661000141300ustar00rootroot00000000000000This software is covered under the zlib license. C++ version Copyright (c) 2006-2011 Erin Catto http://www.box2d.org Python version Copyright (c) 2008-2011 Ken Lauer / sirkne at gmail dot com Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. pybox2d-2.3.2/MANIFEST.in000066400000000000000000000005161276457661000146630ustar00rootroot00000000000000include INSTALL include LICENSE include MANIFEST.in include MANIFEST include README include setup.py include distribute_setup.py recursive-include examples *.py recursive-include examples/data *.png *.tga *.txt *.ttf recursive-include examples/pgu * recursive-include library *.py recursive-include Box2D *.py *.i *.cpp *.h *.c *.txt pybox2d-2.3.2/README.md000066400000000000000000000020411276457661000143770ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/pybox2d/pybox2d.svg?branch=master)](https://travis-ci.org/pybox2d/pybox2d) [![Coverage Status](https://coveralls.io/repos/pybox2d/pybox2d/badge.svg?branch=master&service=github)](https://coveralls.io/github/pybox2d/pybox2d?branch=master) pybox2d ------- 2D Game Physics for Python https://github.com/pybox2d/pybox2d What is it? ----------- pybox2d is a 2D physics library for your games and simple simulations. It's based on the Box2D library, written in C++. It supports several shape types (circle, polygon, thin line segments), and quite a few joint types (revolute, prismatic, wheel, etc.). Getting Started --------------- For installation or building instructions, see [INSTALL.md](INSTALL.md). Check out the testbed [examples](examples) to see what pybox2d can do. Then take a look at the [getting started manual](https://github.com/pybox2d/pybox2d/wiki/manual) located on the pybox2d wiki. Bugs ---- Please submit any bugs that you find to the [issue tracker](https://github.com/pybox2d/pybox2d/issues). pybox2d-2.3.2/devel/000077500000000000000000000000001276457661000142225ustar00rootroot00000000000000pybox2d-2.3.2/devel/all_classes.py000066400000000000000000000061011276457661000170570ustar00rootroot00000000000000from __future__ import print_function # add "b2ContactPoint", as it's custom # First, define some classes not seen by swig ignore = ["b2ContactConstraint", "b2PolygonContact", "b2PolygonAndCircleContact", "b2CircleContact", "b2JointType", "b2BodyType", "b2ContactSolver", "b2PointState", "b2WorldQueryWrapper", "b2WorldRayCastWrapper", "b2SeparationFunction", "b2Block", "b2ContactConstraintPoint", "b2PositionSolverManifold", "b2LimitState"] # Then check which ones we manually ignore for line in open('../Box2D/Box2D.i', 'r').readlines(): if '%ignore' in line: c = line.split('ignore ')[1].strip() if ';' not in c: continue c = c[:c.index(';')].strip() ignore.append(c) all_classes= [ "b2AABB", "b2Block", "b2BlockAllocator", "b2Body", "b2BodyDef", "b2BodyType", "b2BroadPhase", "b2Chunk", "b2CircleContact", "b2CircleShape", "b2ClipVertex", "b2Color", "b2Contact", "b2ContactPoint", "b2ContactConstraint", "b2ContactConstraintPoint", "b2ContactEdge", "b2ContactFilter", "b2ContactID", "b2ContactImpulse", "b2ContactListener", "b2ContactManager", "b2ContactRegister", "b2ContactSolver", "b2DebugDraw", "b2DestructionListener", "b2DistanceInput", "b2DistanceJoint", "b2DistanceJointDef", "b2DistanceOutput", "b2DistanceProxy", "b2DynamicTree", "b2DynamicTreeNode", "b2Filter", "b2Fixture", "b2FixtureDef", "b2FrictionJoint", "b2FrictionJointDef", "b2GearJoint", "b2GearJointDef", "b2Island", "b2Jacobian", "b2Joint", "b2JointDef", "b2JointEdge", "b2JointType", "b2LimitState", "b2LineJoint", "b2LineJointDef", "b2Manifold", "b2ManifoldPoint", "b2MassData", "b2Mat22", "b2Mat33", "b2MouseJoint", "b2MouseJointDef", "b2Pair", "b2PointState", "b2PolygonAndCircleContact", "b2PolygonContact", "b2PolygonShape", "b2Position", "b2PositionSolverManifold", "b2PrismaticJoint", "b2PrismaticJointDef", "b2PulleyJoint", "b2PulleyJointDef", "b2QueryCallback", "b2RayCastCallback", "b2RayCastInput", "b2RayCastOutput", "b2RevoluteJoint", "b2RevoluteJointDef", "b2Segment", "b2SeparationFunction", "b2Shape", "b2Simplex", "b2SimplexCache", "b2SimplexVertex", "b2StackAllocator", "b2StackEntry", "b2Sweep", "b2TimeStep", "b2TOIInput", "b2Transform", "b2Vec2", "b2Vec3", "b2Velocity", "b2Version", "b2WeldJoint", "b2WeldJointDef", "b2World", "b2WorldManifold", "b2WorldQueryWrapper", "b2WorldRayCastWrapper" ] # Statistics print("Total classes: %d" % len(all_classes)) print('Ignored classes:', len(ignore)) for c in ignore: if c not in all_classes: print('%s not found' % c) else: all_classes.remove(c) print('Remaining classes:', len(all_classes)) # And the classes are available in 'all_classes' pybox2d-2.3.2/devel/dict_replacement.py000066400000000000000000000040051276457661000200750ustar00rootroot00000000000000from all_classes import * print(""" /* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %pythoncode %{ def _dir_filter(self): # Using introspection, mimic dir() by adding up all of the __dicts__ # for the current class and all base classes (type(self).__mro__ returns # all of the classes that make it up) # Basically filters by: # __x__ OK # __x bad # _classname bad def check(s): if s[:2]=='__': if s[-2:]=='__': return True else: return False else: for typename in typenames: if typename in s: return False return True keys=sum([c.__dict__.keys() for c in type(self).__mro__], []) typenames = ["_%s" % c.__name__ for c in type(self).__mro__] ret=[s for s in list(set(keys)) if check(s)] ret.sort() return ret %} """) extend_string=""" %%extend %s { %%pythoncode %%{ __dir__ = _dir_filter %%} } """ for c in all_classes: print(extend_string % c) pybox2d-2.3.2/devel/find_extended.py000066400000000000000000000021341276457661000173740ustar00rootroot00000000000000from __future__ import print_function import glob import re import os from all_classes import * files = glob.glob('../Box2D/Box2D_*.i') classes = {} ignore_files = [ 'Box2D_kwargs.i', 'Box2D_dir.i', ] def find_extended(path): f = open(path, "r") fn = os.path.split(path)[1] for line in f.readlines(): m=re.search('%extend\s*(.*)\s*{', line) if m: cls=m.groups()[0].strip() if cls in classes: if fn not in classes[cls]: classes[cls].append(fn) else: classes[cls] = [fn] f.close() for file in files: if os.path.split(file)[1] not in ignore_files: find_extended(file) print("%19s %s" % ('Class', 'Extended in')) remaining=list(all_classes) for key, value in list(classes.items()): print("%20s %s" % (key, ', '.join(value))) remaining.remove(key) ignore_unmodified=[s for s in remaining if s[-3:] == 'Def'] #ignore_unmodified += [] print() print("Unmodified classes") for cls in remaining: if cls not in ignore_unmodified: print(cls) pybox2d-2.3.2/devel/find_results000066400000000000000000000053601276457661000166520ustar00rootroot00000000000000Total classes: 95 Ignored classes: 29 Remaining classes: 66 Class Extended in b2Shape Box2D_shapes.i b2Fixture Box2D_bodyfixture.i, Box2D_userdata.i b2MouseJoint Box2D_joints.i b2PulleyJoint Box2D_joints.i b2LineJoint Box2D_joints.i b2Vec2 Box2D_vectors.i b2Vec3 Box2D_vectors.i b2AABB Box2D_vectors.i b2FixtureDef Box2D_bodyfixture.i, Box2D_userdata.i b2BodyDef Box2D_bodyfixture.i, Box2D_userdata.i b2Manifold Box2D_contact.i b2WorldManifold Box2D_contact.i b2World Box2D_userdata.i, Box2D_world.i b2PrismaticJoint Box2D_joints.i b2CircleShape Box2D_shapes.i b2Joint Box2D_joints.i, Box2D_userdata.i b2GearJoint Box2D_joints.i b2WeldJoint Box2D_joints.i b2RevoluteJoint Box2D_joints.i b2Mat22 Box2D_vectors.i b2JointDef Box2D_userdata.i b2Transform Box2D_vectors.i b2Color Box2D_misc.i b2PolygonShape Box2D_shapes.i b2Contact Box2D_contact.i b2DistanceJoint Box2D_joints.i b2Body Box2D_bodyfixture.i, Box2D_userdata.i b2FrictionJoint Box2D_joints.i Newly modified, to check/test ----------------------------- b2DistanceProxy # Needed for b2DistanceInput b2Mat33 # Add support for b2Mat33 * b2Vec3 / TODO: test all matrix math, and add a test b2Segment # TestSegment with output b2Version # TODO: __repr__ modification Unmodified classes ------------------ b2ContactImpulse # TODO: check this (PostSolve) b2RayCastCallback # Director added, should be ok (TODO: check raycasts) b2DebugDraw # Director added, should be ok b2DestructionList. # Director added, should be ok b2QueryCallback # Director added, should be ok b2BlockAllocator # Could possibly be used with b2Shape.Clone(), # but not without access to the block allocator. Ignoring this and the clone function. b2Sweep # Actually should be ok b2ClipVertex # Basic struct b2ContactPoint # Created in Box2D_contact.i b2ContactEdge # Basic struct b2ContactFilter # Director added, should be ok b2ContactID # Basic union b2ContactListener # Director added, should be ok b2ContactRegister # Added to ignore list, shouldn't be used b2DistanceInput # Should be ok unmodified. Basic struct b2DistanceOutput # Basic struct b2Filter # Basic struct b2Jacobian # Basic struct with a couple functions. b2JointEdge # Basic struct b2ManifoldPoint # Basic struct b2MassData # Basic struct b2Pair # Basic struct b2RayCastInput # Basic struct b2RayCastOutput # Basic struct b2TOIInput # Basic struct pybox2d-2.3.2/devel/init_kwargs.py000066400000000000000000000043351276457661000171220ustar00rootroot00000000000000from all_classes import * print(""" /* * pybox2d -- http://pybox2d.googlecode.com * * Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %pythoncode %{ def _init_kwargs(self, **kwargs): for key, value in list(kwargs.items()): try: setattr(self, key, value) except Exception as ex: raise ex.__class__('Failed on kwargs, class="%s" key="%s": %s' % (self.__class__.__name__, key, ex)) %} """) extend_string=""" %%feature("shadow") %s::%s() { def __init__(self, **kwargs): _Box2D.%s_swiginit(self,_Box2D.new_%s()) _init_kwargs(self, **kwargs) } """ director_string=""" %%feature("shadow") %s::%s() { def __init__(self, **kwargs): if self.__class__ == %s: _self = None else: _self = self _Box2D.%s_swiginit(self,_Box2D.new_%s(_self, )) _init_kwargs(self, **kwargs) } """ all_classes.remove('b2World') director_classes = ['b2ContactFilter', 'b2ContactListener', 'b2QueryCallback', 'b2DebugDraw', 'b2DestructionListener' ] abstract_classes = ['b2Joint', 'b2Shape', 'b2RayCastCallback', 'b2Contact'] for c in abstract_classes: # print(director_string % tuple([c]*4)) all_classes.remove(c) for c in director_classes: print(director_string % tuple([c]*5)) all_classes.remove(c) for c in all_classes: print(extend_string % tuple([c]*4)) pybox2d-2.3.2/devel/release.cmd000066400000000000000000000005441276457661000163320ustar00rootroot00000000000000set HOME=C:\Users\Ken\ set NAME="Ken Lauer" cd .. del /s /f /q build C:\Python27\python.exe setup.py bdist_egg upload --identity=%NAME% --sign --quiet C:\Python27\python.exe setup.py bdist_wininst --target-version=2.7 register upload --identity=%NAME% --sign --quiet C:\Python27\python.exe setup.py sdist upload --identity=%NAME% --sign cd devel pybox2d-2.3.2/devel/test.py000066400000000000000000000044571276457661000155650ustar00rootroot00000000000000classname = "b2DebugDraw" gets = "GetFlags SetFlags ClearFlags AppendFlags".split(" ") sets = "".split(" ") kwargs = True # remove duplicates gets = list(set(gets)) sets = list(set(sets)) renames = ["%%rename(__%s) %s::%s;" % (s, classname, s) for s in gets+sets if s not in ('GetAnchorA', 'GetAnchorB', '')] gets_mod=[] for s in gets: if s[:3]=="Get": gets_mod.append(s[3:]) elif s[:2]=="Is": gets_mod.append(s[2:]) else: gets_mod.append(s) sets_mod=[] for s in sets: if s[:3]=="Set": sets_mod.append(s[3:]) else: sets_mod.append(s) done = [] getter_setter = [] getter = [] for i, s in enumerate(gets_mod): if s in sets_mod: orig_set=sets[ sets_mod.index(s) ] orig_get = gets[i] getter_setter.append( (s, orig_get, orig_set) ) sets[sets_mod.index(s)] = None else: getter.append( (s, gets[i]) ) setter = [s for s in sets if s is not None] if kwargs: print ''' /**** %s ****/ %%extend %s { public: %%pythoncode %%{ def __init__(self, **kwargs): """__init__(self, **kwargs) -> %s """ _Box2D.%s_swiginit(self,_Box2D.new_%s()) for key, value in kwargs.items(): setattr(self, key, value) # Read-write properties ''' % tuple([classname[2:]] + [classname]*4) else: print ''' /**** %s ****/ %%extend %s { public: %%pythoncode %%{ # Read-write properties ''' % (classname[2:], classname) for name, g, s in getter_setter: newname= name[0].lower() + name[1:] print " %s = property(__%s, __%s)" % (newname, g, s) print " # Read-only" for name, g in getter: newname= name[0].lower() + name[1:] if newname in ('anchorA', 'anchorB'): print " %s = property(lambda self: self._b2Joint__%s(), None)" % (newname, name) else: print " %s = property(__%s, None)" % (newname, g) print " # Write-only" for s in setter: if not s: continue if s[:3]=='Set': name = s[3:] else: name = s newname= name[0].lower() + name[1:] print " %s = property(None, __%s)" % (newname, s) print """ %} } """ print " ", print "\n ".join(renames) pybox2d-2.3.2/devel/windows_release.py000066400000000000000000000033421276457661000177700ustar00rootroot00000000000000import os for platform in ['win32', 'win-amd64']: versions=['2.5', '2.6', '2.7', '3.0', '3.1', '3.2'] def get_path(platform, version): if platform=='win32': version_path='' else: version_path='-x64' return r'c:\python%s%s\python.exe'%(version.replace('.', ''), version_path) interpreters=[get_path(platform, version) for version in versions] lib_paths=[r'build\lib.%s-%s' % (platform, version) for version in versions] print '@echo off' print 'echo ---Start--- > test_results.txt' print 'echo ---Start--- > build_results.txt' do_stuff=''' echo * %(version)s %(platform)s echo -------- %(version)s %(platform)s -------- >> build_results.txt echo -------- %(version)s %(platform)s -------- >> test_results.txt %(interpreter)s setup.py clean -a >> build_results.txt 2>&1 %(interpreter)s setup.py build --force >> build_results.txt 2>&1 type Box2D\pybox2d_license_header.txt > Box2D_.py type %(lib_path)s\Box2D\Box2D.py >> Box2D_.py move /y Box2D_.py %(lib_path)s\Box2D\Box2D.py %(interpreter)s setup.py develop >> build_results.txt 2>&1 %(interpreter)s setup.py test >> test_results.txt 2>&1 %(interpreter)s setup.py bdist_wininst -t"pybox2d" -dinstaller >> build_results.txt 2>&1 %(interpreter)s setup.py bdist_egg >> build_results.txt 2>&1 ''' distutils_cfg='''[build] compiler=mingw32''' for version, interpreter, lib_path in zip(versions, interpreters, lib_paths): python_path=os.path.split(interpreter)[0] if version < '2.6': cfg_file=r'%s\lib\distutils\distutils.cfg' % python_path try: open(cfg_file, 'w').write(distutils_cfg) except: pass print do_stuff % locals() pybox2d-2.3.2/doc_release.cmd000066400000000000000000000000271276457661000160540ustar00rootroot00000000000000cd doc @call release pybox2d-2.3.2/environ-26.cmd000066400000000000000000000006541276457661000155220ustar00rootroot00000000000000@echo off set LC_ALL=en_US set EDITOR=c:\vim72\vim.exe set PYTHON_PATH=C:\python26\ set SWIG_PATH=C:\swigwin-1.3.40\ set PATH=%PATH%;%PYTHON_PATH%;%SWIG_PATH% echo Using Python in %PYTHON_PATH% echo Checking version... echo --- python.exe -V echo --- echo Using SWIG in %SWIG_PATH% echo Checking version... echo --- swig.exe -version echo --- echo Type 'setup.py build', and then 'setup.py install' to install. pybox2d-2.3.2/examples/000077500000000000000000000000001276457661000147415ustar00rootroot00000000000000pybox2d-2.3.2/examples/__init__.py000066400000000000000000000000001276457661000170400ustar00rootroot00000000000000pybox2d-2.3.2/examples/apply_force.py000066400000000000000000000071351276457661000176240ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from math import sqrt from Box2D import (b2FixtureDef, b2PolygonShape, b2Transform, b2Mul, b2_pi) class ApplyForce (Framework): name = "ApplyForce" description = "Use w, a, and d to control the ship." def __init__(self): super(ApplyForce, self).__init__() self.world.gravity = (0.0, 0.0) # The boundaries ground = self.world.CreateBody(position=(0, 20)) ground.CreateEdgeChain( [(-20, -20), (-20, 20), (20, 20), (20, -20), (-20, -20)] ) # TODO: make note of transform.R.set() -> transform.angle = xf1 = b2Transform() xf1.angle = 0.3524 * b2_pi xf1.position = xf1.R * (1.0, 0.0) xf2 = b2Transform() xf2.angle = -0.3524 * b2_pi xf2.position = xf2.R * (-1.0, 0.0) self.body = self.world.CreateDynamicBody( position=(0, 2), angle=b2_pi, angularDamping=5, linearDamping=0.1, shapes=[b2PolygonShape(vertices=[xf1 * (-1, 0), xf1 * (1, 0), xf1 * (0, .5)]), b2PolygonShape(vertices=[xf2 * (-1, 0), xf2 * (1, 0), xf2 * (0, .5)])], shapeFixture=b2FixtureDef(density=2.0), ) gravity = 10.0 fixtures = b2FixtureDef(shape=b2PolygonShape(box=(0.5, 0.5)), density=1, friction=0.3) for i in range(10): body = self.world.CreateDynamicBody( position=(0, 5 + 1.54 * i), fixtures=fixtures) # For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m) r = sqrt(2.0 * body.inertia / body.mass) self.world.CreateFrictionJoint( bodyA=ground, bodyB=body, localAnchorA=(0, 0), localAnchorB=(0, 0), collideConnected=True, maxForce=body.mass * gravity, maxTorque=body.mass * r * gravity ) def Keyboard(self, key): if not self.body: return if key == Keys.K_w: f = self.body.GetWorldVector(localVector=(0.0, -200.0)) p = self.body.GetWorldPoint(localPoint=(0.0, 2.0)) self.body.ApplyForce(f, p, True) elif key == Keys.K_a: self.body.ApplyTorque(50.0, True) elif key == Keys.K_d: self.body.ApplyTorque(-50.0, True) if __name__ == "__main__": main(ApplyForce) pybox2d-2.3.2/examples/backends/000077500000000000000000000000001276457661000165135ustar00rootroot00000000000000pybox2d-2.3.2/examples/backends/__init__.py000066400000000000000000000000001276457661000206120ustar00rootroot00000000000000pybox2d-2.3.2/examples/backends/opencv_draw.py000066400000000000000000000125121276457661000213750ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Python version Copyright (c) 2015 John Stowers # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. import cv2 import numpy as np from Box2D import (b2Color, b2DistanceJoint, b2MouseJoint, b2PulleyJoint) from Box2D.b2 import (staticBody, dynamicBody, kinematicBody, polygonShape, circleShape, loopShape, edgeShape) def cvcolor(color): return int(255.0 * color[2]), int(255.0 * color[1]), int(255.0 * color[0]) def cvcoord(pos): return tuple(map(int, pos)) class OpencvDrawFuncs(object): def __init__(self, w, h, ppm, fill_polygon=True, flip_y=True): self._w = w self._h = h self._ppm = ppm self._colors = { staticBody: (255, 255, 255), dynamicBody: (127, 127, 127), kinematicBody: (127, 127, 230), } self._fill_polygon = fill_polygon self._flip_y = flip_y self.screen = np.zeros((self._h, self._w, 3), np.uint8) def install(self): polygonShape.draw = self._draw_polygon circleShape.draw = self._draw_circle loopShape.draw = self._draw_loop edgeShape.draw = self._draw_edge def draw_world(self, world): for body in world.bodies: for fixture in body.fixtures: fixture.shape.draw(body, fixture) for joint in world.joints: self._draw_joint(joint) def clear_screen(self, screen=None): if screen is None: self.screen.fill(0) else: self.screen = screen def _fix_vertices(self, vertices): if self._flip_y: return [(v[0], self._h - v[1]) for v in vertices] else: return [(v[0], v[1]) for v in vertices] def _draw_joint(self, joint): bodyA, bodyB = joint.bodyA, joint.bodyB xf1, xf2 = bodyA.transform, bodyB.transform x1, x2 = xf1.position, xf2.position p1, p2 = joint.anchorA, joint.anchorB color = b2Color(0.5, 0.8, 0.8) x1, x2, p1, p2 = self._fix_vertices((x1 * self._ppm, x2 * self._ppm, p1 * self._ppm, p2 * self._ppm)) if isinstance(joint, b2DistanceJoint): cv2.line(self.screen, cvcoord(p1), cvcoord(p2), cvcolor(color), 1) elif isinstance(joint, b2PulleyJoint): s1, s2 = joint.groundAnchorA, joint.groundAnchorB s1, s2 = self._fix_vertices((s1 * self._ppm, s2 * self._ppm)) cv2.line(self.screen, cvcoord(s1), cvcoord(p1), cvcolor(color), 1) cv2.line(self.screen, cvcoord(s2), cvcoord(p2), cvcolor(color), 1) cv2.line(self.screen, cvcoord(s1), cvcoord(s2), cvcolor(color), 1) elif isinstance(joint, b2MouseJoint): pass # don't draw it here else: cv2.line(self.screen, cvcoord(x1), cvcoord(p1), cvcolor(color), 1) cv2.line(self.screen, cvcoord(p1), cvcoord(p2), cvcolor(color), 1) cv2.line(self.screen, cvcoord(x2), cvcoord(p2), cvcolor(color), 1) def _draw_polygon(self, body, fixture): polygon = fixture.shape transform = body.transform vertices = self._fix_vertices([transform * v * self._ppm for v in polygon.vertices]) pts = np.array(vertices, np.int32) pts = pts.reshape((-1, 1, 2)) cv2.polylines(self.screen, [pts], True, self._colors[body.type]) if self._fill_polygon: lightc = np.array(self._colors[body.type], dtype=int) * 0.5 cv2.fillPoly(self.screen, [pts], lightc) def _draw_circle(self, body, fixture): circle = fixture.shape position = self._fix_vertices( [body.transform * circle.pos * self._ppm])[0] cv2.circle(self.screen, cvcoord(position), int( circle.radius * self._ppm), self._colors[body.type], 1) def _draw_edge(self, body, fixture): edge = fixture.shape v = [body.transform * edge.vertex1 * self._ppm, body.transform * edge.vertex2 * self._ppm] vertices = self._fix_vertices(v) cv2.line(self.screen, cvcoord(vertices[0]), cvcoord(vertices[1]), self._colors[body.type], 1) def _draw_loop(self, body, fixture): loop = fixture.shape transform = body.transform vertices = self._fix_vertices([transform * v * self._ppm for v in loop.vertices]) v1 = vertices[-1] for v2 in vertices: cv2.line(self.screen, cvcoord(v1), cvcoord(v2), self._colors[body.type], 1) v1 = v2 pybox2d-2.3.2/examples/backends/opencv_framework.py000066400000000000000000000267351276457661000224510ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2015 John Stowers # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. """ Global Keys: Space - shoot projectile Z/X - zoom Escape - quit Other keys can be set by the individual test. Mouse: Left click - select/drag body (creates mouse joint) """ import string import time import cv2 import numpy as np import framework from framework import FrameworkBase, fwSettings from Box2D import b2DrawExtended, b2Vec2 from opencv_draw import cvcolor, cvcoord class OpencvDraw(framework.b2DrawExtended): """ This debug draw class accepts callbacks from Box2D (which specifies what to draw) and handles all of the rendering. If you are writing your own game, you likely will not want to use debug drawing. Debug drawing, as its name implies, is for debugging. """ surface = None axisScale = 10.0 def __init__(self, **kwargs): b2DrawExtended.__init__(self, **kwargs) self.flipX = False self.flipY = True self.convertVertices = True def StartDraw(self): self.zoom = self.test.viewZoom self.center = self.test.viewCenter self.offset = self.test.viewOffset self.screenSize = self.test.screenSize def EndDraw(self): pass def DrawPoint(self, p, size, color): """ Draw a single point at point p given a pixel size and color. """ self.DrawCircle(p, size / self.zoom, color, drawwidth=0) def DrawAABB(self, aabb, color): """ Draw a wireframe around the AABB with the given color. """ points = [(aabb.lowerBound.x, aabb.lowerBound.y), (aabb.upperBound.x, aabb.lowerBound.y), (aabb.upperBound.x, aabb.upperBound.y), (aabb.lowerBound.x, aabb.upperBound.y)] pts = np.array(points, np.int32) pts = pts.reshape((-1, 1, 2)) cv2.polylines(self.surface, [pts], True, cvcolor(color)) def DrawSegment(self, p1, p2, color): """ Draw the line segment from p1-p2 with the specified color. """ cv2.line(self.surface, cvcoord(p1), cvcoord(p2), cvcolor(color), 1) def DrawTransform(self, xf): """ Draw the transform xf on the screen """ p1 = xf.position p2 = self.to_screen(p1 + self.axisScale * xf.R.x_axis) p3 = self.to_screen(p1 + self.axisScale * xf.R.y_axis) p1 = self.to_screen(p1) cv2.line(self.surface, cvcoord(p1), cvcoord(p2), (0, 0, 255), 1) cv2.line(self.surface, cvcoord(p1), cvcoord(p3), (0, 255, 0), 1) def DrawCircle(self, center, radius, color, drawwidth=1): """ Draw a wireframe circle given the center, radius, axis of orientation and color. """ radius *= self.zoom if radius < 1: radius = 1 else: radius = int(radius) cv2.circle(self.surface, cvcoord(center), radius, cvcolor(color), drawwidth) def DrawSolidCircle(self, center, radius, axis, color): """ Draw a solid circle given the center, radius, axis of orientation and color. """ radius *= self.zoom if radius < 1: radius = 1 else: radius = int(radius) FILL = False cv2.circle(self.surface, cvcoord(center), radius, cvcolor(color), -1 if FILL else 1) cv2.line(self.surface, cvcoord(center), cvcoord((center[0] - radius * axis[0], center[1] + radius * axis[1])), (0, 0, 255), 1) def DrawPolygon(self, vertices, color): """ Draw a wireframe polygon given the screen vertices with the specified color. """ if not vertices: return if len(vertices) == 2: cv2.line(self.surface, cvcoord(vertices[0]), cvcoord( vertices[1]), cvcolor(color), 1) else: pts = np.array(vertices, np.int32) pts = pts.reshape((-1, 1, 2)) cv2.polylines(self.surface, [pts], True, cvcolor(color)) def DrawSolidPolygon(self, vertices, color): """ Draw a filled polygon given the screen vertices with the specified color. """ FILL = False if not FILL: self.DrawPolygon(vertices, color) return if not vertices: return if len(vertices) == 2: cv2.line(self.surface, cvcoord(vertices[0]), cvcoord( vertices[1]), cvcolor(color), 1) else: pts = np.array(vertices, np.int32) pts = pts.reshape((-1, 1, 2)) cv2.fillPoly(self.surface, [pts], cvcolor(color)) # Only support ascii keys # The following import is only needed to do the initial loading and # overwrite the Keys class. class OpencvKeysType(type): def __getattr__(cls, key): return getattr(cls, key, None) class OpencvKeys: __metaclass__ = OpencvKeysType for key in string.ascii_lowercase + string.digits: setattr(OpencvKeys, 'K_%c' % key, ord(key)) framework.Keys = OpencvKeys class OpencvFramework(FrameworkBase): def __init__(self, w=640, h=480, resizable=False): super(OpencvFramework, self).__init__() if fwSettings.onlyInit: # testing mode doesn't initialize opencv return self._viewZoom = 10.0 self._viewCenter = None self._viewOffset = None self.screenSize = None self.fps = 0 self.screen = np.zeros((h, w, 3), np.uint8) if resizable: cv2.namedWindow(self.name, getattr(cv2, 'WINDOW_NORMAL', 0)) cv2.resizeWindow(self.name, w, h) else: cv2.namedWindow(self.name, getattr(cv2, 'WINDOW_AUTOSIZE', 1)) cv2.setMouseCallback(self.name, self._on_mouse) self._t0 = time.time() self.textLine = 30 self._font_name = cv2.FONT_HERSHEY_SIMPLEX self._font_scale = 0.5 self._font_thickness = 1 (_, self._font_h), _ = cv2.getTextSize("X", self._font_name, self._font_scale, self._font_thickness) self.screenSize = b2Vec2(w, h) self.renderer = OpencvDraw(surface=self.screen, test=self) self.world.renderer = self.renderer self.viewCenter = (0, 20.0) self.groundbody = self.world.CreateBody() # mouse callback function def _on_mouse(self, event, x, y, flags, param): p = self.ConvertScreenToWorld(x, y) if event == cv2.EVENT_LBUTTONDOWN: self.MouseDown(p) if event == cv2.EVENT_LBUTTONUP: self.MouseUp(p) elif event == cv2.EVENT_MOUSEMOVE: self.MouseMove(p) def setCenter(self, value): """ Updates the view offset based on the center of the screen. Tells the debug draw to update its values also. """ self._viewCenter = b2Vec2(*value) self._viewCenter *= self._viewZoom self._viewOffset = self._viewCenter - self.screenSize / 2 def setZoom(self, zoom): self._viewZoom = zoom viewZoom = property(lambda self: self._viewZoom, setZoom, doc='Zoom factor for the display') viewCenter = property(lambda self: self._viewCenter / self._viewZoom, setCenter, doc='Screen center in camera coordinates') viewOffset = property(lambda self: self._viewOffset, doc='The offset of the top-left corner of the screen') def run(self): """ Main loop. Continues to run while checkEvents indicates the user has requested to quit. Updates the screen and tells the GUI to paint itself. """ while True: self._t1 = time.time() dt = 1.0 / self.settings.hz key = 0xFF & cv2.waitKey(int(dt * 1000.0)) if key == 27: break elif key != 255: if key == 32: # Space self.LaunchRandomBomb() elif key == 81: # Left self.viewCenter -= (0.5, 0) elif key == 83: # Right self.viewCenter += (0.5, 0) elif key == 82: # Up self.viewCenter += (0, 0.5) elif key == 84: # Down self.viewCenter -= (0, 0.5) elif key == 80: # Home self.viewZoom = 1.0 self.viewCenter = (0.0, 20.0) elif key == ord('z'): # Zoom in self.viewZoom = min(1.1 * self.viewZoom, 50.0) elif key == ord('x'): # Zoom out self.viewZoom = max(0.9 * self.viewZoom, 0.02) else: self.Keyboard(key) self.screen.fill(0) self.SimulationLoop() cv2.imshow(self.name, self.screen) dt = self._t1 - self._t0 self._t0 = self._t1 self.fps = 1 / dt self.world.contactListener = None self.world.destructionListener = None self.world.renderer = None def ConvertScreenToWorld(self, x, y): x = (x + self.viewOffset.x) / self.viewZoom y = ((self.screenSize.y - y + self.viewOffset.y) / self.viewZoom) return b2Vec2(x, y) def DrawStringAt(self, x, y, str, color=(229, 153, 153, 255)): """ Draw some text, str, at screen coordinates (x, y). """ color = (color[2], color[1], color[0]) cv2.putText(self.screen, str, (x, y), self._font_name, self._font_scale, color, self._font_thickness) def Print(self, str, color=(229, 153, 153, 255)): """ Draw some text at the top status lines and advance to the next line. """ color = (color[2], color[1], color[0]) cv2.putText(self.screen, str, (5, self.textLine), self._font_name, self._font_scale, color, self._font_thickness) self.textLine += self._font_h + 2 def Keyboard(self, key): """ Callback indicating 'key' has been pressed down. The keys are mapped after pygame's style. from framework import Keys if key == Keys.K_z: ... """ pass def KeyboardUp(self, key): """ Callback indicating 'key' has been released. See Keyboard() for key information """ pass pybox2d-2.3.2/examples/backends/pygame_framework.py000066400000000000000000000377451276457661000224440ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. """ Global Keys: F1 - toggle menu (can greatly improve fps) Space - shoot projectile Z/X - zoom Escape - quit Other keys can be set by the individual test. Mouse: Left click - select/drag body (creates mouse joint) Right click - pan Shift+Left - drag to create a directed projectile Scroll - zoom """ from __future__ import (print_function, absolute_import, division) import sys import warnings try: import pygame_sdl2 except ImportError: if sys.platform in ('darwin', ): warnings.warn('OSX has major issues with pygame/SDL 1.2 when used ' 'inside a virtualenv. If this affects you, try ' 'installing the updated pygame_sdl2 library.') else: # pygame_sdl2 is backward-compatible with pygame: pygame_sdl2.import_as_pygame() import pygame from pygame.locals import (QUIT, KEYDOWN, KEYUP, MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION, KMOD_LSHIFT) from ..framework import (FrameworkBase, Keys) from ..settings import fwSettings from Box2D import (b2DrawExtended, b2Vec2) try: from .pygame_gui import (fwGUI, gui) GUIEnabled = True except Exception as ex: print('Unable to load PGU; menu disabled.') print('(%s) %s' % (ex.__class__.__name__, ex)) GUIEnabled = False class PygameDraw(b2DrawExtended): """ This debug draw class accepts callbacks from Box2D (which specifies what to draw) and handles all of the rendering. If you are writing your own game, you likely will not want to use debug drawing. Debug drawing, as its name implies, is for debugging. """ surface = None axisScale = 10.0 def __init__(self, test=None, **kwargs): b2DrawExtended.__init__(self, **kwargs) self.flipX = False self.flipY = True self.convertVertices = True self.test = test def StartDraw(self): self.zoom = self.test.viewZoom self.center = self.test.viewCenter self.offset = self.test.viewOffset self.screenSize = self.test.screenSize def EndDraw(self): pass def DrawPoint(self, p, size, color): """ Draw a single point at point p given a pixel size and color. """ self.DrawCircle(p, size / self.zoom, color, drawwidth=0) def DrawAABB(self, aabb, color): """ Draw a wireframe around the AABB with the given color. """ points = [(aabb.lowerBound.x, aabb.lowerBound.y), (aabb.upperBound.x, aabb.lowerBound.y), (aabb.upperBound.x, aabb.upperBound.y), (aabb.lowerBound.x, aabb.upperBound.y)] pygame.draw.aalines(self.surface, color, True, points) def DrawSegment(self, p1, p2, color): """ Draw the line segment from p1-p2 with the specified color. """ pygame.draw.aaline(self.surface, color.bytes, p1, p2) def DrawTransform(self, xf): """ Draw the transform xf on the screen """ p1 = xf.position p2 = self.to_screen(p1 + self.axisScale * xf.R.x_axis) p3 = self.to_screen(p1 + self.axisScale * xf.R.y_axis) p1 = self.to_screen(p1) pygame.draw.aaline(self.surface, (255, 0, 0), p1, p2) pygame.draw.aaline(self.surface, (0, 255, 0), p1, p3) def DrawCircle(self, center, radius, color, drawwidth=1): """ Draw a wireframe circle given the center, radius, axis of orientation and color. """ radius *= self.zoom if radius < 1: radius = 1 else: radius = int(radius) pygame.draw.circle(self.surface, color.bytes, center, radius, drawwidth) def DrawSolidCircle(self, center, radius, axis, color): """ Draw a solid circle given the center, radius, axis of orientation and color. """ radius *= self.zoom if radius < 1: radius = 1 else: radius = int(radius) pygame.draw.circle(self.surface, (color / 2).bytes + [127], center, radius, 0) pygame.draw.circle(self.surface, color.bytes, center, radius, 1) pygame.draw.aaline(self.surface, (255, 0, 0), center, (center[0] - radius * axis[0], center[1] + radius * axis[1])) def DrawPolygon(self, vertices, color): """ Draw a wireframe polygon given the screen vertices with the specified color. """ if not vertices: return if len(vertices) == 2: pygame.draw.aaline(self.surface, color.bytes, vertices[0], vertices) else: pygame.draw.polygon(self.surface, color.bytes, vertices, 1) def DrawSolidPolygon(self, vertices, color): """ Draw a filled polygon given the screen vertices with the specified color. """ if not vertices: return if len(vertices) == 2: pygame.draw.aaline(self.surface, color.bytes, vertices[0], vertices[1]) else: pygame.draw.polygon( self.surface, (color / 2).bytes + [127], vertices, 0) pygame.draw.polygon(self.surface, color.bytes, vertices, 1) # the to_screen conversions are done in C with b2DrawExtended, leading to # an increase in fps. # You can also use the base b2Draw and implement these yourself, as the # b2DrawExtended is implemented: # def to_screen(self, point): # """ # Convert from world to screen coordinates. # In the class instance, we store a zoom factor, an offset indicating where # the view extents start at, and the screen size (in pixels). # """ # x=(point.x * self.zoom)-self.offset.x # if self.flipX: # x = self.screenSize.x - x # y=(point.y * self.zoom)-self.offset.y # if self.flipY: # y = self.screenSize.y-y # return (x, y) class PygameFramework(FrameworkBase): TEXTLINE_START = 30 def setup_keys(self): keys = [s for s in dir(pygame.locals) if s.startswith('K_')] for key in keys: value = getattr(pygame.locals, key) setattr(Keys, key, value) def __reset(self): # Screen/rendering-related self._viewZoom = 10.0 self._viewCenter = None self._viewOffset = None self.screenSize = None self.rMouseDown = False self.textLine = 30 self.font = None self.fps = 0 # GUI-related (PGU) self.gui_app = None self.gui_table = None self.setup_keys() def __init__(self): super(PygameFramework, self).__init__() self.__reset() if fwSettings.onlyInit: # testing mode doesn't initialize pygame return print('Initializing pygame framework...') # Pygame Initialization pygame.init() caption = "Python Box2D Testbed - " + self.name pygame.display.set_caption(caption) # Screen and debug draw self.screen = pygame.display.set_mode((640, 480)) self.screenSize = b2Vec2(*self.screen.get_size()) self.renderer = PygameDraw(surface=self.screen, test=self) self.world.renderer = self.renderer try: self.font = pygame.font.Font(None, 15) except IOError: try: self.font = pygame.font.Font("freesansbold.ttf", 15) except IOError: print("Unable to load default font or 'freesansbold.ttf'") print("Disabling text drawing.") self.Print = lambda *args: 0 self.DrawStringAt = lambda *args: 0 # GUI Initialization if GUIEnabled: self.gui_app = gui.App() self.gui_table = fwGUI(self.settings) container = gui.Container(align=1, valign=-1) container.add(self.gui_table, 0, 0) self.gui_app.init(container) self.viewCenter = (0, 20.0) self.groundbody = self.world.CreateBody() def setCenter(self, value): """ Updates the view offset based on the center of the screen. Tells the debug draw to update its values also. """ self._viewCenter = b2Vec2(*value) self._viewCenter *= self._viewZoom self._viewOffset = self._viewCenter - self.screenSize / 2 def setZoom(self, zoom): self._viewZoom = zoom viewZoom = property(lambda self: self._viewZoom, setZoom, doc='Zoom factor for the display') viewCenter = property(lambda self: self._viewCenter / self._viewZoom, setCenter, doc='Screen center in camera coordinates') viewOffset = property(lambda self: self._viewOffset, doc='The offset of the top-left corner of the screen') def checkEvents(self): """ Check for pygame events (mainly keyboard/mouse events). Passes the events onto the GUI also. """ for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYDOWN and event.key == Keys.K_ESCAPE): return False elif event.type == KEYDOWN: self._Keyboard_Event(event.key, down=True) elif event.type == KEYUP: self._Keyboard_Event(event.key, down=False) elif event.type == MOUSEBUTTONDOWN: p = self.ConvertScreenToWorld(*event.pos) if event.button == 1: # left mods = pygame.key.get_mods() if mods & KMOD_LSHIFT: self.ShiftMouseDown(p) else: self.MouseDown(p) elif event.button == 2: # middle pass elif event.button == 3: # right self.rMouseDown = True elif event.button == 4: self.viewZoom *= 1.1 elif event.button == 5: self.viewZoom /= 1.1 elif event.type == MOUSEBUTTONUP: p = self.ConvertScreenToWorld(*event.pos) if event.button == 3: # right self.rMouseDown = False else: self.MouseUp(p) elif event.type == MOUSEMOTION: p = self.ConvertScreenToWorld(*event.pos) self.MouseMove(p) if self.rMouseDown: self.viewCenter -= (event.rel[0] / 5.0, -event.rel[1] / 5.0) if GUIEnabled: self.gui_app.event(event) # Pass the event to the GUI return True def run(self): """ Main loop. Continues to run while checkEvents indicates the user has requested to quit. Updates the screen and tells the GUI to paint itself. """ # If any of the test constructors update the settings, reflect # those changes on the GUI before running if GUIEnabled: self.gui_table.updateGUI(self.settings) running = True clock = pygame.time.Clock() while running: running = self.checkEvents() self.screen.fill((0, 0, 0)) # Check keys that should be checked every loop (not only on initial # keydown) self.CheckKeys() # Run the simulation loop self.SimulationLoop() if GUIEnabled and self.settings.drawMenu: self.gui_app.paint(self.screen) pygame.display.flip() clock.tick(self.settings.hz) self.fps = clock.get_fps() self.world.contactListener = None self.world.destructionListener = None self.world.renderer = None def _Keyboard_Event(self, key, down=True): """ Internal keyboard event, don't override this. Checks for the initial keydown of the basic testbed keys. Passes the unused ones onto the test via the Keyboard() function. """ if down: if key == Keys.K_z: # Zoom in self.viewZoom = min(1.1 * self.viewZoom, 50.0) elif key == Keys.K_x: # Zoom out self.viewZoom = max(0.9 * self.viewZoom, 0.02) elif key == Keys.K_SPACE: # Launch a bomb self.LaunchRandomBomb() elif key == Keys.K_F1: # Toggle drawing the menu self.settings.drawMenu = not self.settings.drawMenu elif key == Keys.K_F2: # Do a single step self.settings.singleStep = True if GUIEnabled: self.gui_table.updateGUI(self.settings) else: # Inform the test of the key press self.Keyboard(key) else: self.KeyboardUp(key) def CheckKeys(self): """ Check the keys that are evaluated on every main loop iteration. I.e., they aren't just evaluated when first pressed down """ pygame.event.pump() self.keys = keys = pygame.key.get_pressed() if keys[Keys.K_LEFT]: self.viewCenter -= (0.5, 0) elif keys[Keys.K_RIGHT]: self.viewCenter += (0.5, 0) if keys[Keys.K_UP]: self.viewCenter += (0, 0.5) elif keys[Keys.K_DOWN]: self.viewCenter -= (0, 0.5) if keys[Keys.K_HOME]: self.viewZoom = 1.0 self.viewCenter = (0.0, 20.0) def Step(self, settings): if GUIEnabled: # Update the settings based on the GUI self.gui_table.updateSettings(self.settings) super(PygameFramework, self).Step(settings) if GUIEnabled: # In case during the step the settings changed, update the GUI reflecting # those settings. self.gui_table.updateGUI(self.settings) def ConvertScreenToWorld(self, x, y): return b2Vec2((x + self.viewOffset.x) / self.viewZoom, ((self.screenSize.y - y + self.viewOffset.y) / self.viewZoom)) def DrawStringAt(self, x, y, str, color=(229, 153, 153, 255)): """ Draw some text, str, at screen coordinates (x, y). """ self.screen.blit(self.font.render(str, True, color), (x, y)) def Print(self, str, color=(229, 153, 153, 255)): """ Draw some text at the top status lines and advance to the next line. """ self.screen.blit(self.font.render( str, True, color), (5, self.textLine)) self.textLine += 15 def Keyboard(self, key): """ Callback indicating 'key' has been pressed down. The keys are mapped after pygame's style. from framework import Keys if key == Keys.K_z: ... """ pass def KeyboardUp(self, key): """ Callback indicating 'key' has been released. See Keyboard() for key information """ pass pybox2d-2.3.2/examples/backends/pygame_gui.py000066400000000000000000000072571276457661000212260ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. try: from ..pgu import gui except: raise ImportError('Unable to load PGU') from ..settings import checkboxes from ..settings import sliders class fwGUI(gui.Table): """ Deals with the initialization and changing the settings based on the GUI controls. Callbacks are not used, but the checkboxes and sliders are polled by the main loop. """ form = None def __init__(self,settings, **params): # The framework GUI is just basically a HTML-like table # There are 2 columns right-aligned on the screen gui.Table.__init__(self,**params) self.form=gui.Form() fg = (255,255,255) # "Toggle menu" self.tr() self.td(gui.Label("F1: Toggle Menu",color=(255,0,0)),align=1,colspan=2) for slider in sliders: # "Slider title" self.tr() self.td(gui.Label(slider['text'],color=fg),align=1,colspan=2) # Create the slider self.tr() e = gui.HSlider(getattr(settings, slider['name']),slider['min'],slider['max'],size=20,width=100,height=16,name=slider['name']) self.td(e,colspan=2,align=1) # Add each of the checkboxes. for text, variable in checkboxes: self.tr() if variable == None: # Checkboxes that have no variable (i.e., None) are just labels. self.td(gui.Label(text, color=fg), align=1, colspan=2) else: # Add the label and then the switch/checkbox self.td(gui.Label(text, color=fg), align=1) self.td(gui.Switch(value=getattr(settings, variable),name=variable)) def updateGUI(self, settings): """ Change all of the GUI elements based on the current settings """ for text, variable in checkboxes: if not variable: continue if hasattr(settings, variable): self.form[variable].value = getattr(settings, variable) # Now do the sliders for slider in sliders: name=slider['name'] self.form[name].value=getattr(settings, name) def updateSettings(self, settings): """ Change all of the settings based on the current state of the GUI. """ for text, variable in checkboxes: if variable: setattr(settings, variable, self.form[variable].value) # Now do the sliders for slider in sliders: name=slider['name'] setattr(settings, name, int(self.form[name].value)) # If we're in single-step mode, update the GUI to reflect that. if settings.singleStep: settings.pause=True self.form['pause'].value = True self.form['singleStep'].value = False pybox2d-2.3.2/examples/backends/pyglet_framework.py000066400000000000000000000541511276457661000224540ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. """ Global Keys: Space - shoot projectile Z/X - zoom Escape - quit Other keys can be set by the individual test. Mouse: Left click - select/drag body (creates mouse joint) Right click - pan Shift+Left - drag to create a directional projectile Scroll - zoom You can easily add your own tests based on test_empty. """ import string import math import pyglet from pyglet import gl from Box2D import (b2Vec2, b2Draw) from ..framework import (FrameworkBase, Keys) from ..settings import fwSettings class grBlended (pyglet.graphics.Group): """ This pyglet rendering group enables blending. """ def set_state(self): gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) def unset_state(self): gl.glDisable(gl.GL_BLEND) class grPointSize (pyglet.graphics.Group): """ This pyglet rendering group sets a specific point size. """ def __init__(self, size=4.0): super(grPointSize, self).__init__() self.size = size def set_state(self): gl.glPointSize(self.size) def unset_state(self): gl.glPointSize(1.0) class grText(pyglet.graphics.Group): """ This pyglet rendering group sets the proper projection for displaying text when used. """ window = None def __init__(self, window=None): super(grText, self).__init__() self.window = window def set_state(self): gl.glMatrixMode(gl.GL_PROJECTION) gl.glPushMatrix() gl.glLoadIdentity() gl.gluOrtho2D(0, self.window.width, 0, self.window.height) gl.glMatrixMode(gl.GL_MODELVIEW) gl.glPushMatrix() gl.glLoadIdentity() def unset_state(self): gl.glPopMatrix() gl.glMatrixMode(gl.GL_PROJECTION) gl.glPopMatrix() gl.glMatrixMode(gl.GL_MODELVIEW) class PygletDraw(b2Draw): """ This debug draw class accepts callbacks from Box2D (which specifies what to draw) and handles all of the rendering. If you are writing your own game, you likely will not want to use debug drawing. Debug drawing, as its name implies, is for debugging. """ blended = grBlended() circle_segments = 16 surface = None circle_cache_tf = {} # triangle fan (inside) circle_cache_ll = {} # line loop (border) def __init__(self, test): super(PygletDraw, self).__init__() self.test = test def StartDraw(self): pass def EndDraw(self): pass def triangle_fan(self, vertices): """ in: vertices arranged for gl_triangle_fan ((x,y),(x,y)...) out: vertices arranged for gl_triangles (x,y,x,y,x,y...) """ out = [] for i in range(1, len(vertices) - 1): # 0,1,2 0,2,3 0,3,4 .. out.extend(vertices[0]) out.extend(vertices[i]) out.extend(vertices[i + 1]) return len(out) // 2, out def line_loop(self, vertices): """ in: vertices arranged for gl_line_loop ((x,y),(x,y)...) out: vertices arranged for gl_lines (x,y,x,y,x,y...) """ out = [] for i in range(len(vertices) - 1): # 0,1 1,2 2,3 ... len-1,len len,0 out.extend(vertices[i]) out.extend(vertices[i + 1]) out.extend(vertices[len(vertices) - 1]) out.extend(vertices[0]) return len(out) // 2, out def _getLLCircleVertices(self, radius, points): """ Get the line loop-style vertices for a given circle. Drawn as lines. "Line Loop" is used as that's how the C++ code draws the vertices, with lines going around the circumference of the circle (GL_LINE_LOOP). This returns 'points' amount of lines approximating the border of a circle. (x1, y1, x2, y2, x3, y3, ...) """ ret = [] step = 2 * math.pi / points n = 0 for i in range(points): ret.append((math.cos(n) * radius, math.sin(n) * radius)) n += step ret.append((math.cos(n) * radius, math.sin(n) * radius)) return ret def _getTFCircleVertices(self, radius, points): """ Get the triangle fan-style vertices for a given circle. Drawn as triangles. "Triangle Fan" is used as that's how the C++ code draws the vertices, with triangles originating at the center of the circle, extending around to approximate a filled circle (GL_TRIANGLE_FAN). This returns 'points' amount of lines approximating the circle. (a1, b1, c1, a2, b2, c2, ...) """ ret = [] step = 2 * math.pi / points n = 0 for i in range(points): ret.append((0.0, 0.0)) ret.append((math.cos(n) * radius, math.sin(n) * radius)) n += step ret.append((math.cos(n) * radius, math.sin(n) * radius)) return ret def getCircleVertices(self, center, radius, points): """ Returns the triangles that approximate the circle and the lines that border the circles edges, given (center, radius, points). Caches the calculated LL/TF vertices, but recalculates based on the center passed in. TODO: Currently, there's only one point amount, so the circle cache ignores it when storing. Could cause some confusion if you're using multiple point counts as only the first stored point-count for that radius will show up. TODO: What does the previous TODO mean? Returns: (tf_vertices, ll_vertices) """ if radius not in self.circle_cache_tf: self.circle_cache_tf[ radius] = self._getTFCircleVertices(radius, points) self.circle_cache_ll[ radius] = self._getLLCircleVertices(radius, points) ret_tf, ret_ll = [], [] for x, y in self.circle_cache_tf[radius]: ret_tf.extend((x + center[0], y + center[1])) for x, y in self.circle_cache_ll[radius]: ret_ll.extend((x + center[0], y + center[1])) return ret_tf, ret_ll def DrawCircle(self, center, radius, color): """ Draw an unfilled circle given center, radius and color. """ unused, ll_vertices = self.getCircleVertices( center, radius, self.circle_segments) ll_count = len(ll_vertices) // 2 self.batch.add(ll_count, gl.GL_LINES, None, ('v2f', ll_vertices), ('c4f', [color.r, color.g, color.b, 1.0] * ll_count)) def DrawSolidCircle(self, center, radius, axis, color): """ Draw an filled circle given center, radius, axis (of orientation) and color. """ tf_vertices, ll_vertices = self.getCircleVertices( center, radius, self.circle_segments) tf_count, ll_count = len(tf_vertices) // 2, len(ll_vertices) // 2 self.batch.add(tf_count, gl.GL_TRIANGLES, self.blended, ('v2f', tf_vertices), ('c4f', [0.5 * color.r, 0.5 * color.g, 0.5 * color.b, 0.5] * tf_count)) self.batch.add(ll_count, gl.GL_LINES, None, ('v2f', ll_vertices), ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count))) p = b2Vec2(center) + radius * b2Vec2(axis) self.batch.add(2, gl.GL_LINES, None, ('v2f', (center[0], center[1], p[0], p[1])), ('c3f', [1.0, 0.0, 0.0] * 2)) def DrawPolygon(self, vertices, color): """ Draw a wireframe polygon given the world vertices (tuples) with the specified color. """ if len(vertices) == 2: p1, p2 = vertices self.batch.add(2, gl.GL_LINES, None, ('v2f', (p1[0], p1[1], p2[0], p2[1])), ('c3f', [color.r, color.g, color.b] * 2)) else: ll_count, ll_vertices = self.line_loop(vertices) self.batch.add(ll_count, gl.GL_LINES, None, ('v2f', ll_vertices), ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count))) def DrawSolidPolygon(self, vertices, color): """ Draw a filled polygon given the world vertices (tuples) with the specified color. """ if len(vertices) == 2: p1, p2 = vertices self.batch.add(2, gl.GL_LINES, None, ('v2f', (p1[0], p1[1], p2[0], p2[1])), ('c3f', [color.r, color.g, color.b] * 2)) else: tf_count, tf_vertices = self.triangle_fan(vertices) if tf_count == 0: return self.batch.add(tf_count, gl.GL_TRIANGLES, self.blended, ('v2f', tf_vertices), ('c4f', [0.5 * color.r, 0.5 * color.g, 0.5 * color.b, 0.5] * (tf_count))) ll_count, ll_vertices = self.line_loop(vertices) self.batch.add(ll_count, gl.GL_LINES, None, ('v2f', ll_vertices), ('c4f', [color.r, color.g, color.b, 1.0] * ll_count)) def DrawSegment(self, p1, p2, color): """ Draw the line segment from p1-p2 with the specified color. """ self.batch.add(2, gl.GL_LINES, None, ('v2f', (p1[0], p1[1], p2[0], p2[1])), ('c3f', [color.r, color.g, color.b] * 2)) def DrawXForm(self, xf): """ Draw the transform xf on the screen """ p1 = xf.position k_axisScale = 0.4 p2 = p1 + k_axisScale * xf.R.x_axis p3 = p1 + k_axisScale * xf.R.y_axis self.batch.add(3, gl.GL_LINES, None, ('v2f', (p1[0], p1[1], p2[0], p2[ 1], p1[0], p1[1], p3[0], p3[1])), ('c3f', [1.0, 0.0, 0.0] * 2 + [0.0, 1.0, 0.0] * 2)) def DrawPoint(self, p, size, color): """ Draw a single point at point p given a point size and color. """ self.batch.add(1, gl.GL_POINTS, grPointSize(size), ('v2f', (p[0], p[1])), ('c3f', [color.r, color.g, color.b])) def DrawAABB(self, aabb, color): """ Draw a wireframe around the AABB with the given color. """ self.renderer.batch.add(8, gl.GL_LINES, None, ('v2f', (aabb.lowerBound.x, aabb.lowerBound.y, aabb.upperBound.x, aabb.lowerBound.y, aabb.upperBound.x, aabb.lowerBound.y, aabb.upperBound.x, aabb.upperBound.y, aabb.upperBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.lowerBound.y)), ('c3f', [color.r, color.g, color.b] * 8)) def to_screen(self, point): """ In here for compatibility with other frameworks. """ return tuple(point) class PygletWindow(pyglet.window.Window): def __init__(self, test): super(PygletWindow, self).__init__() self.test = test def on_close(self): """ Callback: user tried to close the window """ pyglet.clock.unschedule(self.test.SimulationLoop) super(PygletWindow, self).on_close() def on_show(self): """ Callback: the window was shown. """ self.test.updateProjection() def on_key_press(self, key, modifiers): self.test._Keyboard_Event(key, down=True) def on_key_release(self, key, modifiers): self.test._Keyboard_Event(key, down=False) def on_mouse_press(self, x, y, button, modifiers): p = self.test.ConvertScreenToWorld(x, y) self.test.mouseWorld = p if button == pyglet.window.mouse.LEFT: if modifiers & pyglet.window.key.MOD_SHIFT: self.test.ShiftMouseDown(p) else: self.test.MouseDown(p) elif button == pyglet.window.mouse.MIDDLE: pass def on_mouse_release(self, x, y, button, modifiers): """ Mouse up """ p = self.test.ConvertScreenToWorld(x, y) self.test.mouseWorld = p if button == pyglet.window.mouse.LEFT: self.test.MouseUp(p) def on_mouse_scroll(self, x, y, scroll_x, scroll_y): """ Mouse scrollwheel used """ if scroll_y < 0: self.test.viewZoom *= 1.1 elif scroll_y > 0: self.test.viewZoom /= 1.1 def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): """ Mouse moved while clicking """ p = self.test.ConvertScreenToWorld(x, y) self.test.mouseWorld = p self.test.MouseMove(p) if buttons & pyglet.window.mouse.RIGHT: self.test.viewCenter -= (float(dx) / 5, float(dy) / 5) class PygletFramework(FrameworkBase): def setup_keys(self): key = pyglet.window.key self.keys = key.KeyStateHandler() # Only basic keys are mapped for now: K_[a-z0-9], K_F[1-12] and # K_COMMA. if hasattr(string, 'ascii_uppercase'): uppercase = string.ascii_uppercase else: uppercase = string.uppercase for letter in uppercase: setattr(Keys, 'K_' + letter.lower(), getattr(key, letter)) for i in range(10): setattr(Keys, 'K_%d' % i, getattr(key, '_%d' % i)) for i in range(1, 13): setattr(Keys, 'K_F%d' % i, getattr(key, 'F%d' % i)) Keys.K_LEFT = key.LEFT Keys.K_RIGHT = key.RIGHT Keys.K_UP = key.UP Keys.K_DOWN = key.DOWN Keys.K_HOME = key.HOME Keys.K_PAGEUP = key.PAGEUP Keys.K_PAGEDOWN = key.PAGEDOWN Keys.K_COMMA = key.COMMA def __reset(self): # Screen/rendering-related self._viewZoom = 10.0 self._viewCenter = None self._viewOffset = None self.screenSize = None self.rMouseDown = False self.textLine = 30 self.font = None self.fps = 0 # Window-related self.fontname = "Arial" self.fontsize = 10 self.font = None self.textGroup = None # Screen-related self._viewZoom = 1.0 self._viewCenter = None self.screenSize = None self.textLine = 30 self.font = None self.fps = 0 self.setup_keys() def __init__(self): super(PygletFramework, self).__init__() self.__reset() if fwSettings.onlyInit: # testing mode doesn't initialize Pyglet return print('Initializing Pyglet framework...') self.window = PygletWindow(self) # Initialize the text display group self.textGroup = grText(self.window) # Load the font and record the screen dimensions self.font = pyglet.font.load(self.fontname, self.fontsize) self.screenSize = b2Vec2(self.window.width, self.window.height) self.renderer = PygletDraw(self) self.renderer.surface = self.window.screen self.world.renderer = self.renderer self._viewCenter = b2Vec2(0, 10.0) self.groundbody = self.world.CreateBody() def setCenter(self, value): """ Updates the view offset based on the center of the screen. Tells the debug draw to update its values also. """ self._viewCenter = b2Vec2(*value) self.updateProjection() def setZoom(self, zoom): self._viewZoom = zoom self.updateProjection() viewZoom = property(lambda self: self._viewZoom, setZoom, doc='Zoom factor for the display') viewCenter = property(lambda self: self._viewCenter, setCenter, doc='Screen center in camera coordinates') def updateProjection(self): """ Recalculates the necessary projection. """ gl.glViewport(0, 0, self.window.width, self.window.height) gl.glMatrixMode(gl.GL_PROJECTION) gl.glLoadIdentity() ratio = float(self.window.width) / self.window.height extents = b2Vec2(ratio * 25.0, 25.0) extents *= self._viewZoom lower = self._viewCenter - extents upper = self._viewCenter + extents # L/R/B/T gl.gluOrtho2D(lower.x, upper.x, lower.y, upper.y) gl.glMatrixMode(gl.GL_MODELVIEW) gl.glLoadIdentity() def run(self): """ Main loop. """ if self.settings.hz > 0.0: pyglet.clock.schedule_interval( self.SimulationLoop, 1.0 / self.settings.hz) # self.window.push_handlers(pyglet.window.event.WindowEventLogger()) # TODO: figure out why this is required self.window._enable_event_queue = False pyglet.app.run() self.world.contactListener = None self.world.destructionListener = None self.world.renderer = None def SimulationLoop(self, dt): """ The main simulation loop. Don't override this, override Step instead. And be sure to call super(classname, self).Step(settings) at the end of your Step function. """ # Check the input and clear the screen self.CheckKeys() self.window.clear() # Update the keyboard status self.window.push_handlers(self.keys) # Create a new batch for drawing self.renderer.batch = pyglet.graphics.Batch() # Reset the text position self.textLine = 15 # Draw the title of the test at the top self.Print(self.name) # Step the physics self.Step(self.settings) self.renderer.batch.draw() self.window.invalid = True self.fps = pyglet.clock.get_fps() def _Keyboard_Event(self, key, down=True): """ Internal keyboard event, don't override this. Checks for the initial keydown of the basic testbed keys. Passes the unused ones onto the test via the Keyboard() function. """ if down: if key == pyglet.window.key.ESCAPE: exit(0) elif key == pyglet.window.key.SPACE: # Launch a bomb self.LaunchRandomBomb() elif key == Keys.K_z: # Zoom in self.viewZoom = min(1.1 * self.viewZoom, 20.0) elif key == Keys.K_x: # Zoom out self.viewZoom = max(0.9 * self.viewZoom, 0.02) else: # Inform the test of the key press self.Keyboard(key) else: self.KeyboardUp(key) def CheckKeys(self): """ Check the keys that are evaluated on every main loop iteration. I.e., they aren't just evaluated when first pressed down """ keys = self.keys if keys[Keys.K_LEFT]: self.viewCenter -= (0.5, 0) elif keys[Keys.K_RIGHT]: self.viewCenter += (0.5, 0) if keys[Keys.K_UP]: self.viewCenter += (0, 0.5) elif keys[Keys.K_DOWN]: self.viewCenter -= (0, 0.5) if keys[Keys.K_HOME]: self.viewZoom = 1.0 self.viewCenter = (0.0, 20.0) # def Step(self, settings): # super(PygletFramework, self).Step(settings) def ConvertScreenToWorld(self, x, y): """ Takes screen (x, y) and returns world coordinate b2Vec2(x,y). """ u = float(x) / self.window.width v = float(y) / self.window.height ratio = float(self.window.width) / self.window.height extents = b2Vec2(ratio * 25.0, 25.0) extents *= self._viewZoom lower = self._viewCenter - extents upper = self._viewCenter + extents p = b2Vec2( (1.0 - u) * lower.x + u * upper.x, (1.0 - v) * lower.y + v * upper.y) return p def DrawStringAt(self, x, y, str, color=(229, 153, 153, 255)): """ Draw some text, str, at screen coordinates (x, y). """ pyglet.text.Label(str, font_name=self.fontname, font_size=self.fontsize, x=x, y=self.window.height - y, color=color, batch=self.renderer.batch, group=self.textGroup) def Print(self, str, color=(229, 153, 153, 255)): """ Draw some text, str, at screen coordinates (x, y). """ pyglet.text.Label(str, font_name=self.fontname, font_size=self.fontsize, x=5, y=self.window.height - self.textLine, color=color, batch=self.renderer.batch, group=self.textGroup) self.textLine += 15 def Keyboard(self, key): """ Callback indicating 'key' has been pressed down. """ pass def KeyboardUp(self, key): """ Callback indicating 'key' has been released. See Keyboard() for key information """ pass pybox2d-2.3.2/examples/backends/pyqt4_framework.py000066400000000000000000001004261276457661000222260ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. """ Global Keys: Space - shoot projectile Z/X - zoom Escape - quit Other keys can be set by the individual test. Mouse: Left click - select/drag body (creates mouse joint) Right click - get body/fixture information Shift+Left - drag to create a directed projectile Scroll - zoom """ import string import sys import re from PyQt4 import (QtGui, QtCore) from PyQt4.QtGui import (QTableWidgetItem, QColor) from PyQt4.QtCore import Qt from Box2D import (b2AABB, b2CircleShape, b2Color, b2DistanceJoint, b2EdgeShape, b2LoopShape, b2MouseJoint, b2Mul, b2PolygonShape, b2PulleyJoint, b2Vec2) from Box2D import (b2_pi, b2_staticBody, b2_kinematicBody) from ..framework import (fwQueryCallback, FrameworkBase, Keys) from .. import settings from .pyqt4_gui import Ui_MainWindow class Pyqt4Draw(object): """ This debug drawing class differs from the other frameworks. It provides an example of how to iterate through all the objects in the world and associate (in PyQt4's case) QGraphicsItems with them. While DrawPolygon and DrawSolidPolygon are not used for the core shapes in the world (DrawPolygonShape is), they are left in for compatibility with other frameworks and the tests. world_coordinate parameters are also left in for compatibility. Screen coordinates cannot be used, as PyQt4 does the scaling and rotating for us. If you utilize this framework and need to add more items to the QGraphicsScene for a single step, be sure to add them to the temp_items array to be deleted on the next draw. """ MAX_TIMES = 20 axisScale = 0.4 def __init__(self, test): self.test = test self.window = self.test.window self.scene = self.window.scene self.view = self.window.graphicsView self.item_cache = {} self.temp_items = [] self.status_font = QtGui.QFont("Times", 10, QtGui.QFont.Bold) self.font_spacing = QtGui.QFontMetrics(self.status_font).lineSpacing() self.draw_idx = 0 def StartDraw(self): for item in self.temp_items: self.scene.removeItem(item) self.temp_items = [] def EndDraw(self): pass def SetFlags(self, **kwargs): """ For compatibility with other debug drawing classes. """ pass def DrawStringAt(self, x, y, str, color=None): item = QtGui.QGraphicsSimpleTextItem(str) if color is None: color = (255, 255, 255, 255) brush = QtGui.QBrush(QColor(255, 255, 255, 255)) item.setFont(self.status_font) item.setBrush(brush) item.setPos(self.view.mapToScene(x, y)) item.scale(1. / self.test._viewZoom, -1. / self.test._viewZoom) self.temp_items.append(item) self.scene.addItem(item) def DrawPoint(self, p, size, color): """ Draw a single point at point p given a pixel size and color. """ self.DrawCircle(p, size / self.test.viewZoom, color, drawwidth=0) def DrawAABB(self, aabb, color): """ Draw a wireframe around the AABB with the given color. """ line1 = self.scene.addLine(aabb.lowerBound.x, aabb.lowerBound.y, aabb.upperBound.x, aabb.lowerBound.y, pen=QtGui.QPen(QColor(*color.bytes))) line2 = self.scene.addLine(aabb.upperBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.upperBound.y, pen=QtGui.QPen(QColor(*color.bytes))) self.temp_items.append(line1) self.temp_items.append(line2) def DrawSegment(self, p1, p2, color): """ Draw the line segment from p1-p2 with the specified color. """ line = self.scene.addLine(p1[0], p1[1], p2[0], p2[1], pen=QtGui.QPen(QColor(*color.bytes))) self.temp_items.append(line) def DrawTransform(self, xf): """ Draw the transform xf on the screen """ p1 = xf.position p2 = p1 + self.axisScale * xf.R.x_axis p3 = p1 + self.axisScale * xf.R.y_axis line1 = self.scene.addLine(p1[0], p1[1], p2[0], p2[1], pen=QtGui.QPen(QColor(255, 0, 0))) line2 = self.scene.addLine(p1[0], p1[1], p3[0], p3[1], pen=QtGui.QPen(QColor(0, 255, 0))) self.temp_items.append(line1) self.temp_items.append(line2) def DrawCircle(self, center, radius, color, drawwidth=1, shape=None): """ Draw a wireframe circle given the center, radius, axis of orientation and color. """ border_color = [c * 255 for c in color] + [255] pen = QtGui.QPen(QtGui.QColor(*border_color)) ellipse = self.scene.addEllipse(center[0] - radius, center[1] - radius, radius * 2, radius * 2, pen=pen) self.temp_items.append(ellipse) def DrawSolidCircle(self, center, radius, axis, color, shape=None): """ Draw a solid circle given the center, radius, axis of orientation and color. """ border_color = color.bytes + [255] inside_color = (color / 2).bytes + [127] brush = QtGui.QBrush(QtGui.QColor(*inside_color)) pen = QtGui.QPen(QtGui.QColor(*border_color)) ellipse = self.scene.addEllipse(center[0] - radius, center[1] - radius, radius * 2, radius * 2, brush=brush, pen=pen) line = self.scene.addLine(center[0], center[1], (center[0] - radius * axis[0]), (center[1] - radius * axis[1]), pen=QtGui.QPen(QColor(255, 0, 0))) self.temp_items.append(ellipse) self.temp_items.append(line) def DrawPolygon(self, vertices, color, shape=None): """ Draw a wireframe polygon given the world vertices vertices (tuples) with the specified color. """ poly = QtGui.QPolygonF() pen = QtGui.QPen(QtGui.QColor(*color.bytes)) for v in vertices: poly += QtCore.QPointF(*v) item = self.scene.addPolygon(poly, pen=pen) self.temp_items.append(item) def DrawSolidPolygon(self, vertices, color, shape=None): """ Draw a filled polygon given the world vertices vertices (tuples) with the specified color. """ poly = QtGui.QPolygonF() border_color = color.bytes + [255] inside_color = (color / 2).bytes + [127] brush = QtGui.QBrush(QtGui.QColor(*inside_color)) pen = QtGui.QPen(QtGui.QColor(*border_color)) for v in vertices: poly += QtCore.QPointF(*v) item = self.scene.addPolygon(poly, brush=brush, pen=pen) self.temp_items.append(item) def DrawCircleShape(self, shape, transform, color, temporary=False): center = b2Mul(transform, shape.pos) radius = shape.radius axis = transform.R.x_axis border_color = color.bytes + [255] inside_color = (color / 2).bytes + [127] brush = QtGui.QBrush(QtGui.QColor(*inside_color)) pen = QtGui.QPen(QtGui.QColor(*border_color)) ellipse = self.scene.addEllipse(-radius, -radius, radius * 2, radius * 2, brush=brush, pen=pen) line = self.scene.addLine(center[0], center[1], (center[0] - radius * axis[0]), (center[1] - radius * axis[1]), pen=QtGui.QPen(QColor(255, 0, 0))) ellipse.setPos(*center) ellipse.radius = radius if temporary: self.temp_items.append(ellipse) self.temp_items.append(line) else: self.item_cache[hash(shape)] = [ellipse, line] def DrawPolygonShape(self, shape, transform, color, temporary=False): poly = QtGui.QPolygonF() border_color = color.bytes + [255] inside_color = (color / 2).bytes + [127] brush = QtGui.QBrush(QtGui.QColor(*inside_color)) pen = QtGui.QPen(QtGui.QColor(*border_color)) for v in shape.vertices: poly += QtCore.QPointF(*v) item = self.scene.addPolygon(poly, brush=brush, pen=pen) item.setRotation(transform.angle * 180.0 / b2_pi) item.setPos(*transform.position) if temporary: self.temp_items.append(item) else: self.item_cache[hash(shape)] = [item] def _remove_from_cache(self, shape): items = self.item_cache[hash(shape)] del self.item_cache[hash(shape)] for item in items: self.scene.removeItem(item) def DrawShape(self, shape, transform, color, selected=False): """ Draw any type of shape """ cache_hit = False if hash(shape) in self.item_cache: cache_hit = True items = self.item_cache[hash(shape)] items[0].setRotation(transform.angle * 180.0 / b2_pi) if isinstance(shape, b2CircleShape): radius = shape.radius if items[0].radius == radius: center = b2Mul(transform, shape.pos) items[0].setPos(*center) line = items[1] axis = transform.R.x_axis line.setLine(center[0], center[1], (center[0] - radius * axis[0]), (center[1] - radius * axis[1])) else: self._remove_from_cache(shape) cache_hit = False else: items[0].setPos(*transform.position) if not selected or cache_hit: return if selected: color = b2Color(1, 1, 1) temporary = True else: temporary = False if isinstance(shape, b2PolygonShape): self.DrawPolygonShape(shape, transform, color, temporary) elif isinstance(shape, b2EdgeShape): v1 = b2Mul(transform, shape.vertex1) v2 = b2Mul(transform, shape.vertex2) self.DrawSegment(v1, v2, color) elif isinstance(shape, b2CircleShape): self.DrawCircleShape(shape, transform, color, temporary) elif isinstance(shape, b2LoopShape): vertices = shape.vertices v1 = b2Mul(transform, vertices[-1]) for v2 in vertices: v2 = b2Mul(transform, v2) self.DrawSegment(v1, v2, color) v1 = v2 def DrawJoint(self, joint): """ Draw any type of joint """ bodyA, bodyB = joint.bodyA, joint.bodyB xf1, xf2 = bodyA.transform, bodyB.transform x1, x2 = xf1.position, xf2.position p1, p2 = joint.anchorA, joint.anchorB color = b2Color(0.5, 0.8, 0.8) if isinstance(joint, b2DistanceJoint): self.DrawSegment(p1, p2, color) elif isinstance(joint, b2PulleyJoint): s1, s2 = joint.groundAnchorA, joint.groundAnchorB self.DrawSegment(s1, p1, color) self.DrawSegment(s2, p2, color) self.DrawSegment(s1, s2, color) elif isinstance(joint, b2MouseJoint): pass # don't draw it here else: self.DrawSegment(x1, p1, color) self.DrawSegment(p1, p2, color) self.DrawSegment(x2, p2, color) def ManualDraw(self): """ This implements code normally present in the C++ version, which calls the callbacks that you see in this class (DrawSegment, DrawSolidCircle, etc.). This is implemented in Python as an example of how to do it, and also a test. """ colors = { 'active': b2Color(0.5, 0.5, 0.3), 'static': b2Color(0.5, 0.9, 0.5), 'kinematic': b2Color(0.5, 0.5, 0.9), 'asleep': b2Color(0.6, 0.6, 0.6), 'default': b2Color(0.9, 0.7, 0.7), } settings = self.test.settings world = self.test.world if self.test.selected_shapebody: sel_shape, sel_body = self.test.selected_shapebody else: sel_shape = None if settings.drawShapes: for body in world.bodies: transform = body.transform for fixture in body.fixtures: shape = fixture.shape if not body.active: color = colors['active'] elif body.type == b2_staticBody: color = colors['static'] elif body.type == b2_kinematicBody: color = colors['kinematic'] elif not body.awake: color = colors['asleep'] else: color = colors['default'] self.DrawShape(fixture.shape, transform, color, (sel_shape == shape)) if settings.drawJoints: for joint in world.joints: self.DrawJoint(joint) # if settings.drawPairs # pass if settings.drawAABBs: color = b2Color(0.9, 0.3, 0.9) # cm = world.contactManager for body in world.bodies: if not body.active: continue transform = body.transform for fixture in body.fixtures: shape = fixture.shape for childIndex in range(shape.childCount): self.DrawAABB(shape.getAABB( transform, childIndex), color) def to_screen(self, point): """ In here for compatibility with other frameworks. """ return tuple(point) class GraphicsScene (QtGui.QGraphicsScene): def __init__(self, test, parent=None): super(GraphicsScene, self).__init__(parent) self.test = test def keyPressEvent(self, event): self.test._Keyboard_Event(event.key(), down=True) def keyReleaseEvent(self, event): self.test._Keyboard_Event(event.key(), down=False) def mousePressEvent(self, event): pos = self.test.ConvertScreenToWorld( event.scenePos().x(), event.scenePos().y()) if event.button() == Qt.RightButton: self.test.ShowProperties(pos) elif event.button() == Qt.LeftButton: if event.modifiers() == Qt.ShiftModifier: self.test.ShiftMouseDown(pos) else: self.test.MouseDown(pos) def mouseReleaseEvent(self, event): pos = event.scenePos().x(), event.scenePos().y() if event.button() == Qt.RightButton: self.test.MouseUp(pos) elif event.button() == Qt.LeftButton: self.test.MouseUp(pos) def mouseMoveEvent(self, event): pos = event.scenePos().x(), event.scenePos().y() self.test.MouseMove(self.test.ConvertScreenToWorld(*pos)) QtGui.QGraphicsScene.mouseMoveEvent(self, event) class MainWindow(QtGui.QMainWindow, Ui_MainWindow): def __init__(self, test, parent=None): QtGui.QMainWindow.__init__(self) self.setupUi(self) self.scene = GraphicsScene(test) self.test = test self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(0, 0, 0))) self.graphicsView.setScene(self.scene) self.graphicsView.scale(self.test.viewZoom, -self.test.viewZoom) self.reset_properties_list() self.restoreLayout() def increase_font_size(amount=1.0): self.setFontSize(app.font().pointSize() + amount) def decrease_font_size(amount=1.0): self.setFontSize(app.font().pointSize() - amount) self.mnuExit.triggered.connect(self.close) self.mnuIncreaseFontSize.triggered.connect(increase_font_size) self.mnuDecreaseFontSize.triggered.connect(decrease_font_size) self.add_settings_widgets() def add_settings_widgets(self): self.settings_widgets = {} gb = self.gbOptions # the options groupbox layout = QtGui.QVBoxLayout() gb.setLayout(layout) for text, variable in settings.checkboxes: if variable: widget = QtGui.QCheckBox('&' + text) def state_changed(value, variable=variable, widget=widget): setattr(self.test.settings, variable, widget.isChecked()) widget.stateChanged.connect(state_changed) widget.setChecked(getattr(self.test.settings, variable)) self.settings_widgets[variable] = widget else: widget = QtGui.QLabel(text) widget.setAlignment(Qt.AlignHCenter) layout.addWidget(widget) for slider in settings.sliders: label = QtGui.QLabel(slider['text']) label.setAlignment(Qt.AlignHCenter) layout.addWidget(label) widget = QtGui.QScrollBar(Qt.Horizontal) widget.setRange(slider['min'], slider['max']) var = slider['name'] def value_changed(value, slider=slider, label=label): variable = slider['name'] text = slider['text'] setattr(self.test.settings, variable, value) label.setText('%s (%d)' % (text, value)) widget.valueChanged.connect(value_changed) self.settings_widgets[var] = widget layout.addWidget(widget) self.update_widgets_from_settings() def update_widgets_from_settings(self, step_settings=None): if step_settings is None: step_settings = self.test.settings for var, widget in list(self.settings_widgets.items()): if isinstance(widget, QtGui.QCheckBox): widget.setChecked(getattr(step_settings, var)) else: widget.setValue(getattr(step_settings, var)) for slider in settings.sliders: var = slider['name'] self.settings_widgets[var].setValue(getattr(step_settings, var)) def reset_properties_list(self): self.twProperties.clear() self.twProperties.setRowCount(0) self.twProperties.setColumnCount(3) self.twProperties.verticalHeader().hide() # don't show numbers on left self.twProperties.setHorizontalHeaderLabels(['class', 'name', 'value']) def keyPressEvent(self, event): self.test._Keyboard_Event(event.key(), down=True) def keyReleaseEvent(self, event): self.test._Keyboard_Event(event.key(), down=False) @property def settings(self): return QtCore.QSettings("pybox2d", "Framework") def setFontSize(self, size): """ Update the global font size """ if size <= 0.0: return global app font = app.font() font.setPointSize(size) app.setFont(font) def restoreLayout(self): """ Restore the layout of each widget """ settings = self.settings try: self.restoreGeometry(settings.value("geometry").toByteArray()) self.restoreState(settings.value("windowState").toByteArray()) size = settings.value('fontSize').toFloat()[0] self.setFontSize(size) except: pass def saveLayout(self): """ Save the layout of each widget """ settings = self.settings settings.setValue("geometry", self.saveGeometry()) settings.setValue("windowState", self.saveState()) settings.setValue("fontSize", app.font().pointSize()) def closeEvent(self, event): QtGui.QMainWindow.closeEvent(self, event) self.saveLayout() app = None class Pyqt4Framework(FrameworkBase): TEXTLINE_START = 0 def setup_keys(self): # Only basic keys are mapped for now: K_[a-z0-9], K_F[1-12] and # K_COMMA. for letter in string.ascii_uppercase: setattr(Keys, 'K_' + letter.lower(), getattr(Qt, 'Key_%s' % letter)) for i in range(0, 10): setattr(Keys, 'K_%d' % i, getattr(Qt, 'Key_%d' % i)) for i in range(1, 13): setattr(Keys, 'K_F%d' % i, getattr(Qt, 'Key_F%d' % i)) Keys.K_LEFT = Qt.Key_Left Keys.K_RIGHT = Qt.Key_Right Keys.K_UP = Qt.Key_Up Keys.K_DOWN = Qt.Key_Down Keys.K_HOME = Qt.Key_Home Keys.K_PAGEUP = Qt.Key_PageUp Keys.K_PAGEDOWN = Qt.Key_PageDown Keys.K_COMMA = Qt.Key_Comma Keys.K_SPACE = Qt.Key_Space def __reset(self): # Screen/rendering-related self._viewZoom = 10.0 self._viewCenter = None self._viewOffset = None self.screenSize = None self.textLine = 0 self.font = None self.fps = 0 self.selected_shapebody = None, None # GUI-related self.window = None self.setup_keys() def __init__(self): super(Pyqt4Framework, self).__init__() self.__reset() if settings.fwSettings.onlyInit: # testing mode doesn't initialize Pyqt4 return global app app = QtGui.QApplication(sys.argv) print('Initializing Pyqt4 framework...') # Pyqt4 Initialization self.window = MainWindow(self) self.window.show() self.window.setWindowTitle("Python Box2D Testbed - " + self.name) self.renderer = Pyqt4Draw(self) # Note that in this framework, we override the draw debug data routine # that occurs in Step(), and we implement the normal C++ code in # Python. self.world.DrawDebugData = lambda: self.renderer.ManualDraw() self.screenSize = b2Vec2(0, 0) self.viewCenter = (0, 10.0 * 20.0) self.groundbody = self.world.CreateBody() def setCenter(self, value): """ Updates the view offset based on the center of the screen. Tells the debug draw to update its values also. """ self._viewCenter = b2Vec2(*value) self._viewOffset = self._viewCenter - self.screenSize / 2 self.window.graphicsView.centerOn(*self._viewCenter) def setZoom(self, zoom): self._viewZoom = zoom self.window.graphicsView.resetTransform() self.window.graphicsView.scale(self._viewZoom, -self._viewZoom) self.window.graphicsView.centerOn(*self._viewCenter) viewZoom = property(lambda self: self._viewZoom, setZoom, doc='Zoom factor for the display') viewCenter = property(lambda self: self._viewCenter, setCenter, doc='Screen center in camera coordinates') viewOffset = property(lambda self: self._viewOffset, doc='The offset of the top-left corner of the screen') def run(self): """ What would be the main loop is instead a call to app.exec_() for the event-driven pyqt4. """ global app self.step_timer = QtCore.QTimer() self.step_timer.timeout.connect(self.SimulationLoop) self.window.twProperties.itemChanged.connect(self.prop_cell_changed) self.step_timer.start(int((1000.0 / self.settings.hz))) app.exec_() self.step_timer.stop() print('Cleaning up...') self.world.contactListener = None self.world.destructionListener = None self.world.renderer = None self.world = None def _Keyboard_Event(self, key, down=True): """ Internal keyboard event, don't override this. Checks for the initial keydown of the basic testbed keys. Passes the unused ones onto the test via the Keyboard() function. """ if down: if key == Keys.K_z: # Zoom in self.viewZoom = min(1.10 * self.viewZoom, 50.0) elif key == Keys.K_x: # Zoom out self.viewZoom = max(0.9 * self.viewZoom, 0.02) elif key == Keys.K_SPACE: # Launch a bomb self.LaunchRandomBomb() else: # Inform the test of the key press self.Keyboard(key) else: self.KeyboardUp(key) def CheckKeys(self): pass def _ShowProperties(self, obj): self.selected_shapebody = None, None class_ = obj.__class__ ignore_list = ('thisown',) i = 0 twProperties = self.window.twProperties # Get all of the members of the class for prop in dir(class_): # If they're properties and not to be ignored, add them to the # table widget if (isinstance(getattr(class_, prop), property) and prop not in ignore_list): try: value = getattr(obj, prop) except: # Write-only? continue widget = None # Attempt to determine whether it's read-only or not try: setattr(obj, prop, value) except: editable = False else: editable = True # Increase the row count and insert the new item twProperties.setRowCount(twProperties.rowCount() + 1) i = twProperties.rowCount() - 1 self.item = QTableWidgetItem(class_.__name__) twProperties.setItem(i, 0, QTableWidgetItem( class_.__name__)) # class name twProperties.item(i, 0).setFlags(Qt.ItemIsEnabled) twProperties.setItem( i, 1, QtGui.QTableWidgetItem(prop)) # prop name twProperties.item(i, 1).setFlags(Qt.ItemIsEnabled) # and finally, the property values # booleans are checkboxes if isinstance(value, bool): def state_changed(value, prop=prop): self.property_changed(prop, value == Qt.Checked) widget = QtGui.QCheckBox('') widget.stateChanged.connect(state_changed) if value: widget.setCheckState(Qt.Checked) # ints, floats are spinboxes elif isinstance(value, (int, float)): def value_changed(value, prop=prop): self.property_changed(prop, value) widget = QtGui.QDoubleSpinBox() widget.valueChanged.connect(value_changed) widget.setValue(value) # lists turn into -- lists elif isinstance(value, list): widget = QtGui.QListWidget() for entry in value: widget.addItem(str(entry)) if value: # sz=widget.item(0).sizeHint() # print(sz, sz.width(), sz.height()) # sz.setHeight(sz.height()*2) # widget.setMinimumSize(sz) # widget.setMinimumSize(QtCore.QSize(1,60)) pass # TODO # vec2s will be shown as a textbox elif isinstance(value, b2Vec2): value = '(%.2f, %.2f)' % (tuple(value)) else: pass if widget: twProperties.setCellWidget(i, 2, widget) if hasattr(widget, 'setReadOnly'): widget.setReadOnly(not editable) elif hasattr(widget, 'setEnabled'): widget.setEnabled(editable) else: # Just using the table widget, set the cell text cell = QtGui.QTableWidgetItem(str(value)) if editable: cell.setFlags(Qt.ItemIsEditable | Qt.ItemIsEnabled) else: cell.setFlags(Qt.ItemIsEnabled) twProperties.setItem(i, 2, cell) i += 1 # callback indicating a cell in the table widget was changed def prop_cell_changed(self, twi): if twi.column() != 2: # the data column return row = twi.row() prop = str(self.window.twProperties.item(row, 1).text()) self.property_changed(prop, str(twi.text())) # callback indicating one of the property widgets was modified def property_changed(self, prop, value=None): if not self.selected_shapebody[0]: return print('Trying to change %s to %s...' % (prop, value)) shape, body = self.selected_shapebody for inst in (shape, body): if hasattr(inst, prop): try: cur_value = getattr(inst, prop) if isinstance(cur_value, b2Vec2): m = re.search('\(?([\d\.]*)\s*,\s*([\d\.]*)\)?', value) if m: x, y = m.groups() value = (float(x), float(y)) except: raise pass try: setattr(inst, prop, value) except: print('Failed - %s' % sys.exc_info()[1]) def ShowProperties(self, p): aabb = b2AABB(lowerBound=p - (0.001, 0.001), upperBound=p + (0.001, 0.001)) # Query the world for overlapping shapes. query = fwQueryCallback(p) self.world.QueryAABB(query, aabb) if query.fixture: self.window.reset_properties_list() fixture = query.fixture body = fixture.body self._ShowProperties(body) shape = fixture.shape self._ShowProperties(shape) self.selected_shapebody = (shape, body) def Step(self, settings): super(Pyqt4Framework, self).Step(settings) def ConvertScreenToWorld(self, x, y): """ PyQt4 gives us transformed positions, so no need to convert """ return b2Vec2(x, y) DrawStringAt = lambda self, *args: self.renderer.DrawStringAt(*args) def Print(self, str, color=(229, 153, 153, 255)): """ Draw some text at the top status lines and advance to the next line. """ self.DrawStringAt(5, self.textLine, str, color) self.textLine += self.renderer.font_spacing def Keyboard(self, key): """ Callback indicating 'key' has been pressed down. The keys are mapped after pygame's style. from framework import Keys if key == Keys.K_z: ... """ pass def KeyboardUp(self, key): """ Callback indicating 'key' has been released. See Keyboard() for key information """ pass def FixtureDestroyed(self, fixture): shape = fixture.shape if shape == self.selected_shapebody[0]: self.selected_shapebody = None, None self.window.reset_properties_list() if hash(shape) in self.renderer.item_cache: scene_items = self.renderer.item_cache[hash(shape)] for item in scene_items: self.window.scene.removeItem(item) del self.renderer.item_cache[hash(shape)] pybox2d-2.3.2/examples/backends/pyqt4_gui.py000066400000000000000000000121051276457661000210110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'pyqt4_gui.ui' # # Created: Sun Mar 13 19:19:05 2011 # by: PyQt4 UI code generator 4.7.6 # # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: _fromUtf8 = lambda s: s class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName(_fromUtf8("MainWindow")) MainWindow.resize(800, 600) MainWindow.setTabShape(QtGui.QTabWidget.Rounded) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget) self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) self.graphicsView = QtGui.QGraphicsView(self.centralwidget) self.graphicsView.setObjectName(_fromUtf8("graphicsView")) self.horizontalLayout.addWidget(self.graphicsView) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21)) self.menubar.setObjectName(_fromUtf8("menubar")) self.mnuFile = QtGui.QMenu(self.menubar) self.mnuFile.setObjectName(_fromUtf8("mnuFile")) self.menu_Options = QtGui.QMenu(self.menubar) self.menu_Options.setObjectName(_fromUtf8("menu_Options")) self.menu_Font_size = QtGui.QMenu(self.menu_Options) self.menu_Font_size.setObjectName(_fromUtf8("menu_Font_size")) MainWindow.setMenuBar(self.menubar) self.statusbar = QtGui.QStatusBar(MainWindow) self.statusbar.setObjectName(_fromUtf8("statusbar")) MainWindow.setStatusBar(self.statusbar) self.dwProperties = QtGui.QDockWidget(MainWindow) self.dwProperties.setObjectName(_fromUtf8("dwProperties")) self.dwcProperties = QtGui.QWidget() self.dwcProperties.setObjectName(_fromUtf8("dwcProperties")) self.verticalLayout = QtGui.QVBoxLayout(self.dwcProperties) self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) self.gbOptions = QtGui.QGroupBox(self.dwcProperties) self.gbOptions.setObjectName(_fromUtf8("gbOptions")) self.verticalLayout.addWidget(self.gbOptions) self.twProperties = QtGui.QTableWidget(self.dwcProperties) self.twProperties.setLineWidth(1) self.twProperties.setAlternatingRowColors(True) self.twProperties.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel) self.twProperties.setHorizontalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel) self.twProperties.setObjectName(_fromUtf8("twProperties")) self.twProperties.setColumnCount(0) self.twProperties.setRowCount(0) self.verticalLayout.addWidget(self.twProperties) self.dwProperties.setWidget(self.dwcProperties) MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dwProperties) self.mnuExit = QtGui.QAction(MainWindow) self.mnuExit.setObjectName(_fromUtf8("mnuExit")) self.mnuIncreaseFontSize = QtGui.QAction(MainWindow) self.mnuIncreaseFontSize.setObjectName(_fromUtf8("mnuIncreaseFontSize")) self.mnuDecreaseFontSize = QtGui.QAction(MainWindow) self.mnuDecreaseFontSize.setObjectName(_fromUtf8("mnuDecreaseFontSize")) self.mnuFile.addAction(self.mnuExit) self.menu_Font_size.addAction(self.mnuIncreaseFontSize) self.menu_Font_size.addAction(self.mnuDecreaseFontSize) self.menu_Options.addAction(self.menu_Font_size.menuAction()) self.menubar.addAction(self.mnuFile.menuAction()) self.menubar.addAction(self.menu_Options.menuAction()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "pybox2d testbed", None, QtGui.QApplication.UnicodeUTF8)) self.mnuFile.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) self.menu_Options.setTitle(QtGui.QApplication.translate("MainWindow", "&Options", None, QtGui.QApplication.UnicodeUTF8)) self.menu_Font_size.setTitle(QtGui.QApplication.translate("MainWindow", "&Font size", None, QtGui.QApplication.UnicodeUTF8)) self.dwProperties.setWindowTitle(QtGui.QApplication.translate("MainWindow", "Properties", None, QtGui.QApplication.UnicodeUTF8)) self.gbOptions.setTitle(QtGui.QApplication.translate("MainWindow", "Options", None, QtGui.QApplication.UnicodeUTF8)) self.twProperties.setSortingEnabled(True) self.mnuExit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8)) self.mnuIncreaseFontSize.setText(QtGui.QApplication.translate("MainWindow", "&Increase", None, QtGui.QApplication.UnicodeUTF8)) self.mnuDecreaseFontSize.setText(QtGui.QApplication.translate("MainWindow", "&Decrease", None, QtGui.QApplication.UnicodeUTF8)) pybox2d-2.3.2/examples/backends/pyqt4_gui.ui000066400000000000000000000060261276457661000210030ustar00rootroot00000000000000 MainWindow 0 0 800 600 pybox2d testbed QTabWidget::Rounded 0 0 800 21 &File &Options &Font size Properties 1 Options twProperties 1 true QAbstractItemView::ScrollPerPixel QAbstractItemView::ScrollPerPixel true E&xit &Increase &Decrease pybox2d-2.3.2/examples/backends/simple_framework.py000066400000000000000000000151621276457661000224400ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. """ A simple, minimal Pygame-based backend. It will only draw and support very basic keyboard input (ESC to quit). There are no main dependencies other than the actual test you are running. Note that this only relies on framework.py for the loading of this backend, and holding the Keys class. If you write a test that depends only on this backend, you can remove references to that file here and import this module directly in your test. To use this backend, try: % python -m examples.web --backend simple NOTE: Examples with Step() re-implemented are not yet supported, as I wanted to do away with the Settings class. This means the following will definitely not work: Breakable, Liquid, Raycast, TimeOfImpact, ... (incomplete) """ import pygame from pygame.locals import (QUIT, KEYDOWN, KEYUP) import Box2D from Box2D.b2 import (world, staticBody, dynamicBody, kinematicBody, polygonShape, circleShape, edgeShape, loopShape) TARGET_FPS = 60 PPM = 10.0 TIMESTEP = 1.0 / TARGET_FPS VEL_ITERS, POS_ITERS = 10, 10 SCREEN_WIDTH, SCREEN_HEIGHT = 800, 600 SCREEN_OFFSETX, SCREEN_OFFSETY = SCREEN_WIDTH * 1.0 / 2.0, SCREEN_HEIGHT * 2.0 / 3 colors = { staticBody: (255, 255, 255, 255), dynamicBody: (127, 127, 127, 255), kinematicBody: (127, 127, 230, 255), } def fix_vertices(vertices): return [(int(SCREEN_OFFSETX + v[0]), int(SCREEN_OFFSETY - v[1])) for v in vertices] def _draw_polygon(polygon, screen, body, fixture): transform = body.transform vertices = fix_vertices([transform * v * PPM for v in polygon.vertices]) pygame.draw.polygon( screen, [c / 2.0 for c in colors[body.type]], vertices, 0) pygame.draw.polygon(screen, colors[body.type], vertices, 1) polygonShape.draw = _draw_polygon def _draw_circle(circle, screen, body, fixture): position = fix_vertices([body.transform * circle.pos * PPM])[0] pygame.draw.circle(screen, colors[body.type], position, int(circle.radius * PPM)) circleShape.draw = _draw_circle def _draw_edge(edge, screen, body, fixture): vertices = fix_vertices( [body.transform * edge.vertex1 * PPM, body.transform * edge.vertex2 * PPM]) pygame.draw.line(screen, colors[body.type], vertices[0], vertices[1]) edgeShape.draw = _draw_edge def _draw_loop(loop, screen, body, fixture): transform = body.transform vertices = fix_vertices([transform * v * PPM for v in loop.vertices]) v1 = vertices[-1] for v2 in vertices: pygame.draw.line(screen, colors[body.type], v1, v2) v1 = v2 loopShape.draw = _draw_loop def draw_world(screen, world): # Draw the world for body in world.bodies: for fixture in body.fixtures: fixture.shape.draw(screen, body, fixture) class Keys(object): pass # The following import is only needed to do the initial loading and # overwrite the Keys class. import framework # Set up the keys (needed as the normal framework abstracts them between # backends) keys = [s for s in dir(pygame.locals) if s.startswith('K_')] for key in keys: value = getattr(pygame.locals, key) setattr(Keys, key, value) framework.Keys = Keys class SimpleFramework(object): name = 'None' description = '' def __init__(self): self.world = world() print('Initializing pygame framework...') # Pygame Initialization pygame.init() caption = "Python Box2D Testbed - Simple backend - " + self.name pygame.display.set_caption(caption) # Screen and debug draw self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) self.font = pygame.font.Font(None, 15) self.groundbody = self.world.CreateBody() def run(self): """ Main loop. Updates the world and then the screen. """ running = True clock = pygame.time.Clock() while running: for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYDOWN and event.key == Keys.K_ESCAPE): running = False elif event.type == KEYDOWN: self.Keyboard(event.key) elif event.type == KEYUP: self.KeyboardUp(event.key) self.screen.fill((0, 0, 0)) self.textLine = 15 # Step the world self.world.Step(TIMESTEP, VEL_ITERS, POS_ITERS) self.world.ClearForces() draw_world(self.screen, self.world) # Draw the name of the test running self.Print(self.name, (127, 127, 255)) if self.description: # Draw the name of the test running for s in self.description.split('\n'): self.Print(s, (127, 255, 127)) pygame.display.flip() clock.tick(TARGET_FPS) self.fps = clock.get_fps() self.world.contactListener = None self.world.destructionListener = None self.world.renderer = None def Print(self, str, color=(229, 153, 153, 255)): """ Draw some text at the top status lines and advance to the next line. """ self.screen.blit(self.font.render( str, True, color), (5, self.textLine)) self.textLine += 15 def Keyboard(self, key): """ Callback indicating 'key' has been pressed down. The keys are mapped after pygame's style. from .framework import Keys if key == Keys.K_z: ... """ pass def KeyboardUp(self, key): """ Callback indicating 'key' has been released. See Keyboard() for key information """ pass pybox2d-2.3.2/examples/body_types.py000066400000000000000000000072241276457661000175010ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2EdgeShape, b2FixtureDef, b2PolygonShape, b2_dynamicBody, b2_kinematicBody, b2_staticBody) class BodyTypes(Framework): name = "Body Types" description = "Change body type keys: (d) dynamic, (s) static, (k) kinematic" speed = 3 # platform speed def __init__(self): super(BodyTypes, self).__init__() # The ground ground = self.world.CreateBody( shapes=b2EdgeShape(vertices=[(-20, 0), (20, 0)]) ) # The attachment self.attachment = self.world.CreateDynamicBody( position=(0, 3), fixtures=b2FixtureDef( shape=b2PolygonShape(box=(0.5, 2)), density=2.0), ) # The platform fixture = b2FixtureDef( shape=b2PolygonShape(box=(4, 0.5)), density=2, friction=0.6, ) self.platform = self.world.CreateDynamicBody( position=(0, 5), fixtures=fixture, ) # The joints joining the attachment/platform and ground/platform self.world.CreateRevoluteJoint( bodyA=self.attachment, bodyB=self.platform, anchor=(0, 5), maxMotorTorque=50, enableMotor=True ) self.world.CreatePrismaticJoint( bodyA=ground, bodyB=self.platform, anchor=(0, 5), axis=(1, 0), maxMotorForce=1000, enableMotor=True, lowerTranslation=-10, upperTranslation=10, enableLimit=True ) # And the payload that initially sits upon the platform # Reusing the fixture we previously defined above fixture.shape.box = (0.75, 0.75) self.payload = self.world.CreateDynamicBody( position=(0, 8), fixtures=fixture, ) def Keyboard(self, key): if key == Keys.K_d: self.platform.type = b2_dynamicBody elif key == Keys.K_s: self.platform.type = b2_staticBody elif key == Keys.K_k: self.platform.type = b2_kinematicBody self.platform.linearVelocity = (-self.speed, 0) self.platform.angularVelocity = 0 def Step(self, settings): super(BodyTypes, self).Step(settings) if self.platform.type == b2_kinematicBody: p = self.platform.transform.position v = self.platform.linearVelocity if ((p.x < -10 and v.x < 0) or (p.x > 10 and v.x > 0)): v.x = -v.x self.platform.linearVelocity = v if __name__ == "__main__": main(BodyTypes) pybox2d-2.3.2/examples/box_cutter.py000066400000000000000000000220031276457661000174660ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # Original C++ version by Daid # http://www.box2d.org/forum/viewtopic.php?f=3&t=1473 # - Written for pybox2d 2.1 by Ken import sys from .framework import (Framework, Keys, main) from Box2D import (b2AssertException, b2Color, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2RayCastCallback, b2Vec2) LASER_HALF_WIDTH = 2 LASER_SPLIT_SIZE = 0.1 LASER_SPLIT_TAG = 'can_cut' def _polygon_split(fixture, p1, p2, split_size): polygon = fixture.shape body = fixture.body # transform = body.transform local_entry = body.GetLocalPoint(p1) local_exit = body.GetLocalPoint(p2) entry_vector = local_exit - local_entry entry_normal = entry_vector.cross(1.0) last_verts = None new_vertices = [[], []] cut_added = [-1, -1] for vertex in polygon.vertices: # Find out if this vertex is on the new or old shape if entry_normal.dot(b2Vec2(vertex) - local_entry) > 0.0: verts = new_vertices[0] else: verts = new_vertices[1] if last_verts != verts: # if we switch from one shape to the other, add the cut vertices if last_verts == new_vertices[0]: if cut_added[0] != -1: return [] cut_added[0] = len(last_verts) last_verts.append(b2Vec2(local_exit)) last_verts.append(b2Vec2(local_entry)) elif last_verts == new_vertices[1]: if cut_added[1] != -1: return [] cut_added[1] = len(last_verts) last_verts.append(b2Vec2(local_entry)) last_verts.append(b2Vec2(local_exit)) verts.append(b2Vec2(vertex)) last_verts = verts # Add the cut if not added yet if cut_added[0] < 0: cut_added[0] = len(new_vertices[0]) new_vertices[0].append(b2Vec2(local_exit)) new_vertices[0].append(b2Vec2(local_entry)) if cut_added[1] < 0: cut_added[1] = len(new_vertices[1]) new_vertices[1].append(b2Vec2(local_entry)) new_vertices[1].append(b2Vec2(local_exit)) # Cut based on the split size for added, verts in zip(cut_added, new_vertices): if added > 0: offset = verts[added - 1] - verts[added] else: offset = verts[-1] - verts[0] offset.Normalize() verts[added] += split_size * offset if added < len(verts) - 2: offset = verts[added + 2] - verts[added + 1] else: offset = verts[0] - verts[len(verts) - 1] offset.Normalize() verts[added + 1] += split_size * offset # Ensure the new shapes aren't too small for verts in new_vertices: for i, v1 in enumerate(verts): for j, v2 in enumerate(verts): if i != j and (v1 - v2).length < 0.1: # print('Failed to split: too small') return [] try: return [b2PolygonShape(vertices=verts) for verts in new_vertices] except b2AssertException: return [] except ValueError: return [] def _laser_cut(world, laser_body, length=30.0, laser_half_width=2, **kwargs): p1, p2 = get_laser_line(laser_body, length, laser_half_width) callback = laser_callback() world.RayCast(callback, p1, p2) if not callback.hit: return [] hits_forward = callback.hits callback = laser_callback() world.RayCast(callback, p2, p1) if not callback.hit: return [] hits_reverse = callback.hits if len(hits_forward) != len(hits_reverse): return [] ret = [] for (fixture1, point1), (fixture2, point2) in zip(hits_forward, hits_reverse): # renderer.DrawPoint(renderer.to_screen(point1), 2, b2Color(1,0,0)) # renderer.DrawPoint(renderer.to_screen(point2), 2, b2Color(0,1,0)) # renderer.DrawSegment(renderer.to_screen(point1), renderer.to_screen(point2), b2Color(0,1,1)) if fixture1 != fixture2: continue new_polygons = _polygon_split( fixture1, point1, point2, LASER_SPLIT_SIZE) if new_polygons: ret.append((fixture1, new_polygons)) return ret def laser_cut(world, laser_body, length=30.0, laser_half_width=2, **kwargs): cut_fixtures = _laser_cut( world, laser_body, laser_half_width=LASER_HALF_WIDTH) remove_bodies = [] for fixture, new_shapes in cut_fixtures: body = fixture.body if body in remove_bodies: continue new_body = world.CreateDynamicBody( userData=LASER_SPLIT_TAG, position=body.position, angle=body.angle, linearVelocity=body.linearVelocity, angularVelocity=body.angularVelocity, ) try: new_body.CreateFixture( friction=fixture.friction, restitution=fixture.restitution, density=fixture.density, shape=new_shapes[1], ) except AssertionError: print('New body fixture failed: %s' % sys.exc_info()[1]) remove_bodies.append(new_body) try: body.CreateFixture( friction=fixture.friction, restitution=fixture.restitution, density=fixture.density, shape=new_shapes[0], ) body.DestroyFixture(fixture) except AssertionError: print('New fixture/destroy failed: %s' % sys.exc_info()[1]) remove_bodies.append(body) for body in remove_bodies: world.DestroyBody(body) def get_laser_line(laser_body, length, laser_half_width): laser_start = (laser_half_width - 0.1, 0.0) laser_dir = (length, 0.0) p1 = laser_body.GetWorldPoint(laser_start) p2 = p1 + laser_body.GetWorldVector(laser_dir) return (p1, p2) def laser_display(renderer, laser_body, length=30.0, laser_color=(1, 0, 0), laser_half_width=2, **kwargs): if not renderer: return p1, p2 = get_laser_line(laser_body, length, laser_half_width) renderer.DrawSegment(renderer.to_screen( p1), renderer.to_screen(p2), b2Color(*laser_color)) class laser_callback(b2RayCastCallback): """This raycast collects multiple hits.""" def __init__(self, **kwargs): b2RayCastCallback.__init__(self, **kwargs) self.hit = False self.hits = [] def ReportFixture(self, fixture, point, normal, fraction): self.hit = True if fixture.body.userData == LASER_SPLIT_TAG: self.hits.append((fixture, point)) self.last_fixture = fixture self.last_point = point return 1.0 class BoxCutter(Framework): name = "Box Cutter" description = 'Press (c) to cut' move = 0 jump = 100 def __init__(self): super(BoxCutter, self).__init__() # The ground self.ground = self.world.CreateStaticBody( userData='ground', shapes=[ b2EdgeShape(vertices=[(-50, 0), (50, 0)]), b2EdgeShape(vertices=[(-50, 0), (-50, 10)]), b2EdgeShape(vertices=[(50, 0), (50, 10)]), ] ) self.laser_body = self.world.CreateDynamicBody( userData='laser', position=(0, 2), fixtures=b2FixtureDef( density=4.0, shape=b2PolygonShape(box=(LASER_HALF_WIDTH, 1)) ) ) for i in range(2): self.world.CreateDynamicBody( userData=LASER_SPLIT_TAG, position=(3.0 + i * 6, 8), fixtures=b2FixtureDef( density=5.0, shape=b2PolygonShape(box=(3, 3)) ) ) def Keyboard(self, key): if key == Keys.K_c: laser_cut(self.world, self.laser_body, laser_half_width=LASER_HALF_WIDTH) def Step(self, settings): Framework.Step(self, settings) laser_display(self.renderer, self.laser_body, laser_half_width=LASER_HALF_WIDTH) if __name__ == "__main__": main(BoxCutter) pybox2d-2.3.2/examples/breakable.py000066400000000000000000000070761276457661000172350ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2Cross, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2_pi) class Breakable (Framework): name = "Breakable bodies" description = "With enough of an impulse, the single body will split [press b to manually break it]" _break = False # Flag to break broke = False # Already broken? def __init__(self): super(Breakable, self).__init__() # The ground self.world.CreateBody(shapes=b2EdgeShape(vertices=[(-40, 0), (40, 0)])) # The breakable body self.shapes = (b2PolygonShape(box=(0.5, 0.5, (-0.5, 0), 0)), b2PolygonShape(box=(0.5, 0.5, (0.5, 0), 0)) ) self.body = self.world.CreateDynamicBody( position=(0, 40), angle=0.25 * b2_pi, shapes=self.shapes, shapeFixture=b2FixtureDef(density=1), ) self.fixtures = self.body.fixtures def PostSolve(self, contact, impulse): # Already broken? if self.broke: return # If the impulse is enough to split the objects, then flag it to break if max(impulse.normalImpulses) > 40: self._break = True def Break(self): # Create two bodies from one body = self.body center = body.worldCenter body.DestroyFixture(self.fixtures[1]) self.fixture2 = None body2 = self.world.CreateDynamicBody( position=body.position, angle=body.angle, shapes=self.shapes[1], shapeFixture=b2FixtureDef(density=1), ) # Compute consistent velocities for new bodies based on cached # velocity. velocity1 = (self.velocity + b2Cross(self.angularVelocity, body.worldCenter - center)) velocity2 = (self.velocity + b2Cross(self.angularVelocity, body2.worldCenter - center)) body.angularVelocity = self.angularVelocity body.linearVelocity = velocity1 body2.angularVelocity = self.angularVelocity body2.linearVelocity = velocity2 def Step(self, settings): super(Breakable, self).Step(settings) if self._break: self.Break() self.broke = True self._break = False if not self.broke: self.velocity = self.body.linearVelocity self.angularVelocity = self.body.angularVelocity def Keyboard(self, key): if key == Keys.K_b and not self.broke: self._break = True if __name__ == "__main__": main(Breakable) pybox2d-2.3.2/examples/bridge.py000066400000000000000000000065171276457661000165600ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape) def create_bridge(world, ground, size, offset, plank_count, friction=0.6, density=1.0): """ Create a bridge with plank_count planks, utilizing rectangular planks of size (width, height). The bridge should start at x_offset, and continue to roughly x_offset+width*plank_count. The y will not change. """ width, height = size x_offset, y_offset = offset half_height = height / 2 plank = b2FixtureDef( shape=b2PolygonShape(box=(width / 2, height / 2)), friction=friction, density=density, ) bodies = [] prevBody = ground for i in range(plank_count): body = world.CreateDynamicBody( position=(x_offset + width * i, y_offset), fixtures=plank, ) bodies.append(body) world.CreateRevoluteJoint( bodyA=prevBody, bodyB=body, anchor=(x_offset + width * (i - 0.5), y_offset) ) prevBody = body world.CreateRevoluteJoint( bodyA=prevBody, bodyB=ground, anchor=(x_offset + width * (plank_count - 0.5), y_offset), ) return bodies class Bridge (Framework): name = "Bridge" numPlanks = 30 # Number of planks in the bridge def __init__(self): super(Bridge, self).__init__() # The ground ground = self.world.CreateBody( shapes=b2EdgeShape(vertices=[(-40, 0), (40, 0)]) ) create_bridge(self.world, ground, (1.0, 0.25), (-14.5, 5), self.numPlanks, 0.2, 20) fixture = b2FixtureDef( shape=b2PolygonShape(vertices=[(-0.5, 0.0), (0.5, 0.0), (0.0, 1.5), ]), density=1.0 ) for i in range(2): self.world.CreateDynamicBody( position=(-8 + 8 * i, 12), fixtures=fixture, ) fixture = b2FixtureDef(shape=b2CircleShape(radius=0.5), density=1) for i in range(3): self.world.CreateDynamicBody( position=(-6 + 6 * i, 10), fixtures=fixture, ) if __name__ == "__main__": main(Bridge) pybox2d-2.3.2/examples/bullet.py000066400000000000000000000047071276457661000166120ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2EdgeShape, b2FixtureDef, b2PolygonShape, b2Random) class Bullet (Framework): name = "Bullet" description = 'A test for very fast moving objects (bullets)' def __init__(self): super(Bullet, self).__init__() ground = self.world.CreateStaticBody( position=(0, 0), shapes=[b2EdgeShape(vertices=[(-10, 0), (10, 0)]), b2PolygonShape(box=(0.2, 1, (0.5, 1), 0))] ) self._x = 0.20352793 self.body = self.world.CreateDynamicBody( position=(0, 4), fixtures=b2FixtureDef( shape=b2PolygonShape(box=(2, 0.1)), density=1.0), ) self.bullet = self.world.CreateDynamicBody( position=(self._x, 10), bullet=True, fixtures=b2FixtureDef(shape=b2PolygonShape( box=(0.25, 0.25)), density=100.0), linearVelocity=(0, -50) ) def Launch(self): self.body.transform = [(0, 4), 0] self.body.linearVelocity = (0, 0) self.body.angularVelocity = 0 self.x = b2Random() self.bullet.transform = [(self.x, 10), 0] self.bullet.linearVelocity = (0, -50) self.bullet.angularVelocity = 0 def Step(self, settings): super(Bullet, self).Step(settings) if (self.stepCount % 60) == 0: self.Launch() if __name__ == "__main__": main(Bullet) pybox2d-2.3.2/examples/cantilever.py000066400000000000000000000105431276457661000174520ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape) class Cantilever (Framework): name = "Cantilever" description = "" numPlanks = 8 def __init__(self): super(Cantilever, self).__init__() # The ground ground = self.world.CreateBody( shapes=b2EdgeShape(vertices=[(-40, 0), (40, 0)])) plank = b2FixtureDef( shape=b2PolygonShape(box=(0.5, 0.125)), friction=0.2, density=20 ) # Create one cantilever (Only the left end is fixed) prevBody = ground for i in range(self.numPlanks): body = self.world.CreateDynamicBody( position=(-14.5 + i, 5), fixtures=plank, ) self.world.CreateWeldJoint( bodyA=prevBody, bodyB=body, anchor=(-15 + i, 5), ) prevBody = body # Create another higher up prevBody = ground for i in range(self.numPlanks): body = self.world.CreateDynamicBody( position=(-14.5 + i, 15), fixtures=plank, ) self.world.CreateWeldJoint( bodyA=prevBody, bodyB=body, anchor=(-15 + i, 15), ) prevBody = body # And the left-most unconnected one (technically not a cantilever) prevBody = ground for i in range(self.numPlanks): body = self.world.CreateDynamicBody( position=(-4.5 + i, 5), fixtures=plank, ) if i > 0: # skip the joint on the first one self.world.CreateWeldJoint( bodyA=prevBody, bodyB=body, anchor=(-5 + i, 5), ) prevBody = body # And the right-most unconnected one, using joint damping prevBody = ground for i in range(self.numPlanks): body = self.world.CreateDynamicBody( position=(5.5 + i, 10), fixtures=plank, ) if i > 0: # skip the joint on the first one self.world.CreateWeldJoint( bodyA=prevBody, bodyB=body, anchor=(5 + i, 10), frequencyHz=8.0, dampingRatio=0.7, ) prevBody = body # And a few random shapes to play with # First a set of triangles, fixture = b2FixtureDef(shape=b2PolygonShape(vertices=[(-0.5, 0.0), (0.5, 0.0), (0.0, 1.5), ]), density=1.0) for i in range(2): self.world.CreateDynamicBody( position=(-8 + 8 * i, 12), fixtures=fixture, ) # And then a few circles fixture = b2FixtureDef(shape=b2CircleShape(radius=0.5), density=1) for i in range(3): self.world.CreateDynamicBody( position=(-6 + 6 * i, 10), fixtures=fixture, ) if __name__ == "__main__": main(Cantilever) pybox2d-2.3.2/examples/car.py000066400000000000000000000140401276457661000160570ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from .bridge import create_bridge from math import sqrt from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2_pi) def create_car(world, offset, wheel_radius, wheel_separation, density=1.0, wheel_friction=0.9, scale=(1.0, 1.0), chassis_vertices=None, wheel_axis=(0.0, 1.0), wheel_torques=[20.0, 10.0], wheel_drives=[True, False], hz=4.0, zeta=0.7, **kwargs): """ """ x_offset, y_offset = offset scale_x, scale_y = scale if chassis_vertices is None: chassis_vertices = [ (-1.5, -0.5), (1.5, -0.5), (1.5, 0.0), (0.0, 0.9), (-1.15, 0.9), (-1.5, 0.2), ] chassis_vertices = [(scale_x * x, scale_y * y) for x, y in chassis_vertices] radius_scale = sqrt(scale_x ** 2 + scale_y ** 2) wheel_radius *= radius_scale chassis = world.CreateDynamicBody( position=(x_offset, y_offset), fixtures=b2FixtureDef( shape=b2PolygonShape(vertices=chassis_vertices), density=density, ) ) wheels, springs = [], [] wheel_xs = [-wheel_separation * scale_x / 2.0, wheel_separation * scale_x / 2.0] for x, torque, drive in zip(wheel_xs, wheel_torques, wheel_drives): wheel = world.CreateDynamicBody( position=(x_offset + x, y_offset - wheel_radius), fixtures=b2FixtureDef( shape=b2CircleShape(radius=wheel_radius), density=density, ) ) spring = world.CreateWheelJoint( bodyA=chassis, bodyB=wheel, anchor=wheel.position, axis=wheel_axis, motorSpeed=0.0, maxMotorTorque=torque, enableMotor=drive, frequencyHz=hz, dampingRatio=zeta ) wheels.append(wheel) springs.append(spring) return chassis, wheels, springs class Car (Framework): name = "Car" description = "Keys: left = a, brake = s, right = d, hz down = q, hz up = e" hz = 4 zeta = 0.7 speed = 50 bridgePlanks = 20 def __init__(self): super(Car, self).__init__() # The ground -- create some terrain ground = self.world.CreateStaticBody( shapes=b2EdgeShape(vertices=[(-20, 0), (20, 0)]) ) x, y1, dx = 20, 0, 5 vertices = [0.25, 1, 4, 0, 0, -1, -2, -2, -1.25, 0] for y2 in vertices * 2: # iterate through vertices twice ground.CreateEdgeFixture( vertices=[(x, y1), (x + dx, y2)], density=0, friction=0.6, ) y1 = y2 x += dx x_offsets = [0, 80, 40, 20, 40] x_lengths = [40, 40, 10, 40, 0] y2s = [0, 0, 5, 0, 20] for x_offset, x_length, y2 in zip(x_offsets, x_lengths, y2s): x += x_offset ground.CreateEdgeFixture( vertices=[(x, 0), (x + x_length, y2)], density=0, friction=0.6, ) # Teeter body = self.world.CreateDynamicBody( position=(140, 0.90), fixtures=b2FixtureDef( shape=b2PolygonShape(box=(10, 0.25)), density=1.0, ) ) self.world.CreateRevoluteJoint( bodyA=ground, bodyB=body, anchor=body.position, lowerAngle=-8.0 * b2_pi / 180.0, upperAngle=8.0 * b2_pi / 180.0, enableLimit=True, ) # Bridge create_bridge(self.world, ground, (2.0, 0.25), (161.0, -0.125), self.bridgePlanks) # Boxes for y_pos in [0.5, 1.5, 2.5, 3.5, 4.5]: self.world.CreateDynamicBody( position=(230, y_pos), fixtures=b2FixtureDef( shape=b2PolygonShape(box=(0.5, 0.5)), density=0.5, ) ) car, wheels, springs = create_car(self.world, offset=( 0.0, 1.0), wheel_radius=0.4, wheel_separation=2.0, scale=(1, 1)) self.car = car self.wheels = wheels self.springs = springs def Keyboard(self, key): if key == Keys.K_a: self.springs[0].motorSpeed = self.speed elif key == Keys.K_s: self.springs[0].motorSpeed = 0 elif key == Keys.K_d: self.springs[0].motorSpeed = -self.speed elif key in (Keys.K_q, Keys.K_e): if key == Keys.K_q: self.hz = max(0, self.hz - 1.0) else: self.hz += 1.0 for spring in self.springs: spring.springFrequencyHz = self.hz def Step(self, settings): super(Car, self).Step(settings) self.viewCenter = (self.car.position.x, 20) self.Print("frequency = %g hz, damping ratio = %g" % (self.hz, self.zeta)) if __name__ == "__main__": main(Car) pybox2d-2.3.2/examples/chain.py000066400000000000000000000044601276457661000164010ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D.b2 import (edgeShape, polygonShape, fixtureDef) # This test uses the alternative syntax offered by Box2D.b2, so you'll notice # that all of the classes that normally have 'b2' in front of them no longer # do. The choice of which to use is mostly stylistic and is left up to the # user. class Chain (Framework): name = "Chain" def __init__(self): super(Chain, self).__init__() # The ground ground = self.world.CreateBody( shapes=edgeShape(vertices=[(-40, 0), (40, 0)]) ) plank = fixtureDef( shape=polygonShape(box=(0.6, 0.125)), density=20, friction=0.2, ) # Create one Chain (Only the left end is fixed) prevBody = ground y = 25 numPlanks = 30 for i in range(numPlanks): body = self.world.CreateDynamicBody( position=(0.5 + i, y), fixtures=plank, ) # You can try a WeldJoint for a slightly different effect. # self.world.CreateWeldJoint( self.world.CreateRevoluteJoint( bodyA=prevBody, bodyB=body, anchor=(i, y), ) prevBody = body if __name__ == "__main__": main(Chain) pybox2d-2.3.2/examples/character_collision.py000066400000000000000000000101411276457661000213170ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from math import cos, sin from .framework import (Framework, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2_pi) class CharacterCollision(Framework): name = "Character Collision" description = ("This tests various character collision shapes.\n" "Limitation: Square and hexagon can snag on aligned boxes.\n" "Feature: Loops have smooth collision, inside and out." ) def __init__(self): super(CharacterCollision, self).__init__() ground = self.world.CreateStaticBody( position=(0, 0), shapes=b2EdgeShape(vertices=[(-20, 0), (20, 0)]) ) # Collinear edges self.world.CreateStaticBody( shapes=[b2EdgeShape(vertices=[(-8, 1), (-6, 1)]), b2EdgeShape(vertices=[(-6, 1), (-4, 1)]), b2EdgeShape(vertices=[(-4, 1), (-2, 1)]), ] ) # Square tiles self.world.CreateStaticBody( shapes=[b2PolygonShape(box=[1, 1, (4, 3), 0]), b2PolygonShape(box=[1, 1, (6, 3), 0]), b2PolygonShape(box=[1, 1, (8, 3), 0]), ] ) # Square made from an edge loop. Collision should be smooth. body = self.world.CreateStaticBody() body.CreateLoopFixture(vertices=[(-1, 3), (1, 3), (1, 5), (-1, 5)]) # Edge loop. body = self.world.CreateStaticBody(position=(-10, 4)) body.CreateLoopFixture(vertices=[ (0.0, 0.0), (6.0, 0.0), (6.0, 2.0), (4.0, 1.0), (2.0, 2.0), (0.0, 2.0), (-2.0, 2.0), (-4.0, 3.0), (-6.0, 2.0), (-6.0, 0.0), ] ) # Square character 1 self.world.CreateDynamicBody( position=(-3, 8), fixedRotation=True, allowSleep=False, fixtures=b2FixtureDef(shape=b2PolygonShape( box=(0.5, 0.5)), density=20.0), ) # Square character 2 body = self.world.CreateDynamicBody( position=(-5, 5), fixedRotation=True, allowSleep=False, ) body.CreatePolygonFixture(box=(0.25, 0.25), density=20.0) # Hexagon character a = b2_pi / 3.0 self.world.CreateDynamicBody( position=(-5, 8), fixedRotation=True, allowSleep=False, fixtures=b2FixtureDef( shape=b2PolygonShape( vertices=[(0.5 * cos(i * a), 0.5 * sin(i * a)) for i in range(6)]), density=20.0 ), ) # Circle character self.world.CreateDynamicBody( position=(3, 5), fixedRotation=True, allowSleep=False, fixtures=b2FixtureDef( shape=b2CircleShape(radius=0.5), density=20.0 ), ) def Step(self, settings): super(CharacterCollision, self).Step(settings) pass if __name__ == "__main__": main(CharacterCollision) pybox2d-2.3.2/examples/cloth.py000066400000000000000000000131531276457661000164270ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # Ported from the Cloth test by Paril, originally for Box2CS: # http://www.box2d.org/forum/viewtopic.php?f=6&t=6124 # from .framework import (Framework, Keys, main) from Box2D import (b2CircleShape, b2FixtureDef, b2Random, b2Vec2) def create_cloth(world, segment_count, body_size, position=(0, 30), group_index=-1, bar_height=0.5, base_hz=15, base_damping=0.11, density=0.2): segment_w, segment_h = segment_count body_spacing_w = body_size * 2 total_w = body_spacing_w * segment_w position = b2Vec2(*position) # The static bar at the top which holds the cloth bar = world.CreateStaticBody(position=position) bar.CreatePolygonFixture(box=(total_w / 2.0 + body_spacing_w, bar_height / 2.0), groupIndex=group_index) box_fixture = b2FixtureDef(shape=b2CircleShape(radius=body_size), groupIndex=group_index, density=density) weld_joints = [] distance_joints = [] cloth = [[None] * segment_h for x in range(segment_w)] for y in range(segment_h): pos = position - (total_w / 2.0, y * body_spacing_w) for x in range(segment_w): pos += (body_spacing_w, 0.0) body = world.CreateDynamicBody(position=pos, fixtures=box_fixture) cloth[x][y] = body if y == 0: joint = world.CreateWeldJoint(bodyA=body, bodyB=bar, anchor=body.position) weld_joints.append(joint) connect_bodies = [] for y in range(segment_h): for x in range(segment_w): if x <= segment_w - 2: left_body = cloth[x][y] right_body = cloth[x + 1][y] connect_bodies.append((left_body, right_body)) if y > 0: left_body = cloth[x][y] right_body = cloth[x][y - 1] connect_bodies.append((left_body, right_body)) for bodyA, bodyB in connect_bodies: joint = world.CreateDistanceJoint( bodyA=bodyA, bodyB=bodyB, anchorA=bodyA.position, anchorB=bodyB.position, frequencyHz=base_hz + b2Random(0, base_hz / 2.0), dampingRatio=base_damping + b2Random(0.01, base_damping), ) distance_joints.append(joint) return cloth, weld_joints, distance_joints def step_cloth(world, cloth, wind, body_size, segment_count, distance_joints, wind_dir=(1, 1), wind_rand=0.0, distance_factor=1.45): segment_w, segment_h = segment_count body_spacing_w = body_size * 2 if wind: for x in range(segment_w): w = (b2Random(wind_dir[0] - wind_rand / 2.0, wind_dir[0] + wind_rand / 2.0), b2Random(wind_dir[1] - wind_rand / 2.0, wind_dir[1] + wind_rand / 2.0)) cloth[x][-1].linearVelocity += w # If any two points are too far from one another, find the joint connecting # them and destroy it. check_segments = [] for y in range(segment_h): for x in range(segment_w): if y > 0: check_segments.append((cloth[x][y], cloth[x][y - 1])) if x <= segment_w - 2: check_segments.append((cloth[x][y], cloth[x + 1][y])) thresh = body_spacing_w * distance_factor for c1, c2 in check_segments: if (c1.worldCenter - c2.worldCenter).length <= thresh: continue for joint in distance_joints: if ((joint.bodyA == c1 and joint.bodyB == c2) or (joint.bodyA == c2 and joint.bodyB == c1)): world.DestroyJoint(joint) distance_joints.remove(joint) break class Cloth(Framework): name = "Cloth" description = "(w) Toggle wind" def __init__(self): super(Cloth, self).__init__() self.wind = False self.segment_count = (18, 25) self.body_size = 0.22 cloth_info = create_cloth( self.world, self.segment_count, self.body_size) self.cloth, self.weld_joints, self.dist_joints = cloth_info def Keyboard(self, key): if key == Keys.K_w: self.wind = not self.wind def Step(self, settings): super(Cloth, self).Step(settings) if self.wind: self.Print('Wind enabled') step_cloth(self.world, self.cloth, self.wind, self.body_size, self.segment_count, self.dist_joints) if __name__ == "__main__": main(Cloth) pybox2d-2.3.2/examples/collision_filtering.py000066400000000000000000000152601276457661000213550ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2CircleShape, b2EdgeShape, b2Filter, b2FixtureDef, b2PolygonShape, b2Vec2) class CollisionFiltering (Framework): name = "Collision Filtering" description = "See which shapes collide with each other." # This is a test of collision filtering. # There is a triangle, a box, and a circle. # There are 6 shapes. 3 large and 3 small. # The 3 small ones always collide. # The 3 large ones never collide. # The boxes don't collide with triangles (except if both are small). # The box connected to the large triangle has no filter settings, # so it collides with everything. def __init__(self): super(CollisionFiltering, self).__init__() # Ground body world = self.world ground = world.CreateBody( shapes=b2EdgeShape(vertices=[(-40, 0), (40, 0)]) ) # Define the groups that fixtures can fall into # Note that negative groups never collide with other negative ones. smallGroup = 1 largeGroup = -1 # And the categories # Note that these are bit-locations, and as such are written in # hexadecimal. # defaultCategory = 0x0001 triangleCategory = 0x0002 boxCategory = 0x0004 circleCategory = 0x0008 # And the masks that define which can hit one another # A mask of 0xFFFF means that it will collide with everything else in # its group. The box mask below uses an exclusive OR (XOR) which in # effect toggles the triangleCategory bit, making boxMask = 0xFFFD. # Such a mask means that boxes never collide with triangles. (if # you're still confused, see the implementation details below) triangleMask = 0xFFFF boxMask = 0xFFFF ^ triangleCategory circleMask = 0xFFFF # The actual implementation determining whether or not two objects # collide is defined in the C++ source code, but it can be overridden # in Python (with b2ContactFilter). # The default behavior goes like this: # if (filterA.groupIndex == filterB.groupIndex and filterA.groupIndex != 0): # collide if filterA.groupIndex is greater than zero (negative groups never collide) # else: # collide if (filterA.maskBits & filterB.categoryBits) != 0 and (filterA.categoryBits & filterB.maskBits) != 0 # # So, if they have the same group index (and that index isn't the # default 0), then they collide if the group index is > 0 (since # negative groups never collide) # (Note that a body with the default filter settings will always # collide with everything else.) # If their group indices differ, then only if their bitwise-ANDed # category and mask bits match up do they collide. # # For more help, some basics of bit masks might help: # -> http://en.wikipedia.org/wiki/Mask_%28computing%29 # Small triangle triangle = b2FixtureDef( shape=b2PolygonShape(vertices=[(-1, 0), (1, 0), (0, 2)]), density=1, filter=b2Filter( groupIndex=smallGroup, categoryBits=triangleCategory, maskBits=triangleMask, ) ) world.CreateDynamicBody( position=(-5, 2), fixtures=triangle, ) # Large triangle (recycle definitions) triangle.shape.vertices = [ 2.0 * b2Vec2(v) for v in triangle.shape.vertices] triangle.filter.groupIndex = largeGroup trianglebody = world.CreateDynamicBody( position=(-5, 6), fixtures=triangle, fixedRotation=True, # <-- ) # note that the large triangle will not rotate # Small box box = b2FixtureDef( shape=b2PolygonShape(box=(1, 0.5)), density=1, restitution=0.1, filter = b2Filter( groupIndex=smallGroup, categoryBits=boxCategory, maskBits=boxMask, ) ) world.CreateDynamicBody( position=(0, 2), fixtures=box, ) # Large box box.shape.box = (2, 1) box.filter.groupIndex = largeGroup world.CreateDynamicBody( position=(0, 6), fixtures=box, ) # Small circle circle = b2FixtureDef( shape=b2CircleShape(radius=1), density=1, filter=b2Filter( groupIndex=smallGroup, categoryBits=circleCategory, maskBits=circleMask, ) ) world.CreateDynamicBody( position=(5, 2), fixtures=circle, ) # Large circle circle.shape.radius *= 2 circle.filter.groupIndex = largeGroup world.CreateDynamicBody( position=(5, 6), fixtures=circle, ) # Create a joint for fun on the big triangle # Note that it does not inherit or have anything to do with the # filter settings of the attached triangle. box = b2FixtureDef(shape=b2PolygonShape(box=(0.5, 1)), density=1) testbody = world.CreateDynamicBody( position=(-5, 10), fixtures=box, ) world.CreatePrismaticJoint( bodyA=trianglebody, bodyB=testbody, enableLimit=True, localAnchorA=(0, 4), localAnchorB=(0, 0), localAxisA=(0, 1), lowerTranslation=-1, upperTranslation=1, ) if __name__ == "__main__": main(CollisionFiltering) pybox2d-2.3.2/examples/collision_processing.py000066400000000000000000000107421276457661000215460ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2Random, b2Vec2, b2_dynamicBody) class CollisionProcessing (Framework): name = "CollisionProcessing" def __init__(self): super(CollisionProcessing, self).__init__() # Tell the framework we're going to use contacts, so keep track of them # every Step. self.using_contacts = True # Ground body world = self.world ground = world.CreateBody( shapes=b2EdgeShape(vertices=[(-50, 0), (50, 0)],) ) xlow, xhi = -5, 5 ylow, yhi = 2, 35 random_vector = lambda: b2Vec2( b2Random(xlow, xhi), b2Random(ylow, yhi)) # Small triangle triangle = b2FixtureDef( shape=b2PolygonShape(vertices=[(-1, 0), (1, 0), (0, 2)]), density=1, ) world.CreateBody( type=b2_dynamicBody, position=random_vector(), fixtures=triangle, ) # Large triangle (recycle definitions) triangle.shape.vertices = [ 2.0 * b2Vec2(v) for v in triangle.shape.vertices] tri_body = world.CreateBody(type=b2_dynamicBody, position=random_vector(), fixtures=triangle, fixedRotation=True, # <-- ) # note that the large triangle will not rotate # Small box box = b2FixtureDef( shape=b2PolygonShape(box=(1, 0.5)), density=1, restitution=0.1, ) world.CreateBody( type=b2_dynamicBody, position=random_vector(), fixtures=box, ) # Large box box.shape.box = (2, 1) world.CreateBody( type=b2_dynamicBody, position=random_vector(), fixtures=box, ) # Small circle circle = b2FixtureDef( shape=b2CircleShape(radius=1), density=1, ) world.CreateBody( type=b2_dynamicBody, position=random_vector(), fixtures=circle, ) # Large circle circle.shape.radius *= 2 world.CreateBody( type=b2_dynamicBody, position=random_vector(), fixtures=circle, ) def Step(self, settings): # We are going to destroy some bodies according to contact # points. We must buffer the bodies that should be destroyed # because they may belong to multiple contact points. nuke = [] # Traverse the contact results. Destroy bodies that # are touching heavier bodies. body_pairs = [(p['fixtureA'].body, p['fixtureB'].body) for p in self.points] for body1, body2 in body_pairs: mass1, mass2 = body1.mass, body2.mass if mass1 > 0.0 and mass2 > 0.0: if mass2 > mass1: nuke_body = body1 else: nuke_body = body2 if nuke_body not in nuke: nuke.append(nuke_body) # Destroy the bodies, skipping duplicates. for b in nuke: print("Nuking:", b) self.world.DestroyBody(b) nuke = None super(CollisionProcessing, self).Step(settings) if __name__ == "__main__": main(CollisionProcessing) pybox2d-2.3.2/examples/confined.py000066400000000000000000000050001276457661000170730ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from random import random from .framework import (Framework, Keys, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef) class Confined (Framework): name = "Confined space" description = "Press c to create a circle" def __init__(self): super(Confined, self).__init__() # The ground ground = self.world.CreateStaticBody( shapes=[b2EdgeShape(vertices=[(-10, 0), (10, 0)]), b2EdgeShape(vertices=[(-10, 0), (-10, 20)]), b2EdgeShape(vertices=[(10, 0), (10, 20)]), b2EdgeShape(vertices=[(-10, 20), (10, 20)]), ]) # The bodies self.radius = radius = 0.5 columnCount = 5 rowCount = 5 for j in range(columnCount): for i in range(rowCount): self.CreateCircle((-10 + (2.1 * j + 1 + 0.01 * i) * radius, (2 * i + 1) * radius)) self.world.gravity = (0, 0) def CreateCircle(self, pos): fixture = b2FixtureDef(shape=b2CircleShape(radius=self.radius, pos=(0, 0)), density=1, friction=0.1) self.world.CreateDynamicBody( position=pos, fixtures=fixture ) def Keyboard(self, key): if key == Keys.K_c: self.CreateCircle((2.0 * random() - 1.0, self.radius * (1.0 + random()))) if __name__ == "__main__": main(Confined) pybox2d-2.3.2/examples/convex_hull.py000066400000000000000000000054251276457661000176470ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2Clamp, b2Color, b2PolygonShape, b2Random, b2_maxPolygonVertices) class ConvexHull (Framework): name = "ConvexHull" description = ('Press g to generate a new random convex hull, a to switch ' 'to automatic mode') def __init__(self): Framework.__init__(self) self.auto = False self.generate() def generate(self): lower = (-8, -8) upper = (8, 8) self.verts = verts = [] for i in range(b2_maxPolygonVertices): x = 10.0 * b2Random(0.0, 10.0) y = 10.0 * b2Random(0.0, 10.0) # Clamp onto a square to help create collinearities. # This will stress the convex hull algorithm. verts.append(b2Clamp((x, y), lower, upper)) def Keyboard(self, key): if key == Keys.K_a: self.auto = not self.auto elif key == Keys.K_g: self.generate() def Step(self, settings): Framework.Step(self, settings) renderer = self.renderer try: poly = b2PolygonShape(vertices=self.verts) except AssertionError as ex: self.Print('b2PolygonShape failed: %s' % ex) else: self.Print('Valid: %s' % poly.valid) renderer.DrawPolygon([renderer.to_screen(v) for v in self.verts], b2Color(0.9, 0.9, 0.9)) for i, v in enumerate(self.verts): renderer.DrawPoint(renderer.to_screen(v), 2.0, b2Color(0.9, 0.5, 0.5)) x, y = renderer.to_screen(v) self.DrawStringAt(x + 0.05, y + 0.05, '%d' % i) if self.auto: self.generate() if __name__ == "__main__": main(ConvexHull) pybox2d-2.3.2/examples/conveyor_belt.py000066400000000000000000000045431276457661000201730ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2EdgeShape, b2FixtureDef, b2PolygonShape) class ConveyorBelt (Framework): name = "ConveyorBelt" def __init__(self): Framework.__init__(self) self.using_contacts = True ground = self.world.CreateStaticBody( shapes=[b2EdgeShape(vertices=[(-20, 0), (20, 0)])], ) # Platform self.platform = self.world.CreateStaticBody( position=(-5, 5), allowSleep=False, fixtures=b2FixtureDef(friction=0.8, shape=b2PolygonShape(box=(10.0, 5.0)),), ) self.platform_fixture = self.platform.fixtures[0] # Boxes for i in range(5): self.platform = self.world.CreateDynamicBody( position=(-10.0 + 2.0 * i, 7.0), fixtures=b2FixtureDef(density=20.0, shape=b2PolygonShape(box=(0.5, 0.5)),), ) def PreSolve(self, contact, old_manifold): Framework.PreSolve(self, contact, old_manifold) fixture_a, fixture_b = contact.fixtureA, contact.fixtureB if fixture_a == self.platform_fixture: contact.tangentSpeed = 5.0 elif fixture_b == self.platform_fixture: contact.tangentSpeed = -5.0 if __name__ == "__main__": main(ConveyorBelt) pybox2d-2.3.2/examples/data/000077500000000000000000000000001276457661000156525ustar00rootroot00000000000000pybox2d-2.3.2/examples/data/themes/000077500000000000000000000000001276457661000171375ustar00rootroot00000000000000pybox2d-2.3.2/examples/data/themes/default/000077500000000000000000000000001276457661000205635ustar00rootroot00000000000000pybox2d-2.3.2/examples/data/themes/default/Vera.ttf000066400000000000000000002006141276457661000222020ustar00rootroot00000000000000OS/2´_ôcëpVPCLTÑŠ^—ëÈ6cmap¤Ãè ±lXcvt ÿÓ9üüfpgmç´ñÄ&`‹gaspH glyf tAÏ&ìŠ~hdmx4ð!ìHheadÝ„¢ÐT6hheaEoëL$hmtx ÆŽ²´Ä0kernÜRÕ™½ -ŠlocaóËÒ=»„maxpG:ë, nameټȵßpost´Z/»¸ôŽprep;ñ øh::_:: dM0­l  ƒ p t › &   Y &  &   c . 5 ` õ s 0¡ & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5¸ËËÁªœ¦¸fqË ²…u¸Ãˉ-˦ðÓª‡ËªJ3ËÙôT´œ99N´R¸çÍ7sÍ`s3¢V¦V9Åɸßsºé3¼Dßͪåªˤ{¸o{RÇÍššoËÍžÓðºƒÕ˜HžÕÁËöƒT3fÓǤ͚sÕ þ+¤´œbœ-ÕÕÕð{T¤¸#Ӹ˦Ãì“ Ó\qÛ…#¨H99`Õš#fy```{œw`ªé`b{Å{´RÍf¼fwÍ;…‰{ÍJ/œœ}oo5jo{®²-–{öƒT7öœáföÍD)fîs¸€@ÿûþúù%ø2÷–öõþôþó%òñ–ð%ïŠAïþî–í–ìúëúêþé:èBçþæ2åäSå–äŠAäSãâ/ãúâ/áþàþß2ÞÝ–ÜþÛÚ}Ù»ØþÖŠAÖ}ÕÔGÕ}ÔGÓÒÓþÒÑþÐþÏþÎþÍ–ÌËÌþËÊ2ÉþÆ…ÆÅÄþÃþÂþÁþÀþ¿þ¾þ½þ¼þ»þº¹†%¹þ¸·»¸þ·¶]·»·€¶µ%¶]@ÿ¶@µ%´þ³–²þ±þ°þ¯þ®d­¬«%¬d«ª«%ª©ŠA©ú¨þ§þ¦þ¥¤þ£¢£2¢¡d ŠA –Ÿþž žþ œ›œd›š›š™ ˜þ—– —þ– •ŠA•–”“”(“’ú‘»‘þ]»€Ž%]@Ž%þŒ‹.Œþ‹.І%ŠA‰ˆ ‰ˆ ‡†%‡d†…†%…„þƒ‚ƒþ‚þ€þþ@ÿ~}}~þ}}|d{T{%zþyþxw v uþtúsúrúqúpþoþnþl!kþjBjSiþh}gBfþeþdþcþbþa:`ú^ ]þ[þZþYX YúX WW2VþUTUBTSSRQJQþP OþNMNþMLþKJKþJIJI IH GþF–E–DþC-CúB»AK@þ?þ>=>=<=<; <@ÿ; :þ9þ878ú76765 65 43 21 2þ1 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $þ#þ"!! dú d BþúBBþdþþþþBþ-B}dþ  þ   þ  þ-þdþ@-þ-þ¸d…++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++¶, °%Id°@QX ÈY!-,°%Id°@QX ÈY!-,  °P° y ¸ÿÿPXY°°%°%#á °P° y ¸ÿÿPXY°°%á-,KPX °ýEDY!-,°%E`D-,KSX°%°%EDY!!-,ED-fþ–f¤@ ûû/ÄÔì1ÔìÔì0!%!!füsüåþ–øòr)5Õ @@ƒ ü<ì2991/äüÌ0K° TX½ @ ÿÀ878Y¶ P ]%3#3#5ËËË¢þþÕýqþ›eŪéÕM@„üüÜì1ô<ì20K°TK°T[X½@ÿÀ878Y@0 @ P ` p   ¿ ]#!#oª$ªÕýÕ+ýÕ+ž¾`@1 ‡  ‡   üÌ91/<Ô<<ü<<Ô<<Ä2ì220@   ]!! !3!!!!#!#!5!!5!þÝT%Dh$i g8þ¡R>þ›h gþÛg¡hþÅ`Tþ¾if…þ²‡þaŸþašþ²™þbžþbž™NšŸªþÓm!(/Õ@U" '&( /)/))/B" ) *!††#Љ*Љ- ) " & 0ü<ìô<ü<ôäì1/äìÄÔäì2Äîî99990KSXíí9í9íY"K° TX½0@00ÿÀ878YK° TK°T[K°T[X½0ÿÀ00@878Y#.'5.546753.'>54&´diÒjfÑoÝÉÚÌd]®SS¯\ãÖãÖdtzqá{þÓ---´@AÈ$¬–£¼ëè¯*.þU#´œ©Ãš jXV`ÕþOnZXhqÿã)ð #'3•@6$%&%&'$'B’ ’.’$’ &Œ($‘4'!%   ! + 1 4üÄìôìîöî991ä2ô<äìîöîî0KSXííY"K° TK° T[K° T[K°T[K°T[K° T[X½4@44ÿÀ878Y"32654&'2#"&546"32654&%3#2#"&546ÑWccWUccUžº» º»ü—VcbWWcd1 üZ ž¼»ŸŸ¹º‘”„‚••‚ƒ•Ü»»ÛÛ»¼Ûa•‚„””„–ùó Û»½ÚÛ¼ºÜÿãþð 0Í@–  † †  † †††  !         B  (('•+•'”$‘Œ .  .'.'!!1üìÄÔÔìÆî99999991/ÆäöæîîÆ9990KSXíí9í9í9í9í9íí9í9ííí9Y"²2]@² " ) **&:4D ^YZ UZZY0g{›š™—• “••"™-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z““—•œœŸš › š 2 2°29]]3267 >73#'#"5467.54632.#"ò[UÔ _¦Iþ{ü;Bº h]ühäƒñþΆ†02Þ¸S¥UWžDiƒ;#Q¡X’Â?@ýøYËr„þþ~þã“YW×€ác?}<¢Å$$¶/1oX3gŪoÕB@ „üì1ôì0K°TK°T[X½@ÿÀ878Y@ @P`p ]#oªÕýÕ+°þò{ O@˜—  Üä2ì991üì0K°TX½@ÿÀ878YK°TX½ÿÀ@878Y#&547{†‚ƒ… –•”—æþ>ççþ;åëÆàßÄì¤þòo @˜— Ü<ôì991üì03#654¤ –••– …ƒƒìþ<ßàþ:ëåÅççÂ=JÃðN@,  ™ ™ ‘    Ô<ä2Ü<ä2991ôÔ<ì2Äì2990%#'%%73%Ãþ™g:þ°rþ°:gþ™:PrPßÂÃbËþ‡yËbÃÂcËyþ‡ËÙÛ #@ œ  Üü<ü<ì1/Ô<ü<Ä0!!#!5!®-ýÓ¨ýÓ-ýÓªýÓ-ª-žÿÃþ@ žƒüìÔÌ1üì073#ðÓ¤Rþ¬þÀ@d߃¶œÜÌ1Ôì0!!dý僤ۮþ·ƒüì1/ì073#ÛÓÓþþÿB²Õ-@BŸ/Ä991ôì0KSXííY"3#ªýøªÕùm‡ÿãð #@   ‘Œ üìôì1äôìî0"32'2#"‹œœû þ÷ûûþ÷ PþÍþÌþÍþÍ3343 þsþ†þ‡þsyzáZÕ K@B     ÔìÄüì1/ì2ôìÔì0KSXY"K°TX½ ÿÀ @878Y´]7!5%3!!þJþ™eÊJü¤ªsH¸HúÕª–Jð¥@'B¡”  ‘   üÄÔìÀÀ91/ì2ôìôì0KSXíí9Y"K°TK°T[K°T[X½@ÿÀ878Y@2UVVzzv‡tvust‚†‚‚‚¨¨]]%!!567>54&#"5>32‰ÁüLs3aM§†_ÓxzÔXèE[þôªªªw‘:m—Iw–BCÌ12èÂ\¥pþëœÿãsð({@. † †     “  “#‘Œ£)&  )üÄÄÔìôì991ìäôäìæîîîî90K°TK°T[X½)@))ÿÀ878Y@ daa d!]!"&'532654&+532654&#"5>32?‘£þÐþè^ÇjTÈm¾Ç¹¥®¶•ž£˜S¾rsÉYæ Ž%ÄÝò%%Ã12–„•¦wps{$&´ Ѳ|«d¤Õ Œ@   B     ÜÔ<Äì291/äÔ<ì290KSXÉÉY"K° TK° T[X½@ÿÀ878Y@* *HYiwŠ+&+6NO O Vfuz… ]] !33##!5þþ5þÕÕÉý^%üãÍü3¨þ `ÞÿãdÕu@#†  ‰   Œ¤  üÄÔìÄî1ääôìæîþÄî90K°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y!!>32!"&'532654&#"Ýý ,X,ú$þÔþï^ÃhZÀk­ÊÊ­Q¡TÕªþ’þîêñþõ Ë10¶œœ¶$&ÿã–ð $X@$ †   ¥  ‰"‘Œ% " !%üììôìä1äôäüäîîî90@ËËÍÍÍËˤ²]]"32654&.#">32# !2¤ˆŸŸˆˆŸŸ L›LÈÓ;²káþðâþýþîPL›;º¢¡»»¡¢ºy¸$&þòþïW]þïëæþêyb¥¨hÕc@B üÌÄ991/ôì0KSXííY"K°TX½@ÿÀ878Y@X9Hg°°]]!#!¨ÀýâÓþý3ÕVú+‹ÿã‹ð #/C@%  ' - ‘Œ'£0 $*$ !0üÄìôÄìîî991ìäôìîî990"32654&%&&54632#"$54632654&#"‹¥¥¦¥þ¥‚‘ÿÞßþ‘’£þ÷÷÷þ÷¤H‘ƒ‚““‚ƒ‘Åš‡‡š›†‡šV ²€³Ðг€² "ÆÙèèÙÆat‚‚tt‚‚ÿã‡ð$X@#†  ¥ ‰ ‘Œ%!"" %üìäôìì1äôìæþõîî90@ÄÂÀÀÀÂμé]]7532#"543 !"&2654&#"áLœKÈÓ:²làþûâþ±þåLœ>ˆŸŸˆˆŸŸ¸$& V\ëæþsþ†þŸþ[—º¢¡»»¡¢ºðÃ#@ƒ¦ƒü<ì21/ìôì073#3#ðÓÓÓÓþþ#þžÿÃ# %@ƒžƒ¦  ü<ì2ÔÌ1äüìî03#3#ðÓÓÓ¤R#þýÙ¬þÀ@Ù^Û¦M@*œœœœB¨§$#üì291ôì90KSXííííY" 5Ûûøúþðþ‘þ“¶ѦÑÙ`Û¢@ œœ#ü<Ä21ÔìÔì0!!!!Ùúþúþ¢¨ðªÙ^Û¦O@+œœœœB¨§$#ü<ì91ôì90KSXííííY"55Ùúþð¶þ/¦þ/¶m“°ð$p@+$  †ˆ•‘ƒ   &%ÜÄüìÔìî99991/îöþôîÍ9990K° TX½%@%%ÿÀ878Y¶y z z ]%3##546?>54&#"5>32‡ËËÅ¿8ZZ93ƒlO³a^Ág¸ßHZX/'þþ‘še‚VY5^1YnFC¼98ŸL‰VV/5<4‡þœq¢ L•@2  ©©L43¬0©7¬$©7CM34( (+(I+*(I,=MÜìüìþýþ<Æî991ÔÄüìþíÔÆÅî2Äî990K° TK° T[K°T[K°T[K°T[X½MÿÀMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32úŽ|{zy!<›g¬×Ø«gœ;’¥?@hþÕ°{â`±smiùhZ}þÙ˜¹þ¸€€†ˆ~R½Ôk{KOþÂþè£¤ŽŒ¥¤þHMIùÈÈúKLƒý ß±k¼Pƒ‹A@fþµÁŸþêjhmWQoagƒ}}I½¶J}‡® bæ{þùþÐhÕ º@A       B•    ÔÄ91/<äÔì90KSXííííííííY"² ]@:XvpŒ VXP ghxv|rwx‡ˆ€ ˜™–]] !3#!#¼þî%þ{å9Òˆý_ˆÕý®ú+þÉìÕ C@#• •• ­ . !üì2üìÔì9991/ììôìî90²"]!2654&#!2654&#%!2#!“D££þ¼+”‘‘”þ çú€|•¥þðûýèÉý݇‹Œ…fþ>orqp¦À±‰¢ ˘ÈÚsÿã'ð6@ ¡® •¡®•‘Œ 0üì2ì1äôìôìîöî0´].# !267# !2'fç‚ÿþð‚çfjí„þ­þz†S†íbÕ_^þÇþØþÙþÇ^_ÓHHŸghŸGɰÕ.@• •  2 üìôì99991/ìôì0²`]3 !%! )“ô5þáþËþBŸ²–þhþPþa/ûw.,¦þ—þ€þ~þ–É‹Õ .@•••­   üì2ÔÄÄ1/ììôìî0² ]!!!!!!ɰýÇý9øü>ÕªþFªýãªÉ#Õ )@••­ üì2ÔÄ1/ìôìî0² ]!!!!#ÉZýpPý°ÊÕªþHªý7sÿã‹ð9@ ••¡®•‘Œ43 üìüäüÄ1äôìôìþÔî990%!5!# !2&&# !26Ãþ¶uþæ þ¢þu‹^’opü‹þîþík¨Õ‘¦ýSU™mn™HF×_`þÎþÑþÒþÎ%É;Õ ,@•­ 8  üì2üì21/<ä2üì0²P ]3!3#!#ÉÊÞÊÊý"ÊÕýœdú+Çý9É“Õ9·¯üì1/ì0K°TX½ÿÀ@878Y@ 0@P`Ÿ]3#ÉÊÊÕú+ÿ–þf“Õ M@ •° 9 üìä991äüì990K°TX½ ÿÀ @878Y@ 0 @ P ` Ÿ ]3+53265ÉÊÍãM?†nÕú“þòôª–ÂÉjÕ ï@(B¯  üì2ÔÄ91/<ì290KSXííííY"²]@’ ((764GFCUgvwƒˆ”›ç    (+*66650 A@E@@@ b`hgwp ‹‹Ž š¶µÅÅ×Öèéèê÷øù,]q]q3! !#ÉÊžýþöý3ÊÕý‰wýHüãÏý1ÉjÕ%@ •:üìì1/äì0@ 0P€€]3!!ÉÊ×ü_ÕúÕªÉÕ ¿@4  B ¯   >  üìüì91/<Äì290KSXííííY"²p]@V   && & 45 i|{y €‚‚  #,'( 4<VY ej vy •›]]! !###É-}-ÅþËþÄÕüøú+üúáÉ3Õ y@B¯6 üìüì991/<ì2990KSXííY"² ]@068HGif€ FIWXeiy…Š•šŸ ]]!3!#É–ÄþðýjÄÕûáú+áûsÿãÙð #@•• ‘Œ 3üìüì1äôìî0"32' ! 'ÜþýÜÜþÿÜ:xþˆþÆþÅþ‡yLþ¸þåþæþ¸HH¤þ[þžþŸþ[¤bb¥ÉÕ:@••   ? üì2üì91/ôìÔì0@ ?_¯]32654&#%!2+#“þššþ8ÈûþÿûþÊ/ýÏ’‡†’¦ãÛÝâý¨sþøÙð R@*  B ••‘Œ    3üìüì9991Ääôìî990KSXíí9Y""32#'# ! 'ÜþýÜÜþÿ? ôÝ!#þÅþ‡y;:xÑLþ¸þåþæþ¸HHúÏþÝï¥ab¥þ[þžþüþŽÉTÕ±@5  B• •   ?  üì2üÄì99991/<ôìÔì9990KSXíí9Y"²@]@Bz%%%&'&&& 66FFhuuwˆˆ˜˜]]#.+#! 32654&#A{>ÍÙ¿J‹xÜÊÈüƒý‰þ’••’¼~þh–bý‰ÕÖØºOýƒ…‡ÿã¢ð'~@<    B ¡”••”%‘Œ( "-"(ÜÄìüìä99991äôäìîöîÆ90KSXí9í9Y"²)]¶)/)O)].#"!"&'532654&/.54$32HsÌ_¥³w¦zâ×þÝþçjï€{ìr­¼‡š{âÊõiÚ¤Å76€vce+Ù¶Ùà0/ÐEFˆ~n|-À«Æä&ÿúéÕJ@•@@Ôäüä1/ôì20K° TX½@ÿÀ878Y@  @ p Ÿ ]!!#!ïýîËýîÕªúÕ+²ÿã)ÕK@ •Œ  8Aüìüì1ä2ôì99990K°TX½@ÿÀ878Y¶Ÿ]332653! ²Ë®Ã®ËþßþæþåþßÕüuðÓÓð‹ü\þÜþÖ*$hÕ·@'B¯ÔÄ91/ì290KSXííííY"²P]@b*GGZ}ƒ *&&))% 833<<7HEEIIGYVfiizvvyyu€˜—)]]!3 3JýÆÓÙÚÒýÇÕûéú+D¦Õ {@I      B ¯    ÔÌ91/<ì2290KSXííííííííY"²]@ò  ($ >>4 0 LMB @ Yjkg ` {|€ –•     !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx  †‡ˆ‰… Š —Ÿ¯[]]3 3 3# #DÌ:9ã:9Íþ‰þþÅþÂþÕûîûîú+úð=;Õ ]@F      B ¯   ÔÄÜÄ91/<ì290KSXííííííííY"K° TK° T[K°T[X½ ÿÀ @878Y@¸ '' 486 KX[fkww †€‡‹… ”—–     &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x €€ƒˆ…„ƒ ”——•“ Ÿ ¯ @]]3 3 # #ÙsuÙþ Ùþ\þYÚÕýÕ+ý3üø{ý…ÿüçÕ”@(B¯@@ Ôäüä91/ì290KSXííííY"² ]@<5000F@@@QQQe„“ &)78@ ghxp Ÿ ]]3 3#Ùž›ÙýðËÕýšfüòý9Ç\Õ ›@B••B ÜÄÔä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878Y@@ )&8HGH    / 59? GJO UYfio wx Ÿ ]]!!!5!s•üPÇû=°ügÕšûoªš‘°þòXS@©²©±CÜüÌ21üìôì0K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y!#3!°¨ððþXùüÿB²Õ-@BŸ/Ä991ôì0KSXííY"#ªªýøÕùm“Çþòo<@©²©±Cü<Üì1üìôì0K°TK°T[X½ÿÀ@878Y!53#5oþXïïøÞÙ¨ÛÕ@ ÜÌ91ôÌ290##¼ÉþHþHÉÕýÓ‹þu-ÿìþþ¬µ©ÄÄ1Ôì0!5ûØþ¬ªð‰f1@ ´³DÜì1ôì0K° TK°T[X½ÿÀ@878Y #o™þºfþŠv{ÿã-{ %¼@'  ©¹ †º¹#¸Œ   E&üìÌÔì22991/ÄäôüôìÆîî9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p'…‡‡‡ ‡!…"' 'ð'000 0!@@@ @!PPP P!``` `!ppp p!€€€ €!]]"326=7#5#"&5463!54&#"5>32¾ß¬o™¹¸¸?¼ˆ¬Ëýû§—`¶Te¾Zóð3f{bsÙ´)LýªfaÁ¢½À‹..ª''üºÿ㤠8@¹  ¹Œ¸—G Füì22ôì1/ìäôÄìÆî0¶`€ ]4&#"326>32#"&'#3å§’’§§’’§ýŽ:±{ÌÿÿÌ{±:¹¹/ËççËËççRdaþ¼þøþøþ¼ad¨qÿãç{?@†ˆ† ˆ ¹¹¸Œ HEüä2ì1äôìþôîõî0@ € ].#"3267#"!2çNP³ÆÆ³PNM¥]ýþÖ-U¢5¬++ãÍÍã++ª$$>:#qÿãZ8@¹¹Œ¸—G Eüìôì221/ìäôÄìÄî0¶`€ ]3#5#"3232654&#"¢¸¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶^ùì¨daDDaþËççËËççqÿã{p@$ †ˆ©¹ »¹¸ ŒKEüìôìÄ91äôìäîîôî90@)?p Ðð?????,// , ooooo ]q]!3267# 32.#"ü² Í·jÇbcÐkþôþÇ)ü⸥ˆš¹^Z¾Ç44®*,8 CþÝÄ—´®ž/øp@ ©‡—¼    Lü<Äü<ÄÄ991/ä2üìî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y¶@P ]#"!!##535463ø°cM/þѹ°°®½™Phcü/ÑN»«qþVZ{ (J@#  †¹¹&#¸'¼ ¹½& G E)üÄìôì221/ÄäìäôÄìþÕî990¶`*€* *]4&#"326!"&'5326=#"3253¢¥•”¥¥”•¥¸þþúa¬QQžRµ´9²|ÎüüÎ|²9¸=ÈÜÜÈÇÜÜëþâþé³,*½¿[cb::bcªºd4@ ‡¸ — N  Füì2ôì1/<ìôÄì90²`]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡ýžedïÁy+@¾±¼Fü<ì21/äüì0@  @ P ` p ]3#3#Á¸¸¸¸`û éÿÛþVy D@ ¾ ‡½¼ ±O  Fü<ì2ä991ìäôìî990@ @P`p]3+532653#Á¸£µF1iL¸¸`ûŒÖÀœa™(麜 ¼@)B¼— F üì2ÔÄ91/<ìä90KSXííííY"² ]@_ ')+Vfgsw‚‰Ž“–—£    ('(++@ h` ‰…‰š—ª§¶ÅÖ÷ð÷ð]q]33 ##º¹%ëý®kðýǹüiãýôý¬#ýÝÁy"·—Füì1/ì0@ @P`pð]3#Á¸¸ùìº{"Z@&  ‡ ¸¼PPF#üì2üüüì91/<<äô<Äì290@0$P$p$$ $ $¿$ß$ÿ$ ]>32#4&#"#4&#"#3>32)EÀ‚¯¾¹ru¦¹rw¦¹¹?°yz«‰|võâý\ž¡œ¾¤ý‡ž¢›¿£ý‡`®gb|ºd{6@ ‡¸ ¼ N  Füì2ôì1/<äôÄì90´`Ï]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡`®edïqÿãu{ J@¹¹ ¸Œ QEüìôì1äôìî0@#?{{   {  { ð]"32654&'2#"s”¬«•“¬¬“ðþîðñþïßçÉÉçèÈÇéœþÈþìþíþÇ98ºþV¤{>@¹¹¸Œ½¼ GFüì22ôì1äääôÄìÄî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý® ªdaþ¼þøþøþ¼aëËççËËççqþVZ{ >@¹  ¹¸Œ½¼ GEüìôì221äääôÄìÆî0@ `€ à]32654&#"#"3253#/§’’¨¨’’§s:±|ËÿÿË|±:¸¸/ËççËËççý®daDDadªùöºJ{0@  ‡¸ ¼ FüÄì21/äôìÄÔÌ90´PŸ].#"#3>32JI,œ§¹¹:º….´˾ý²`®fcoÿãÇ{'ç@<  S  SB †‰†‰¹¹%¸Œ( R"E(üÄìÔìä99991äôìþõîõî90KSXí9í9Y"²']@m   . , , , ; ; ; ; $( ( *//*(() )!$'† † † †      '/)?)_))€)) )ð)]]q.#"#"&'532654&/.54632‹N¨Z‰‰b”?Ä¥÷ØZÃlfÆa‚Œe«@«˜àÎf´?®((TT@I!*™‰œ¶##¾55YQKP%$•‚ž¬7òž8@©¼‡  Fü<Äü<Ä2991/ìô<Äì2990²¯]!!;#"&5#53w{þ…Ks½½Õ¢‡‡žþÂý ‰NšŸÒ`>®ÿãX`6@ ‡Œ ¼  NFüìôì21/ä2ôÄì90´`Ï]332653#5#"&®¸||•­¸¸C±uÁȺ¦ýaŸŸ¾¤{û ¬fcð=`@'B¿ÔÄ91/ì290KSXííííY"K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@ŽHj{†€‘¤  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz……‰‰‰†––—š˜˜—¨§°Àßÿ>]]3 3#=Ã^^Ãþ\ú`üT¬û V5` @IU U U U   B ¿    ÔÌ91/<ì2290KSXííííííííY"K° TK°T[K°T[K°T[K° T[X½ ÿÀ @878YK° TK° T[K°T[X½ @ ÿÀ878Y@ÿ" 5 IIF @ [[U P nnf yy‡™˜” ¼¼ÎÇÏ         %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } ‡ˆ——”“œ›˜˜™@/– Ÿ¦¦¤¤««©©«¤ ¯µ±½»¸ ¿ÄÃÌÊy]]333# #V¸æåÙæå¸þÛÙñòÙ`ü–jü–jû –üj;y` Z@F      B ¿  ÔÄÔÄ91/<ì290KSXííííííííY"K° TK°T[K°T[K°T[X½ ÿÀ @878YK°TX½ @ ÿÀ878Y@˜   & =1 UWX f vzvt ‚ ™Ÿ—’ ¦©¯¥£       )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x ›”«¤° Ï ß ÿ /]] # # 3 dþkªÙþºþºÙ³þrÙ))`ýßýÁ¸þHJþq=þV`¢@C        B  ‡½ ¼  ÔÄÄ91ä2ôì9990KSXíííííí2Y"K° TK°T[X½ÿÀ@878YK°TX½@ÿÀ878Y@ð     # 5 I O N Z Z j ‡ € “        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx‰Š … … ‰ ‰‰™ • • šš¤ ¤ ««°Ïßÿe]]+5326?3 3“N”|“lLT3!þ;Ã^^ÃhÈzšH†TNü”lXÛ` ´@B©¼© ÜÄ2Ä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878YK°TX½ ÿÀ @878Y@B&GI  + 690 @@E@@CWY_ ``f``b € ¯ ]]!!!5!qjýL´ü}´ýe`¨üÛ“¨%þ²$‚@4 %   ! © ©À ©±% $  C %Ô<Äü<Ä299999991üìÄôìî99999990K° TX½%ÿÀ%%@878Y²&]#"&=4&+5326=46;#"3>ù©lŽ==k©ù>DV[noZV¾”Ýï—ts•ðÝ“XøŽŽœøXþ®·±Ôì1üÌ0#®ªøþ²$ž@6%   ©©#À©±%#C %Ô<Ä2ü<Ä99999991üìÄôìî99999990K° TX½%@%%ÿÀ878YK°TX½%ÿÀ%%@878Y²&]326=467.=4&+532;#"+FŒUZooZUŒF?ù§lŽ>>Žl§ù?¾VøœŽŽøŽW“Ýð•st—ïÝ”ÙÓÛ1#@ œœ ÔÄ1ÔüÔìÀ990#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©1²OD;>MS²OE<>LÿÿhN'$¼uhm !Ë@T   !!  ! !!!B  Á • Ž  !  VV!"ÔÄÔì2Ôî299999991/<æÖîÔî9990KSXííííííííY"² #]@  s › P#f iu {yyv v!€# ]]4&#"326!.54632#!#TY?@WX??Y˜þð!þX=>Ÿsr¡?<Òˆý_ˆÕZ?YWA?XXþóýN)sIs ¡rFv)ú‹þÿÿsþu'ð'&Ý-ÿÿÉ‹k'(žuÿÿÉ3^'1þuÿÿsÿãÙN'2'uÿÿ²ÿã)N'8îuÿÿ{ÿã-f'DRÿÿ{ÿã-f'DCRÿÿ{ÿã-f'D×Rÿÿ{ÿã-'DŽRÿÿ{ÿã-7'DØRÿÿ{ÿã-'DÜRÿÿqþuç{'FÝÿÿqÿãf'H‹ÿÿqÿãf'HC‹ÿÿqÿãf'H׋ÿÿqÿã'HŽ‹ÿÿof'ÖÿÿÿÿǦf'ÖCÿÿÿÿÞ\f'Ö×ÿÿÿÿôF'ÖŽÿÿÿºd7'Qؘÿÿqÿãuf'Rsÿÿqÿãuf'RCsÿÿqÿãuf'R×sÿÿqÿãu'RŽsÿÿqÿãu7'RØsÿÿ®ÿãXf'X{ÿÿ®ÿãXf'XC{ÿÿ®ÿãXf'X×{ÿÿ®ÿãX'XŽ{9ÿ;ÇÕ '@¹  YW Y Ô<ìü<ì1äôÔ<ì203!!#!5!¨°oþ‘°þ‘oÕþ\™û£]™Ãu=ð  @ÃÄà ‘ Z[ZÜìüì1ôìüì0"32654&'2#"&546PnnPPnoO@v+..¹†‡´¸ooPOmmOOp1.-rB„·´‡†º¬þÇ#˜!Q@+  †ˆ †ˆ ¹ ¹¸Œ"  "ÜìÔ<Ô<<ì221äô<ÄìÄþôîõî9990%&&'667#&73¦“¤¤JˆDF‰HA‰Mfñþ÷ ñfI‰ƒX⸹⡬)*ü *'ª#þä 32þá!bð`@!† ©  ”‘   Ü<ÌÌü<ÄÔÄ1/ì2ôäìÔ<î2î990K° TX½ÿÀ@878Y´66].#"!!!!53#535632NLˆ=”t‡þy-üìÇÇÖè=—´¶))›Ô×þ/ªªÑîó\ÿ=¢ð >‘@54&.#"#"&'532654/.5467.54632{?>‹ú?>ÌS8alÎÓƒ\]>9Ì­IšXW”:fqÝÖ€][;;ȦI™¨.Z.L…‡-[.Kˆ“¤''PGZswšeZŒ54m@ލ¤''TLf{x™f[1,pE‚Ÿ3Ñ…! · Ç \ Ôì1Ôì04632#"&3­~|«¬}}¬ú|««|}¬¬žÿ;9Õ %@Á]] ÔÔüÜì91Ä2ôì90!###&&54$yÀ¾Ž×ëÕùfùáNݸ¾èºÿã¬/š@0-'!  *†¹*¹—Œ.  !' $'$-F0üÄüÌÆîÔîî99991/äþîþÕî990@@'(Š Š     ! "&  : :!MM I!I"jj ¥¥¦ ]]4632#"&'532654&/.5467.#"#ºïÚÐÛ—¨:A9¦`áÓ@ˆIPŒAtx;e\`W§—ƒq‚ˆ»qÈÛèàs`/Q*%jŽd¬·¤_[?T>7;‡[¬gp‹ƒû“åÍ/8L`@6EBC?2ÉH0É9JCÊ 9ÊÉÈ É$HE301BKL?gwyVpMIßÑ`3þœDåÍ/IC@&=Ë>:ÌAÊ$1Ë04ÌGÊÉÈ$É 7aD=0^* D^ JÜÌüìþí2î1/îöþýîÖîýîÖî02#"$'&5476$"32676654&'&&&&#"3267#"&54632˜mmllmmþù˜˜þùmmllmm˜ƒâ^^``^^⃄ã^]]^\^ã§B‚B•§«›@zBC‰FØûûØIˆÍnmmþúš˜þûmmnnmm˜šmmng^^^å‚ã^^__^]⃅ã]^^õ! ¯Ÿ®"ôÐÑò'“FÕ >@!  É  b b cbcÔäüäÔìÔì91ô<<ì2Ô<<Ä903#######5J®¤ªqÃ7ËrqËrÉÕÿý¾äþÑ/þB^þä^sîRf1@ ´³DÔì1ôì0K° TK°T[X½ÿÀ@878Y3#‹Çþº™fþˆ×F)’@ÎÍddÜüÔì1ü<ì20K° TK° T[X½@ÿÀ878YK° TK° T[K°T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@````pppp]3#%3#^ËËþyËËÊÊÊÙ'ÛÝ>@" Ïœ Ï œ  Ü<Ä291Ô<Ì2ü<ìþ<ì990!!!!!'7!5!7!Ù}®/þHÃ{üúþþ}®þÕ¶Ãý‡¢;fÕ¨ðªþÇfÓªðHÕ‡@9  B• ••••­    ÔÔ<ì2ÔÄÄ91/<ììÄôììîî0KSXííííY"²€]@gww† …– ¿ ]!!!!!!#!5ýÇý9øü=ýð Íq‹þ¶ËÕªþFªýãªþÕžüðfÿºå +ž@< +,  )&  *&•& •‘&Œ,+,* # )#3,üìüìÀ999999991äôìîÀÀ99999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''¶ý3>¡_Ü'y=¡_Üþý''†NOy;‚ÝW¢fªNPþˆþÆ€Ý[¢gXü²@CHp¸¸@Cþ¸þåp¼Džf b¥MK¿YÆgþöžþŸþ[KK¿XÝÝÏî /ÿ@- !$'!!0 $*0ÔÄÔÄ99991ÔÄÔÄÀ9990@¾     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV´° °!°"°&°'°(´)]]32654&#".#"326#"&54632>32#"&“1†Te€vYR…Ä1…UfvYR†F^ˆº§†_™HDža†¼§†^•/XZ‡ie†‡7XX„je†ˆ‡ߦ¯Ø~ŠŠƒá§¯ÖwÙÛ .@МР œ   Ô<ì2ü<ì21/ìÔ<ìü<ì0!!#!5!!!®-ýÓ¨ýÓ-ýÓúþþ}ªþ}ƒªƒû¦ªÙÛ¨ T@.œœœœBѧœ $# ü<ì2291/ìôì90KSXííííY" 5!!Ûü@Àúþúþúþøþëþî²pªoüªÙÛ¨ V@/œœœœBѧœ$ # ü<<ì291/ìôì90KSXííííY"55!5ÙúþÁAúþø°þ‘ªþ²ýǪªRÃÕÆ@F  B Ó Ó   fe f eÔ<ì2ìüì2ì99991/ä2Ô<ì2Ô<ì290KSXííííY"K° TX½ÿÀ@878Y@(†¦ µ' ' ')((79‡ ˆ¦ ¥ª©]]!#!5!5'!5!3 3!!!þcÉþ` Tþ´þþ{y¿þÂþµTŸÇþ9Ç{3›{JýD¼ý¶{›3®þVå` M@% ‡Œ ¼½!   NF!üì2ôìÄ91ää2ô<ìÜÄ990¶"`"Ï"]3326533267#"&'#"&'®¸Š‡”•¸#% )I#ER2‘bf*þV ýH‘”¨¨ü¢<9 ”NPOONNý×hÿçÁ-)b@'! '!Õ* $$*ÔÌÜÌ9991äÌÜÌÎÎ990K° TK° T[K°T[K°T[K°T[X½*@**ÿÀ878Y>54&#"#"&54632#"&54324&#"32ôIH7$$0e´ÖþßÕ˜ËÝ¢e‚ WOmVPmmW£Kƒt,>bþÊþùþ±þFØ£Æ[àt}þþÏt{þw;Á ]@    ÔÄ91ÄÔÌÎ990@0QVPZ spvupz €€ Z pp{ t €€ ]]!! !!5 7êüA ýJïúÞÕýIÁÁý3ýÀ•!ãœþwqÁ@×Ö¯ggÔìÔì1üìì20!#!#œÕðý ïÁø¶}ùƒÿáÿðª/#Ë@1 ÚÙ"ØÕ $ #" #h#$ÔÔÔì9999991/<äôì22î9990K° TX½$ÿÀ$$@878Y@V             ##(]]#3267#"&5467!##"#>3!‡¶i/7.%7vy"PþºÂµÃ)6<  ¥y‘þJ\:1fd.¡xüo‘@E¦}/þú%&@ Û Ûܱ& iji&Üìüì1üìÜäÞä026732#"&'&&#"#"&546327j ¾ÊPd@7*8  k½ÄOeD=!0 þú°l9¼TA6?&#Hý•Ánþ!þbSA8?SsÕ;ð)_@3(%ãÝá%Ý ßÞÝ à‘* "(kl"k *ÜìÌüì22ÀÀ9991ôäüôìÄîíÖîî99990!!#5#"&5463354&#"56632"32655‹°ýP®•,]€˜¿¼¶uu>ˆDI‘E·³þì¡~bRh‚P{¸þ@p?D‡q‡Š[[""°ðCO@Mr`Õdð.@ãáÝ àÝ‘ klk Üìüì991ôìôìüì0!!2#"&546"32654&‹°ýPX³Îγ³Ðгi~hi}|P{Ý¿¿Ûܾ¿Ýs¡ˆ…  …‰ NÏç@@" å‘å  mm  ÔììÔììÀÀ9991/<ì2ôì0%!5654#"!5!&5! Ïý¨±ÆþøØØþ÷Dzý¨?ž‘1/Ž¡²²²aLÊð"þÝïÊþ´a²²‹*¸>ŠþwþËÂþØ{ÿão{3>@C'-%= 4©%†ˆ©:¹.†-º*¹»1 ¸Œ%?47&%7& =&-7"E?üìÌÔü<ÔìÄ999991Ää2ô<Ääü<ôìÄî2îôîî9990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0…+…0€@@ @°@À@Ð@à@à@ð@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/€,€-€.€/]q].#">32!3267#"&'#"&5463!54&#"5>32"326=¶¥‰™¹DJÔ„âü² Ì·hÈddÐj§øMIؽÒýû§—`¶Te¾ZŽÕï߬o™¹”—´®ž0Z^þÝúZ¿È55®*,ywxx»¨½À‹..ª''`þf{bsÙ´)Hÿ¢œ¼ +ä@<+,&  )&  *&¹& ¹¸&Œ,+,* # #Q)E,üì2ôì2À9999991äôìîÀÀ99999990@p(?-YVUV jf!{    { z{ {!"#$%{&›•%¨ -ð-&YVUZ(ifej(ztvz(‰•š$¢­$]] 32654&'.#".5327#"&''‰þ)gA“¬\*g>—©}66ñ]ŸC‹_’56þîð`¡?‹`!ý°*(èÈOuš))ëÓHn.—MÅw834¨O³MÆxþíþÇ43¨Nÿã¬Õ $†@/ †ˆ !ƒ# •Œ#%" " "!& %ÜìÔüìÔì99991äôìþÍôî9990K°TK°T[K°T[X½%ÿÀ%%@878Y@ ttttv]33267#"&546?>7>5#53ô¾7ZZ:3ƒmN´`^Àg¸àIYX0&ÄÊÊDœe‚WX5^1YnFC¼98ŸL‰VV/5<6þ5Õ b@ƒ ü<ì2991/ôüÌ0K° TX½ @ ÿÀ878YK°TK°T[K°T[X½ ÿÀ @878Y¶ P ]#53#3ËËË¢×þú+eþ›ÙÛ^@ œÜÔì1ÔÄì0!#!Ù¨û¦^ýÁ•=ÿ×} *@    ÔÌ91ÔÌÄ903##'%\½sý®BþÁ}}`ùºs-Pbý;þV#Š@@   B   ©Šæ©Šæ©!—$  $ÔÌ91Ä2Äüìôìîöîî299990KSXí2í9Y"K° TX½$ÿÀ$$@878Y.#"!!#"&'53267#5!>32&P,`r<þÃ:¼º:d/4a/am"‰ø?$Æ—5dð¤z„þÉý…þãÓ¦!!‰¦­J·ÃÙÛô;?@.9*-" *œ19œ"œ œ<-<Ô<Ä21ÔìÔìÜüÔìÀ9999990#"'&'&'&#"56632326#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©gi³an’ ›^X¬bi³an“ ›^V©o³NE;=LT³NE;=KÚ²OE;=LS²NE;=Kÿú`Á8@ÔÌ91/ÄÌ90@cmpxyvn]] !3!¬þ^DýïàCúšîûÄú?ž%# †@Ièèèè è è è  è B  ç¦ o o nüü<Ôì2991ô<ì2990KSXííííííííY"55%þÓ-þ+#þÓ-þ+#¿þôþô¿¢R¢¿þôþô¿¢RÁH# †@I è è è è èèèèB  ç¦ o opü<üÔ<ì991ô<ì2990KSXííííííííY"5%5ÁÕþ+-þÓ²Õþ+-þÓ#þ^Rþ^¿  ¿þ^Rþ^¿  ìþ #@ƒ   ÔüÔìÔì1/<<ì220%3#%3#%3#–ÔÔ©ÕÕú­ÕÕþþþþþþÿÿhk'$¼uÿÿh^'$¼uÿÿsÿãÙ^'2'us Õ;@•••­   üìÔÄÄÔì299991/ìì2ôì2î0!!!!! !# !3úýÇý9øû×þOþA¿±gþ¿þÀ@AÕªþFªýãª|pm|ªþáþàþßþßqÿãÃ{'3„@1†ˆ ©. ¹(¹»"%¸Œ4"1 K1 Q+E4üìôüôìÄ9991ä2ô<Ääì2Äî2îôî90@%?5_5p5Ÿ5Ï5Ð5ð5????? ooooo ]q].#"!3267#"&'#"32>32%"32654& ¤‰™¹Hü² Ì·jÈbdÐj òQGÑŒñþïñŒÓBNèâú°”¬«•“¬¬”˜³®ž5Z¾Ç44®*,nmnm98olkpþ݇çÉÉçèÈÇééy¶©é/Æ1üì0!!üyéyµ©/Ì1Ôì0!!øy®émÕ '@ž   ÜüÌÔÌþÔÎ1ô<ì20#53#53Ó¤RšÓ¤Ré­?þÁ­­?þÁ®émÕ '@ ž  ÜìÔÌÜîÔÎ1ô<ì203#%3#Ó¤RšÓ¤RÕ¬þÀ@¬¬þÀ@®éÓÕ@ žÜüÔÌ1ôì0#53Ó¤Ré­?þÁ²þ×Õ@ žqÜìÔÌ1ôì03#Ó¤RÕ˜þÁ?Ù–Ûo )@êêœ r ÜÔ<ü<Ä1ÔÄüÄîî03#3#!!ßööööýúúþoöþõAªþ#îu"@ÔÌ91ÔÌ990 úþþôþ þ üÏüÇ9%ûÛûÓ-ÿÿ=þV'\Ž^ÿÿÿüçN'<suþ‰ÿãÍð+@BŒ‘ÔÌ1ää0KSXííY"3#- ü\ ðùó^R¼²#/ƒ@I -'! - -¹ëì'¹ë!0 *$0* $ $(st*(s0Üäìôäì9999999991ÔäìôäìÀ9999999907'#"&''7&&5467'766324&#"326{ÏrÎ%$&(ÑrÏ;t=:x=ÏqÏ%%&&ÏsÏ7t@?s9ÏqÏ(&%%ÏsÎ>v:@t8ÎsÏ'%$þ|pššprœžs#G@%èèèèBç¦onüì291ôì90KSXííííY"5sþÓ-þ+#¿þôþô¿¢RÁ–#I@&èèèèBç¦opü<ì91ôì90KSXííííY"5ÁÕþ+-þÓ#þ^Rþ^¿  /J›@( ©‡¾±— ¼ Lü<Ä2Äü<Äî2991/<æ2îþîîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€€€ Ðï]]#!##53546;#"3#J¹þ¹°°­³¹°cMù¹¹`û Ñü/ÑN·¯™Phc²é/J„@! © ‡— ¼   Lü<ÄÄü<Äî991/<æ2þîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€ € € Ðï]!#!"!!##53546J¹þ·cM/þѹ°°®ùì{Phcü/ÑN»«9ÿ;ÇÕ>@ ¹¹  ÂY W Y Ô<<ì2ü<<ì21äôÄ2Ä2î2î20%!#!5!!5!3!!!Çþ‘°þ‘oþ‘o°oþ‘oßþ\¤š™¤þ\™ýáÛH®F·ƒÔì1Ôì03#ÛÓÓFþ®ÿÓþ@ žƒÔìÔÌ1üì0%3#Ó¤Rþ¬þÀ@®ÿmþ '@ žƒ   ÜìÔÌÜîÔÎ1ü<ì20%3#%3#šÓ¤RþfÓ¤Rþ¬þÀ@¬¬þÀ@qÿã Lð #'3?K®@D$%&%&'$'B@’ .’(’F’4 :&Œ$‘L%IC'1+C =  1 =I 7+ ! LüäìÔÄìäîîöîî991ä2ô<<ä2ì2îöîî20KSXííY"K°TK° T[K° T[K° T[K° T[K°T[X½L@LLÿÀ878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&ôWddWUccUžº» º»ùtž¼»ŸŸ¹º% üZ VcbWWcd²žº» º»ŸWccWUcc‘”„‚••‚ƒ•Ü»»ÛÛ»¼ÛàÛ»½ÚÛ¼ºÜùóŽ•‚„””„–ýŸÜ»»ÛÛ»¼Û”„‚••‚ƒ•ÿÿhm'$¼uÿÿÉ‹m'(žuÿÿhk'$¼uÿÿÉ‹N'(žuÿÿÉ‹k'(žuÿÿ¢k',ÿ/uÿÿÿþ`m',ÿ/uÿÿXN',ÿ/uÿÿ;ºk',ÿ/uÿÿsÿãÙk'2'uÿÿsÿãÙm'2'uÿÿsÿãÙk'2'uÿÿ²ÿã)k'8îuÿÿ²ÿã)m'8îuÿÿ²ÿã)k'8îuÁy` ·¿Füì1/ì0@ @P`p]3#Á¸¸`û Áî?f7@ ´³uÜì91ôì290K° TK°T[X½ÿÀ@878Y3#'#¶”õ‹´´‹fþˆõõ¶J7c@$  Ãà íVwVvôìüì99991ü<üÔ<ì99990K° TK° T[X½ÿÀ@878Y'.#"#>3232673#"&ü9! &$}f[&@%9! &$}f[&@Z7IR‡“!7IR‡“Õb+ö/·ïîÔÌ1üì0K° TK°T[X½ÿÀ@878Y!!ÕVýªö”Ç)9H W@ ð³VVÜìÔì1ô<Ôì0K° TX½ÿÀ@878YK°TK°T[K°T[X½@ÿÀ878Y332673#"&Çv aWV` v ž‘‘žHKKJLšDf,@ ÎÍdÔì1üì0K° TX½ÿÀ@878Y3#šÌÌÌîá _@Áò ÁñV xVÔìôì1ôìôì0K° TK° T[X½ÿÀ@878YK° TK° T[K° T[X½ÿÀ@878Y4&#"3267#"&54632˜X@AWWA@XzŸssŸŸssŸô?XW@AWX@s  ssŸŸ#þuÁ@  ó' ÜÔìÔÌ1/ÔüÄ90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ ƒ0.W=ðî®fB@´³ÔÜÔÌ991ô<ì20K° TK°T[X½ÿÀ@878Y3#3#ü²ø‡ªß‰fþˆxþˆLþuÁ @  óô 'ÔìÄÔÌ1/üüÄ90!33267#"&546¸w-+76 >&Dzs5=X..… W]0iÁî?f7@ ´³uÜì91ô<ì90K° TK°T[X½ÿÀ@878Y373¶õ‹´´‹õîxõõþˆÿòuÕ ?@ •  : yô<ìÄü<Ä991/äì90´0P]3%!!'7ÓË9Pþw×ü^”MáÕý˜Ûoþîýãª;jnžH ^@ — z z Ô<äü<ä991/ì90K°TX½ @ ÿÀ878Y@ @ P ` sz p à ð ]37#'7Ǹ}Lɸ{JÅý¦ZjüãšXjÿÿ‡ÿã¢m'6‹uÿÿoÿãÇf'Vàÿÿ\m'=¾uÿÿXÛf']àþ¢®˜@ õõÜ<ì21ÔìÔì0##®ªªª˜ý öý ö ºÕ g@  © ••  2  yô<ì2ÄôìÄ91/Æ2îöîî20@( °Ÿ Ÿ Ÿ Ÿ ŸŸŸŸ¿ ¿ ¿ ¿ ¿¿¿¿]]! )#53!!3 !Ó ±–þiþPþ`ÉÉËPþ°ó5þáþËÕþ—þ€þ~þ–¼ãþýê.,qÿãu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ##¹ ¹Œ#±)&' ! (%#" QE)üìôì99999991ìÄôìî9990KSXÉÉÉÉííííY"²?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x" *ð*']].#"32654&#"5432''%'3%F2X)§¹®’‘®6 ~rþäæçþåÝ4*ŸþÁ!µäM!þÙ“ØÃ¼ÞÞ¼z¼&þà­ÿþÉ7ÿú7´kc\Ì‘oabÿÿÿüçk'<suÿÿ=þVf'\^ÉÕ =@• •ö  ? üì22üì91/ôüìÔì0@ ?_]332+#32654&#ÉÊþûþÿûþÊÊþš™ŽÕþøáÜÜâþ®'ýÑ’††‘ºþV¤>@¹¹Œ¸½— GFüì22ôì1ìääôÄìÆî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý®¾ý¢daþ¼þøþøþ¼aëËççËËççÙ-Û×¶œÔÄ1Ôì0!!Ùúþת?œÅ …@M œ  œœœœœ œ œ B   Ô<Ì291Ô<Ì290KSXííííííííY" '7œþ7Éwþ5þ5vÈþ8vËËLþ5þ7yËþ5yÉËyþ5ˉœÅß ,@Ý ÝÝ ÷‘ |]|| Üôäüä1ôììÔìî2035733!œÌßæ‰Íý× c)t'ý+n^œ´ðJ@$}}BÝÝ÷ Ý‘~ÜÄÔÄì91ôÄìüìî90KSXí2íY"!!56754&#"56632 ¨ýª"?XhU4zHM…9‘®þµ8rn81^BQ##{„l‹þä0bÍð(H@' Ý Ý Ý Ý ø÷Ý ø#‘)~&~ )ÜÄÄÔìÔì9991ôäìüäìÔìîî90#"&'532654&##532654&#"56632 \e¾±9}F4wCmxolV^^ad_(fQI€7©Z`mR|†yOFJLl?<:=svcE`ÿÿ‰ÿãð'ð'¼5 ‹ýdÿÿ‰ÿã?ð'ð'¼5ñ‹ýdÿÿbÿãð'ò'¼5 ‹ýdÿÿsÿã‹m'* uÿÿqþVZH'JÚ‹ÿÿÉ•P', ÿ/uÿÿ‡þu¢ð'6Ý‹ÿÿoþuÇ{'VÝÿÿsÿã'k'&-uÿÿqÿãçf'F‰ÿÿsÿã'm'&-uÿÿqÿãçf'Fà‰qÿãô$J@$Ó ù"¹¹ Œ¸—   GE%üìô<Äü<Ä1/ìäôÄìÄîý<î20¶`&€& &]!5!533##5#"3232654&#"¢þºF¸šš¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶N}““}úü¨daDDaþËççËËççd߃¶œÜÌ1Ôì0!!dý僤ÛH®F·ƒÔì1Ôì03#ÛÓÓFþÿãð1@: Ó"+Ó ¡®•¡®•/‘Œ) 2+"!)#&  , & &*!/<ÔÄ2üÄÄ99999999991Ä2äôìôìîöîî2Ý<î20K° TK° T[K° T[K°T[K°T[K°T[X½2ÿÀ22@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-ŸŸŸ Ÿ Ÿ Ÿ Ÿ ŸŸŸŸŸŸ–Ÿ Ÿ!Ÿ"Ÿ#Ÿ$Ÿ%Ÿ&Ÿ'Ÿ(Ÿ)Ÿ*Ÿ+Ÿ,-2   USjg ]].#"!!!!3267#"#734&5465#7332[©fÊ A7ýæ¾8þŠ Êf©[Y¹`íþË(Ó7‹Â7œ(6ìb¹bÕiZÈ»{.# .{»ÊZiÓHH"{/ #/{"G×)Ù¥@ ÎddÔüÜì1Ô<ì20K°TK°T[X½@ÿÀ878YK°TK° T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y@````pppp]3#%3#^ËËþyËËÙËËËsîðö@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@ %%6FVjg //]]3#7¹ä™öþø¶Jéu@!  ÃÃúVV ÔìÔì99991ô<ìÔì2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y´ ]'.#"#4632326=3#"&ü9 $(}gV$=09" (}gT";9! 2-ev 3)dw î‹ö‰@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@*$$5CUUŸŸ¯¯//]]#ÇÄ™æöþøÏî1øw@ úÔÄ91ô<Ä90K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ //- ]3#'#¢¼Ó‹¦¦‹øþö²²Ïî1ø†@ úÔÄ91ôÄ290K° TK° T[K° T[K° T[X½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ "  ]373¢Ó‹¦¦‹Óî ²²þö?œôß Ô@ Ý ÷‘ ] ÜÔ<Äì291ôüÔ<ì290K°TK°T[K°T[K°T[K° T[K° T[X½@ÿÀ878YK°TK°T[X½ÿÀ@878Y@T /9IFYi‹«»       "5GK S[ e„¥µ]] !33##5!5ÝþË5¦‡‡þbfþ]ýämººyÇ9ø j@à úVVÔìÔì1ôüÄ20K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TK°T[X½ÿÀ@878Y332673#"&Çv cSRav  Ÿø6978w{zšfÛ¶úÔÌ1ôÌ03#šÌÌÛÍ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßà>: ~ÿ1BSax~’ÇÝ©À & 0 : ¬!""""+"H"e%Êûÿÿ   0AR^x}’ÆØ©À  0 9 ¬!""""+"H"`%ÊûÿÿÿãÿõÿØÿ ÿ^ÿCÿhÿüöüÛà–à…àVßjÞqÞ_Úï¿8ôüúúü (B¬£„…½–熎‹©¤ŠÙƒ“ñò—ˆÃÝðžªóôõ¢­ÉÇ®bcdËeÈÊÏÌÍÎèfÒÐѯgï‘ÕÓÔhêì‰jikmln oqprsutvwéxzy{}|¸¡~€ëíºýþÿøÖùúãä×àÚÛÜßØÞ²³¶·Ä´µÅ‚‡«˜¨š™î¼¥’”•Íf‹‹55®Å´žªšq=3ۤ=´Ù‹žãd‹Û²‡á–œdž¨‹²ð²ž´Ù´Ù´Ù?“‡y}É–s)ÉÉšÉ3sÉ\É\ÿ–?ÉuÉçÉüÉLsÓÉLsɇãÿúÛ²yéD{=ãÿü{\°²Ç´Ùÿìªç{ºfqqìqÑ/qº9Á9ÿÛ¢º9Á˺ºåqºqJº+o#7®¼=‹V¼;¼=3X²´Ùyy–sÉüÉLsÛ²ç{ç{ç{ç{ç{ç{fqìqìqìqìq99ÿÇ9ÿÞ9ÿôºåqåqåqåqåq®®®®9ì\¸3ž º's×´ÙËLfªÝ´Ù´Ù´ÙR®#hdœ¶ÿá+/ÅsÅ`NÛ{åH?55´Ù=´ÙZÿúåžåÁìyyLss/q%®%®‹®‹²´Ùô¼=ãÿüVþ‰^3ž3Á / /9‹Û‹®%® ¼qyÉyÉÉ\¢\ÿþ\\;LsLsLsÛ²Û²Û²9ÁÁ¶ÕÇšî#ðLÁÿòF‡+o{\3X²3 åqãÿü¼=×ɺ´Ù´5‰5^5bÁ‰Á‰Áb3sq\ɇ+o–sfq–sfqqãd‹Û×s¶ ÏÏ5?Çšÿ+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóõôöøùúûüýþÿ     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""X“ÿ¶Oƒ²ö!n˜´ÊÞE‚~áL·üeÏî  R s ®  ß X ° û : i “ æ  = z /¬E…ëuñ)pཊëP‹±á@Ö"m¹#{ßC€øw³R¡Ø‡Äº‡wè [ r ó!5!B!â!ï!ü" ""#"0"="J"W"d"q"~"‹"˜"¥"²"¿"Ì"Ù"æ"ó## ##'#4#A#N#[#h#”#Ï$4$%3%S%&&º'K''·((X(Ã)_*%*\*£*é+z+Ó,D,,±-P- ..R.ª/‡0A0½11!1P1Ï2H2z2ß3F3p3p3}3Š3—3æ4z44£4Ñ4ÿ5595g5‘5ž5«5Ï6[6“6Í7C7©7ë888J999)969C9P9]9j9w9„9‘9ž9«9¸9Å9Ò9ï::{: :å;;^;Ž;Ä;ô<"<_<§<´<Á<Î<Û<þ=c>;>H>U>˜>ç>ý?a??Ü@:@K@\@m@z@‡@”@¡@®@»@È@Õ@âA@AVAkBEBªB÷C_C²CÿDUDÛE*E?-†” x$ÿÓ%ÿ·&')*K+-r./2934K57ÿD9ÿˆ:ÿ­;ÿš<ÿ =IQR&UYÿÉZ\ÿÜbÿÓdg9xy&z&{&|&}&‰­ÿÓ®ÿÓ¯9ºÿÜ»ÿ ÇÿÓÉÿÓÐ9Ñ9Ò9åéêÿ ëÿÜìöKûý$ÿÓ$ÿÜ$ÿÜ$$9$&ÿÜ$*ÿÜ$2ÿÜ$4ÿÜ$6$7ÿa$8$9ÿ}$:ÿ$;$<ÿa$FÿÜ$GÿÜ$HÿÜ$Iÿ·$RÿÜ$TÿÜ$WÿÜ$X$Yÿˆ$Zÿ­$\ÿu$b9$dÿÜ$gÿÜ$h$oÿÜ$pÿÜ$qÿÜ$rÿÜ$sÿÜ$yÿÜ$zÿÜ${ÿÜ$|ÿÜ$}ÿÜ$~$$€$$©ÿ·$ª$­9$®9$¯ÿÜ$´þø$µÿ$ºÿu$»ÿa$Å/$Ç9$É9$ÐÿÜ$ÑÿÜ$ÒÿÜ$Ó$Ô$Õ$ã$êÿa$ëÿu$öÿÜ$ù$ûÿÜ$üÿÜ$ýÿÜ$þÿÜ%%&ÿÜ%*ÿÜ%2ÿÜ%6ÿÜ%9ÿÁ%:ÿ·%<ÿ%dÿÜ%gÿÜ%©ÿÁ%ªÿÜ%¯ÿÜ%´ÿ%µÿ%»ÿ%Åÿ­%ÐÿÜ%ÑÿÜ%ÒÿÜ%ãÿÜ%êÿ%öÿÜ%ùÿÜ%ûÿÜ%ýÿÜ&&$&6&<ÿÜ&b&©ÿÜ&ªÿÜ&­&®&´&µ&&»ÿÜ&Å&Ç&É&ã&êÿÜ&ù''$ÿÜ'9ÿÜ':'<ÿ'bÿÜ'©ÿÜ'ªÿÜ'­ÿÜ'®ÿÜ'´ÿÓ'µÿÉ'»ÿ'ÅÿD'ÇÿÜ'ÉÿÜ'êÿ))þ·)ÿa)$ÿD)6ÿÜ)7ÿÜ)DÿD)Hÿ)Lÿk)Rÿ·)Uÿk)Xÿ)\ÿD)bÿD)iÿD)jÿD)kÿD)lÿD)mÿD)nÿD)pÿ)qÿ)rÿ)sÿ)yÿ·)zÿ·){ÿ·)|ÿ·)}ÿ·)~ÿ)ÿ)€ÿ)ÿ)©)ª)­ÿD)®ÿD)´ÿÓ)µ)ºÿD)Åþˆ)ÇÿD)ÉÿD)ãÿÜ)ëÿD)ùÿÜ**$*7ÿ·*:*<ÿš*b*©ÿÜ*ªÿÜ*­*®*´ÿÓ*µÿÓ*»ÿš*ÅÿÉ*Ç*É*êÿš++ÿÜ++©+ª+´ÿ·+µÿÁ+Åÿ·-ÿ·-$ÿÜ-bÿÜ-©ÿÜ-ªÿÜ-­ÿÜ-®ÿÜ-´ÿ·-µÿÁ-Åÿ-ÇÿÜ-ÉÿÜ.ÿ).$ÿÜ.&ÿ.2ÿ.7ÿa.8ÿÉ.:ÿ·.<ÿ·.DÿÜ.Hÿš.Rÿš.Xÿš.\ÿk.bÿÜ.dÿ.gÿ.hÿÉ.iÿÜ.jÿÜ.kÿÜ.lÿÜ.mÿÜ.nÿÜ.pÿš.qÿš.rÿš.sÿš.yÿš.zÿš.{ÿš.|ÿš.}ÿš.~ÿš.ÿš.€ÿš.ÿš.©ÿ}.ª.­ÿÜ.®ÿÜ.¯ÿ.´ÿÁ.µÿÁ.ºÿk.»ÿ·.Å.ÇÿÜ.ÉÿÜ.Ðÿ.Ñÿ.Òÿ.ÓÿÉ.ÔÿÉ.ÕÿÉ.êÿ·.ëÿk.ûÿ.ýÿ/ÿÜ/$//2ÿ·/7þæ/8ÿš/9ÿ/:ÿD/<þð/D/HÿÜ/RÿÜ/XÿÜ/\ÿD/b//gÿ·/hÿš/i/j/k/l/m/n/pÿÜ/qÿÜ/rÿÜ/sÿÜ/yÿÜ/zÿÜ/{ÿÜ/|ÿÜ/}ÿÜ/~ÿÜ/ÿÜ/€ÿÜ/ÿÜ/©/ª/­//®//¯ÿ·/´þa/µýæ/ºÿD/»þð/Å/Ç//É//Ðÿ·/Ñÿ·/Òÿ·/Óÿš/Ôÿš/Õÿš/êþð/ëÿD292ÿ­2ÿÜ2$ÿÜ29ÿÜ2;ÿ}2<ÿ2bÿÜ2©ÿÜ2ª2­ÿÜ2®ÿÜ2´ÿÓ2µÿÜ2»ÿ2ÅÿD2ÇÿÜ2ÉÿÜ2êÿ3ÿÓ3þÁ33$ÿ}383:3<ÿÓ3Dÿ¤3Hÿ·3LÿÓ3QÿÜ3Rÿ·3UÿÜ3VÿÜ3XÿÜ3\3bÿ}3h3iÿ¤3jÿ¤3kÿ¤3lÿ¤3mÿ¤3nÿ¤3pÿ·3qÿ·3rÿ·3sÿ·3xÿÜ3yÿ·3zÿ·3{ÿ·3|ÿ·3}ÿ·3~ÿÜ3ÿÜ3€ÿÜ3ÿÜ3©ÿÜ3ª3­ÿ}3®ÿ}3´&3µ&3º3»ÿÓ3Åþ·3Çÿ}3Éÿ}3Ó3Ô3Õ3äÿÜ3êÿÓ3ë3úÿÜ494©4ª4´ÿÓ4µÿÜ4Åÿ}5ÿ­5ÿ·5ÿÁ5$ÿ­5&ÿš57ÿk59ÿ5:ÿ­5<ÿ}5DÿÓ5Hÿ¤5Rÿ¤5Xÿ¤5\ÿ5bÿ­5dÿš5iÿÓ5jÿÓ5kÿÓ5lÿÓ5mÿÓ5nÿÓ5pÿ¤5qÿ¤5rÿ¤5sÿ¤5yÿ¤5zÿ¤5{ÿ¤5|ÿ¤5}ÿ¤5~ÿ¤5ÿ¤5€ÿ¤5ÿ¤5©ÿ5ªÿÜ5­ÿ­5®ÿ­5´ÿk5µÿ}5ºÿ5»ÿ}5ÅÿÜ5Çÿ­5Éÿ­5êÿ}5ëÿ5ûÿš5ýÿš6$&6&6*6264666b&6d6g6­&6®&6¯6Ç&6É&6Ð6Ñ6Ò6ã6ö6ù6û6ý7ÿD7ÿ 7ÿ7$ÿa7&ÿˆ77ÿÜ7Dþ­7Fþ¤7Hþ¤7LÿÁ7Rþ¤7UþÓ7Vþ­7XþÉ7Zþ­7\þÁ7bÿa7dÿˆ7iþ­7jþ­7kþ­7lþ­7mþ­7nþ­7oþ¤7pþ¤7qþ¤7rþ¤7sþ¤7yþ¤7zþ¤7{þ¤7|þ¤7}þ¤7~þÉ7þÉ7€þÉ7þÉ7©ÿD7ªÿ7­ÿa7®ÿa7´7µÿÓ7ºþÁ7Åþø7Çÿa7Éÿa7äþ­7ëþÁ7úþ­7ûÿˆ7üþ¤7ýÿˆ7þþ¤8$8-8=ÿÜ8b8­8®8Ç8É8åÿÜ9ÿˆ9þø9ÿY9$ÿ}92ÿÜ9Dÿa9Hÿa9LÿÓ9Rÿa9Xÿu9\ÿÉ9bÿ}9gÿÜ9iÿa9jÿa9kÿa9lÿa9mÿa9nÿa9pÿa9qÿa9rÿa9sÿa9yÿa9zÿa9{ÿa9|ÿa9}ÿa9~ÿu9ÿu9€ÿu9ÿu9©ÿN9ªÿ9­ÿ}9®ÿ}9¯ÿÜ9´9µ9ºÿÉ9Åþæ9Çÿ}9Éÿ}9ÐÿÜ9ÑÿÜ9ÒÿÜ9ëÿÉ:ÿ­:ÿ:ÿˆ:$ÿ:Dÿ}:Hÿˆ:LÿÓ:Rÿˆ:Uÿ¤:Xÿ·:\ÿÜ:bÿ:iÿ}:jÿ}:kÿ}:lÿ}:mÿ}:nÿ}:pÿˆ:qÿˆ:rÿˆ:sÿˆ:yÿˆ:zÿˆ:{ÿˆ:|ÿˆ:}ÿˆ:~ÿ·:ÿ·:€ÿ·:ÿ·:©ÿ:ªÿÜ:­ÿ:®ÿ:´ÿÜ:µ:ºÿÜ:Åþø:Çÿ:Éÿ:ëÿÜ;ÿš;$;&ÿk;2ÿ};7ÿÜ;Hÿ¤;b;dÿk;gÿ};pÿ¤;qÿ¤;rÿ¤;sÿ¤;©ÿ;ª;­;®;¯ÿ};´ÿa;µÿ­;ÅÿÓ;Ç;É;Ðÿ};Ñÿ};Òÿ};ûÿk;ýÿk<ÿ <þa<þð<$ÿa<&ÿ<2ÿ<Dþæ<Hþð<Lÿ·<Rþð<Xÿ<bÿa<dÿ<gÿ<iþæ<jþæ<kþæ<lþæ<mþæ<nþæ<pþð<qþð<rþð<sþð<yþð<zþð<{þð<|þð<}þð<~ÿ<ÿ<€ÿ<ÿ<©ÿ<ªÿk<­ÿa<®ÿa<¯ÿ<´ÿ<µÿÜ<Åþø<Çÿa<Éÿa<Ðÿ<Ñÿ<Òÿ<ûÿ<ýÿ=ÿÜ=©=ª=´ÿÜ=µÿÜ=ÅÿÜH[ÿÜIÿIÿkIÿ·IWÿÜIZÿÜI\ÿÜI©ÿ·IªÿÜI´AIµIºÿÜIÅÿIëÿÜNDÿÜNHÿ·NRÿ·NXÿÁN\ÿ·NiÿÜNjÿÜNkÿÜNlÿÜNmÿÜNnÿÜNpÿ·Nqÿ·Nrÿ·Nsÿ·Nyÿ·Nzÿ·N{ÿ·N|ÿ·N}ÿ·N~ÿÁNÿÁN€ÿÁNÿÁNºÿ·Nëÿ·QQQQ©QªQ´ÿkQµÿQÅÿ¤R&RÿÜRR[ÿÁR©RªR´ÿkRµÿ·RÅÿ}Uÿ}UÿDUÿÜUFÿÓUGÿÜUHÿÓUIUJÿÜUKÿÜUPÿÜUQÿÜURÿÓUTÿÜUUÿÜUXUYUZU[ÿÉU\U]UoÿÓUpÿÓUqÿÓUrÿÓUsÿÓUxÿÜUyÿÓUzÿÓU{ÿÓU|ÿÓU}ÿÓU~UU€UU©ÿ·UªU´UµVUºUÅþÉUæUëU÷ÿÜUüÿÓUþÿÓYÿÉYÿaYÿY©ÿÜYªÿÜY´YµÿÜYÅþðZZÿDZÿZ©ÿÜZªÿÜZ´ZµZÅÿ)[FÿÜ[HÿÁ[RÿÁ[oÿÜ[pÿÁ[qÿÁ[rÿÁ[sÿÁ[yÿÁ[zÿÁ[{ÿÁ[|ÿÁ[}ÿÁ[üÿÜ[þÿÜ\ÿÜ\þÜ\ÿk\©ÿÜ\ªÿÜ\´\µ\ÅþÓbÿÓbÿÜbÿÜb$9b&ÿÜb*ÿÜb2ÿÜb4ÿÜb6b7ÿab8b9ÿ}b:ÿb;b<ÿabFÿÜbGÿÜbHÿÜbIÿ·bRÿÜbTÿÜbWÿÜbXbYÿˆbZÿ­b\ÿubb9bdÿÜbgÿÜbhboÿÜbpÿÜbqÿÜbrÿÜbsÿÜbyÿÜbzÿÜb{ÿÜb|ÿÜb}ÿÜb~bb€bb©ÿ·bªb­9b®9b¯ÿÜb´þøbµÿbºÿub»ÿabÅ/bÇ9bÉ9bÐÿÜbÑÿÜbÒÿÜbÓbÔbÕbãbêÿabëÿuböÿÜbùbûÿÜbüÿÜbýÿÜbþÿÜdd$d6d<ÿÜdbd©ÿÜdªÿÜd­d®d´dµ&d»ÿÜdÅdÇdÉdãdêÿÜdùg9gÿ­gÿÜg$ÿÜg9ÿÜg;ÿ}g<ÿgbÿÜg©ÿÜgªg­ÿÜg®ÿÜg´ÿÓgµÿÜg»ÿgÅÿDgÇÿÜgÉÿÜgêÿh$h-h=ÿÜhbh­h®hÇhÉhåÿÜp[ÿÜq[ÿÜr[ÿÜs[ÿÜxxxx©xªx´ÿkxµÿxÅÿ¤y&yÿÜyy[ÿÁy©yªy´ÿkyµÿ·yÅÿ}z&zÿÜzz[ÿÁz©zªz´ÿkzµÿ·zÅÿ}{&{ÿÜ{{[ÿÁ{©{ª{´ÿk{µÿ·{Åÿ}|&|ÿÜ||[ÿÁ|©|ª|´ÿk|µÿ·|Åÿ}}&}ÿÜ}}[ÿÁ}©}ª}´ÿk}µÿ·}Åÿ}‰&‰©‰ª‰´ÿ‰µÿ‰Åÿ­©ª´ÿ­µÿ¤Åÿ©$©%ÿÜ©&ÿÜ©'ÿÜ©)©*ÿÜ©+©-ÿÜ©.©/©2©3©4©5©7ÿ©9ÿ©:ÿÜ©;©<ÿk©=©I©Q©R©U©YÿÜ©ZÿÜ©\ÿÜ©b©dÿÜ©g©x©y©z©{©|©}©‰©—©­©®©¯©ºÿÜ©»ÿk©Ç©É©Ð©Ñ©Ò©å©é©êÿk©ëÿÜ©ì©öÿÜ©ûÿÜ©ýÿܪ$ÿ·ª%ÿ·ª&ÿܪ'ÿܪ)ª*ª+ª-ÿܪ.ª/ª2ÿܪ3ª4ª5ª7ÿDª9ÿNª:ÿª;ÿª<ÿª=ªIªQªRªUªYÿܪZÿܪ\ÿܪbÿ·ªdÿܪgÿܪxªyªzª{ª|ª}ª‰ªª­ÿ·ª®ÿ·ª¯ÿܪºÿܪ»ÿªÇÿ·ªÉÿ·ªÐÿܪÑÿܪÒÿܪåªéªêÿªëÿܪìªöªûÿܪýÿÜ­ÿÓ­ÿÜ­ÿÜ­$9­&ÿÜ­*ÿÜ­2ÿÜ­4ÿÜ­6­7ÿa­8­9ÿ}­:ÿ­;­<ÿa­FÿÜ­GÿÜ­HÿÜ­Iÿ·­RÿÜ­TÿÜ­WÿÜ­X­Yÿˆ­Zÿ­­\ÿu­b9­dÿÜ­gÿÜ­h­oÿÜ­pÿÜ­qÿÜ­rÿÜ­sÿÜ­yÿÜ­zÿÜ­{ÿÜ­|ÿÜ­}ÿÜ­~­­€­­©ÿ·­ª­­9­®9­¯ÿÜ­´þø­µÿ­ºÿu­»ÿa­Å/­Ç9­É9­ÐÿÜ­ÑÿÜ­ÒÿÜ­Ó­Ô­Õ­ã­êÿa­ëÿu­öÿÜ­ù­ûÿÜ­üÿÜ­ýÿÜ­þÿÜ®ÿÓ®ÿÜ®ÿÜ®$9®&ÿÜ®*ÿÜ®2ÿÜ®4ÿÜ®6®7ÿa®8®9ÿ}®:ÿ®;®<ÿa®FÿÜ®GÿÜ®HÿÜ®Iÿ·®RÿÜ®TÿÜ®WÿÜ®X®Yÿˆ®Zÿ­®\ÿu®b9®dÿÜ®gÿÜ®h®oÿÜ®pÿÜ®qÿÜ®rÿÜ®sÿÜ®yÿÜ®zÿÜ®{ÿÜ®|ÿÜ®}ÿÜ®~®®€®®©ÿ·®ª®­9®®9®¯ÿÜ®´þø®µÿ®ºÿu®»ÿa®Å/®Ç9®É9®ÐÿÜ®ÑÿÜ®ÒÿܮӮԮծã®êÿa®ëÿu®öÿÜ®ù®ûÿÜ®üÿÜ®ýÿÜ®þÿܯ9¯ÿ­¯ÿܯ$ÿܯ9ÿܯ;ÿ}¯<ÿ¯bÿܯ©ÿܯª¯­ÿܯ®ÿܯ´ÿÓ¯µÿܯ»ÿ¯ÅÿD¯ÇÿܯÉÿܯêÿ´$þø´%ÿÁ´&ÿ·´'ÿÁ´)ÿÁ´*ÿ·´+ÿÁ´-ÿÁ´.ÿÁ´/ÿÁ´2ÿ·´3ÿÁ´4ÿ·´5ÿÁ´7´9´:´;ÿˆ´<´=ÿÜ´Iÿ·´Qÿ´Rÿk´Uÿ´Yÿ·´Zÿ·´\ÿ·´bþø´dÿ·´gÿ·´xÿ´yÿk´zÿk´{ÿk´|ÿk´}ÿk´‰ÿÁ´þ}´­þø´®þø´¯ÿ·´ºÿ·´»´Çþø´Éþø´Ðÿ·´Ñÿ·´Òÿ·´åÿÜ´éÿ·´ê´ëÿ·´ìÿÁ´öÿ·´ûÿ·´ýÿ·ºÿܺþܺÿkº©ÿܺªÿܺ´ºµºÅþÓ»ÿ »þa»þð»$ÿa»&ÿ»2ÿ»Dþæ»Hþð»Lÿ·»Rþð»Xÿ»bÿa»dÿ»gÿ»iþæ»jþæ»kþæ»lþæ»mþæ»nþæ»pþð»qþð»rþð»sþð»yþð»zþð»{þð»|þð»}þð»~ÿ»ÿ»€ÿ»ÿ»©ÿ»ªÿk»­ÿa»®ÿa»¯ÿ»´ÿ»µÿÜ»Åþø»Çÿa»Éÿa»Ðÿ»Ñÿ»Òÿ»ûÿ»ýÿÅ$&Å%ÿ·Å&ÿÅ'ÿ·Å)ÿ·Å*ÿ·Å+ÿ·Å-/Å.ÿ·Å/ÿ·Å2ÿÅ3ÿ·Å4ÿÅ5ÿ·Å7þæÅ9þˆÅ:ÿÅ;ÿ·Å<þˆÅ=ÅIÿÜÅQÿ·ÅRÿ·ÅUÿ·ÅYÿÅZÿ<Å\ÿÅb&ÅdÿÅgÿÅxÿ·Åyÿ·Åzÿ·Å{ÿ·Å|ÿ·Å}ÿ·Å‰ÿ·Å&Å­&Å®&ůÿźÿÅ»þˆÅÇ&ÅÉ&ÅÐÿÅÑÿÅÒÿÅåÅéÿ·ÅêþˆÅëÿÅìÿ·Åöÿ·ÅûÿÅýÿÇÿÓÇÿÜÇÿÜÇ$9Ç&ÿÜÇ*ÿÜÇ2ÿÜÇ4ÿÜÇ6Ç7ÿaÇ8Ç9ÿ}Ç:ÿÇ;Ç<ÿaÇFÿÜÇGÿÜÇHÿÜÇIÿ·ÇRÿÜÇTÿÜÇWÿÜÇXÇYÿˆÇZÿ­Ç\ÿuÇb9ÇdÿÜÇgÿÜÇhÇoÿÜÇpÿÜÇqÿÜÇrÿÜÇsÿÜÇyÿÜÇzÿÜÇ{ÿÜÇ|ÿÜÇ}ÿÜÇ~ÇÇ€ÇÇ©ÿ·ÇªÇ­9Ç®9ǯÿÜÇ´þøÇµÿǺÿuÇ»ÿaÇÅ/ÇÇ9ÇÉ9ÇÐÿÜÇÑÿÜÇÒÿÜÇÓÇÔÇÕÇãÇêÿaÇëÿuÇöÿÜÇùÇûÿÜÇüÿÜÇýÿÜÇþÿÜÉÿÓÉÿÜÉÿÜÉ$9É&ÿÜÉ*ÿÜÉ2ÿÜÉ4ÿÜÉ6É7ÿaÉ8É9ÿ}É:ÿÉ;É<ÿaÉFÿÜÉGÿÜÉHÿÜÉIÿ·ÉRÿÜÉTÿÜÉWÿÜÉXÉYÿˆÉZÿ­É\ÿuÉb9ÉdÿÜÉgÿÜÉhÉoÿÜÉpÿÜÉqÿÜÉrÿÜÉsÿÜÉyÿÜÉzÿÜÉ{ÿÜÉ|ÿÜÉ}ÿÜÉ~ÉÉ€ÉÉ©ÿ·ÉªÉ­9É®9ɯÿÜÉ´þøÉµÿɺÿuÉ»ÿaÉÅ/ÉÇ9ÉÉ9ÉÐÿÜÉÑÿÜÉÒÿÜÉÓÉÔÉÕÉãÉêÿaÉëÿuÉöÿÜÉùÉûÿÜÉüÿÜÉýÿÜÉþÿÜÐ9Ðÿ­ÐÿÜÐ$ÿÜÐ9ÿÜÐ;ÿ}Ð<ÿÐbÿÜЩÿÜЪЭÿÜЮÿÜдÿÓеÿÜлÿÐÅÿDÐÇÿÜÐÉÿÜÐêÿÑ9Ñÿ­ÑÿÜÑ$ÿÜÑ9ÿÜÑ;ÿ}Ñ<ÿÑbÿÜÑ©ÿÜѪѭÿÜÑ®ÿÜÑ´ÿÓѵÿÜÑ»ÿÑÅÿDÑÇÿÜÑÉÿÜÑêÿÒ9Òÿ­ÒÿÜÒ$ÿÜÒ9ÿÜÒ;ÿ}Ò<ÿÒbÿÜÒ©ÿÜÒªÒ­ÿÜÒ®ÿÜÒ´ÿÓÒµÿÜÒ»ÿÒÅÿDÒÇÿÜÒÉÿÜÒêÿÓ$Ó-Ó=ÿÜÓbÓ­Ó®ÓÇÓÉÓåÿÜÔ$Ô-Ô=ÿÜÔbÔ­Ô®ÔÇÔÉÔåÿÜÕ$Õ-Õ=ÿÜÕbÕ­Õ®ÕÇÕÉÕåÿÜã$&ã&ã*ã2ã4ã6ãb&ãdãgã­&ã®&ã¯ãÇ&ãÉ&ãÐãÑãÒãããöãùãûãýåÿÜå©åªå´ÿÜåµÿÜåÅÿÜéé©éªé´ÿ¤éµÿéÅÿ·êÿ êþaêþðê$ÿaê&ÿê2ÿêDþæêHþðêLÿ·êRþðêXÿêbÿaêdÿêgÿêiþæêjþæêkþæêlþæêmþæênþæêpþðêqþðêrþðêsþðêyþðêzþðê{þðê|þðê}þðê~ÿêÿê€ÿêÿê©ÿêªÿkê­ÿaê®ÿaê¯ÿê´ÿêµÿÜêÅþøêÇÿaêÉÿaêÐÿêÑÿêÒÿêûÿêýÿëÿÜëþÜëÿkë©ÿÜëªÿÜë´ëµëÅþÓììÿkìÿ·ì©ìªì´ÿÜìµìÅÿDöö$ö7ÿ·ö:ö<ÿšöbö©ÿÜöªÿÜö­ö®ö´ÿÓöµÿÓö»ÿšöÅÿÉöÇöÉöêÿšù$&ù&ù*ù2ù4ù6ùb&ùdùgù­&ù®&ù¯ùÇ&ùÉ&ùÐùÑùÒùãùöùùùûùýûû$û6û<ÿÜûbû©ÿÜûªÿÜû­û®û´ûµ&û»ÿÜûÅûÇûÉûãûêÿÜûùýý$ý6ý<ÿÜýbý©ÿÜýªÿÜý­ý®ý´ýµ&ý»ÿÜýÅýÇýÉýãýêÿÜýù MB@hmþ ¼þ‰þ‰ L GÌþBGÌSf €¯ JBits@ ûþšmãB±‹`#cÕVeraSansÿÿÿÿ6ÿÿþ628R00@                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "                      "       #                       #     $               $    &              &    ÿÿ P ì_<õº¹ð¸ºÂg‘þ‰þ Lmpybox2d-2.3.2/examples/data/themes/default/box.down.png000066400000000000000000000004701276457661000230300ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕl–átEXtCommentCreated with The GIMPïd%nœIDAT8Ë¥“;à DŸªxÆ9B’û_'ŸÖ7 )Q !v#¶X±Å@UÕ¹[ˆ¯”)«FkÛqÑ_¾r€ ÜÓ/ÌÁ;ïN 4ýCaÏF@×Edã+÷'ðHÙí 0ˆpO¨˜Ué2Ñòýš¥ ÜΓëô¥uФÓvß>\æi¼CÞX^¿óh–>¢\ÓŠ2IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/box.hover.png000066400000000000000000000005041276457661000232020ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ&¾ »ÜtEXtCommentCreated with The GIMPïd%n¨IDAT8Ë¥“Mƒ „?I­vÝ¿ÓÀɹI›vãÔÔnÀEýA¢Iõy3“ ´Öž´ ðÖÚ¤×Æ¯ÞmA9®áÙE¸ ú àÑô¤ÖOA·Màÿ“Õ»AÿH>ÿ€ÿÿÕ¿YÿßÈ_ÿ‚ßÉaÿˆßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿÕ¿Yÿÿ€ÿ5/ÿ‘ê×€ÿ5/ÿÿ€ÿ:4ÿíÝ•ÿôå ÿíÝ•ÿ:4ÿÿ‚ÿÿpf6ÿÕÆÿ‰úí´ÿÕÆÿpf6ÿÿÿ‚„ÿ„pybox2d-2.3.2/examples/data/themes/default/button.hover.tga000066400000000000000000000014101276457661000237110ustar00rootroot00000000000000  („@@@@@@ÿ„@@@‚@@@@@@ÿVUTÿ¹¶§ÿîëÞÿ‰ýüùÿîëÞÿ¹¶§ÿVUTÿ@@@ÿ‚@@@@@@@@@ÿ‹ÿóïÛÿ÷óßÿˆ÷óáÿ÷óßÿ÷óáÿ÷óßÿóïÛÿ‹ÿ@@@ÿ@@@@@@@@@ÿ‚rÿ‘ïæ¿ÿ‚rÿ@@@ÿ€@@@@@@KKKÿáÕÿ‚çÚŸÿŒçÛ¡ÿçÚŸÿçÛ¡ÿáÕÿKKKÿ€@@@@@@ÿ„~bÿ“àÏ€ÿ„~bÿ€@@@ÿ@@@ÿ¬Zÿ“×Âaÿ­Ÿ[ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿªšPÿ×ÁYÿ×ÀWÿŒ×ÁYÿ×ÀWÿ‚×ÁYÿªšPÿ€@@@ÿ@@@ÿvoNÿ“àÌpÿvoNÿ€@@@ÿ@@@BB@ÿàЄÿçÖ‡ÿ‚çÖ‰ÿˆçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿàЄÿCBAÿ€@@@@@@@@@ÿgcOÿ‘ïá¡ÿgcOÿ@@@ÿ€@@@@@@@@@ÿlgRÿòæ°ÿŠ÷ì¹ÿ÷ë·ÿ÷ì¹ÿòæ°ÿlgRÿ@@@ÿ@@@‚@@@@@@ÿDCBÿ“ŒiÿàÕ ÿ‰ûòÇÿàÕ ÿ“ŒiÿDCBÿ@@@ÿ‚@@@„@@@@@@ÿ„@@@pybox2d-2.3.2/examples/data/themes/default/button.normal.tga000066400000000000000000000013311276457661000240600ustar00rootroot00000000000000  („ÿ„‚ÿ”””ÿÝÝÝÿùùùÿ‰ÿÿÿÿùùùÿÝÝÝÿ”””ÿÿ‚ÿ¿¿¿ÿøøøÿúúúÿøøøÿ¿¿¿ÿÿÿ´´´ÿ‘ðððÿ´´´ÿÿ€ŠŠŠÿáááÿ‘ãããÿáááÿŠŠŠÿ€ÿªªªÿ“ÒÒÒÿªªªÿ€ÿÿ°°°ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ±±±ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿªªªÿ»»»ÿºººÿŒ»»»ÿºººÿ‚»»»ÿªªªÿ€ÿÿ™™™ÿ“ËËËÿ™™™ÿ€ÿ€€€ÿÔÔÔÿ‘ØØØÿÔÔÔÿ€€€ÿ€ÿ•••ÿ‘åååÿ•••ÿÿ€ÿ™™™ÿëëëÿïïïÿëëëÿ™™™ÿÿ‚ÿÿ³³³ÿâââÿ‰ôôôÿâââÿ³³³ÿÿÿ‚„ÿ„pybox2d-2.3.2/examples/data/themes/default/check.png000066400000000000000000000003151276457661000223450ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÕ4x@’ÙtEXtCommentCreated with The GIMPïd%n5IDAT(Ïc` #øÇˆ"€…Lj¦‡]1#K1(JD™¹+8ò?þ€¢¦O¨ sÃIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/checkbox.off.hover.tga000066400000000000000000000006721276457661000247460ustar00rootroot00000000000000  (@@@@@@ÿ€@@@@@@ÿÿÿÿÿ€@@@ÿ@@@ÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ@@@ÿïæ¿ÿ€@@@ÿ@@@ÿ…çÛ¡ÿçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ@@@ÿàÏ€ÿ€@@@ÿ@@@ÿ‚×Âaÿ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ@@@ÿз@ÿ€@@@ÿ@@@ÿз@ÿ€@@@ÿ@@@ÿ×ÁYÿ×ÀWÿƒ×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ@@@ÿàÌpÿ€@@@ÿ@@@ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿƒçÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ@@@ÿïá¡ÿ€@@@ÿ@@@ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿ‚÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ@@@ÿÿ÷Ñÿ€@@@ÿ@@@@@@ÿ€@@@pybox2d-2.3.2/examples/data/themes/default/checkbox.off.normal.tga000066400000000000000000000005001276457661000251010ustar00rootroot00000000000000  (ÿ€ÿÿÿÿÿ€ÿÿúúúÿ€ÿÿðððÿ€ÿÿãããÿ€ÿÿÒÒÒÿ€ÿÿ‚ÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ‚¿¿¿ÿ€ÿÿªªªÿ€ÿÿªªªÿ€ÿÿ»»»ÿºººÿƒ»»»ÿºººÿ»»»ÿºººÿ»»»ÿ€ÿÿËËËÿ€ÿÿØØØÿ€ÿÿåååÿ€ÿÿïïïÿ€ÿÿ÷÷÷ÿ€ÿÿ€pybox2d-2.3.2/examples/data/themes/default/checkbox.on.hover.tga000066400000000000000000000010271276457661000246030ustar00rootroot00000000000000  (???ÿ€???ÿþþþÿ€???ÿ???ÿöòàÿöòÞÿöòàÿöòÞÿöòàÿöòÞÿöòàÿöòÞÿöòàÿöòÞÿ€???ÿ???ÿ‚îå¾ÿÿ…îå¾ÿÿ‚îå¾ÿ€???ÿ???ÿæÚ ÿ‚ÿæÚ ÿæÙžÿæÚ ÿ‚ÿæÙžÿ€???ÿ???ÿ‚ßÎÿ‚ÿßÎÿ‚ÿ‚ßÎÿ€???ÿ???ÿ‚ÖÁ`ÿÖÁ^ÿ…ÿÖÁ`ÿ‚ÖÁ^ÿ€???ÿ???ÿ„϶?ÿƒÿ„϶?ÿ€???ÿ???ÿ„϶?ÿƒÿ„϶?ÿ€???ÿ???ÿÖÀXÿÖ¿VÿÖÀXÿ…ÿÖ¿VÿÖÀXÿ€???ÿ???ÿ‚ßËoÿ‚ÿßËoÿ‚ÿ‚ßËoÿ€???ÿ???ÿæÕˆÿæÕ†ÿ‚ÿæÕˆÿ‚æÕ†ÿ‚ÿæÕ†ÿ€???ÿ???ÿ‚îà ÿÿ…îà ÿÿ‚îà ÿ€???ÿ???ÿöê¶ÿöë¸ÿöê¶ÿöë¸ÿ‚öê¶ÿ‚öë¸ÿöê¶ÿöë¸ÿöê¶ÿ€???ÿ???ÿþöÐÿ€???ÿ???ÿ€pybox2d-2.3.2/examples/data/themes/default/checkbox.on.normal.tga000066400000000000000000000007641276457661000247570ustar00rootroot00000000000000  (ÿ€ÿþþþÿ€ÿÿóîÕÿóíÓÿóîÕÿóíÓÿóîÕÿóíÓÿóîÕÿóíÓÿóîÕÿóíÓÿ€ÿÿ‚éÞ©ÿÿ…éÞ©ÿÿ‚éÞ©ÿ€ÿÿÞÍ€ÿ‚ÿÞÍ€ÿÞÍ~ÿÞÍ€ÿ‚ÿÞÍ~ÿ€ÿÿ‚Ô½Tÿ‚ÿÔ½Tÿ‚ÿ‚Ô½Tÿ€ÿÿ‚Ê­*ÿÉ­)ÿ…ÿÊ­*ÿ‚É­)ÿ€ÿÿ„¿ÿƒÿ„¿ÿ€ÿÿ„¿ÿƒÿ„¿ÿ€ÿÿÉ«ÿʬÿÉ«ÿ…ÿʬÿÉ«ÿ€ÿÿ‚Ôº@ÿ‚ÿÔº@ÿ‚ÿ‚Ôº@ÿ€ÿÿÞÈ`ÿÞÇ^ÿ‚ÿÞÈ`ÿ‚ÞÇ^ÿ‚ÿÞÇ^ÿ€ÿÿ‚éÖÿÿ…éÖÿÿ‚éÖÿ€ÿÿóäŸÿ€ÿÿþóÀÿ€ÿÿ€pybox2d-2.3.2/examples/data/themes/default/config.txt000066400000000000000000000172351276457661000226010ustar00rootroot00000000000000desktop background desktop.png input font Vera.ttf 16 input background input.normal.png input color #000000 input:focus background input.focus.png input padding_left 6 input padding_right 6 input padding_top 3 input padding_bottom 3 link font Vera.ttf 24 link color #0000FF link:hover color #FF0000 link:down color #00FF00 label font Vera.ttf 12 label color #000000 document font Vera.ttf 16 document color #000000 div font Vera.ttf 16 div color #000000 td font Vera.ttf 16 td color #000000 th font Vera.ttf 16 th color #000000 h1 font Vera.ttf 24 h1 color #000000 h2 font Vera.ttf 20 h2 color #000000 h3 font Vera.ttf 16 h3 color #000000 h4 font Vera.ttf 14 h4 color #000000 h5 font Vera.ttf 12 h5 color #000000 h6 font Vera.ttf 10 h6 color #000000 ul font Vera.ttf 16 ul color #000000 ol font Vera.ttf 16 ol color #000000 li font Vera.ttf 16 li color #000000 li padding_left 32 pre font mono 16 pre color #000000 code font mono 16 code color #000000 checkbox off checkbox.off.normal.tga checkbox on checkbox.on.normal.tga checkbox:hover off checkbox.off.hover.tga checkbox:hover on checkbox.on.hover.tga checkbox:down off checkbox.off.hover.tga checkbox:down on checkbox.on.hover.tga switch off checkbox.off.normal.tga switch on checkbox.on.normal.tga switch:hover off checkbox.off.hover.tga switch:hover on checkbox.on.hover.tga switch:down off checkbox.off.hover.tga switch:down on checkbox.on.hover.tga radio off radio.off.normal.tga radio on radio.on.normal.tga radio:hover off radio.off.hover.tga radio:hover on radio.on.hover.tga radio:down off radio.off.hover.tga radio:down on radio.on.hover.tga button background button.normal.tga button:hover background button.hover.tga button:down background button.down.tga button padding_left 8 button padding_right 8 button padding_top 1 button padding_bottom 1 button.label font Vera.ttf 16 button.label color #000000 slider background slider.tga slider bar slider.bar.normal.tga slider:hover bar slider.bar.hover.tga slider width 16 slider height 16 hslider background hslider.tga hslider bar hslider.bar.normal.tga hslider:hover bar hslider.bar.hover.tga hslider:down bar hslider.bar.hover.tga hslider width 16 hslider height 16 vslider background vslider.tga vslider bar vslider.bar.normal.tga vslider:hover bar vslider.bar.hover.tga vslider:down bar vslider.bar.hover.tga vslider width 16 vslider height 16 xhscrollbar height 16 xhscrollbar background scroller.slide.h.tga xhscrollbar bar scroller.slide.bar.normal.tga xhscrollbar:hover bar scroller.slide.bar.hover.tga xvscrollbar width 16 xvscrollbar background scroller.slide.v.tga xvscrollbar bar scroller.slide.bar.normal.tga xvscrollbar:hover bar scroller.slide.bar.hover.tga hscrollbar.slider background hslider.tga hscrollbar.slider bar hslider.bar.normal.tga hscrollbar.slider:hover bar hslider.bar.hover.tga hscrollbar.slider:down bar hslider.bar.hover.tga hscrollbar.slider width 16 hscrollbar.slider height 16 hscrollbar minus hslider.left.tga hscrollbar plus hslider.right.tga vscrollbar.slider background vslider.tga vscrollbar.slider bar vslider.bar.normal.tga vscrollbar.slider:hover bar vslider.bar.hover.tga vscrollbar.slider:down bar vslider.bar.hover.tga vscrollbar.slider width 16 vscrollbar.slider height 16 vscrollbar minus vslider.up.tga vscrollbar plus vslider.down.tga select.selected background select.selected.normal.tga select.selected:hover background select.selected.hover.tga select.selected:down background select.selected.down.tga select.selected padding_left 4 select.selected padding_right 4 select.selected padding_top 1 select.selected padding_bottom 1 select.arrow background select.arrow.normal.tga select.arrow:hover background select.arrow.hover.tga select.arrow:down background select.arrow.down.tga select.arrow padding_left 1 select.arrow padding_right 1 select.options background select.options.png select.option background select.option.normal.png select.option:hover background select.option.hover.png select.option:down background select.option.hover.png select.option padding_left 4 select.option padding_right 4 select.option padding_top 1 select.option padding_bottom 1 #select.option border_top 1 #select.option border_right 1 #select.option border_bottom 1 #select.option border_left 1 select.option.label font Vera.ttf 16 select.option.label color #000000 select.options padding_left 1 select.options padding_right 1 select.options padding_top 1 select.options padding_bottom 1 select arrow select.arrow.png dialog background dialog.bar.png xdialog.bar background dialog.bar.png dialog.bar padding_left 8 dialog.bar padding_right 8 dialog.bar padding_top 2 dialog.bar padding_bottom 1 dialog.bar.close image dialog.close.normal.tga dialog.bar.close:hover image dialog.close.hover.tga dialog.bar.close:down image dialog.close.down.tga dialog.main background dialog.png dialog.main padding_left 8 dialog.main padding_right 8 dialog.main padding_top 4 dialog.main padding_bottom 4 keysym font Vera.ttf 16 keysym background input.normal.png keysym color #000000 keysym:focus background input.focus.png keysym padding_left 6 keysym padding_right 6 keysym padding_top 3 keysym padding_bottom 3 tool background tool.normal.tga tool:hover background tool.hover.tga tool:down background tool.down.tga tool padding_left 4 tool padding_right 4 tool padding_top 1 tool padding_bottom 1 tool.label font Vera.ttf 16 tool.label color #000000 menu background menu.normal.tga menu:hover background menu.hover.tga menu:down background menu.down.tga menu padding_left 6 menu padding_right 6 menu padding_top 3 menu padding_bottom 3 menu.label font Vera.ttf 16 menu.label color #000000 menu-open background menu.down.tga menu-open:hover background menu.down.tga menu-open:down background menu.down.tga menu-open padding_left 6 menu-open padding_right 6 menu-open padding_top 3 menu-open padding_bottom 3 menu.options background select.options.png menu.option background select.option.normal.png menu.option:hover background select.option.hover.png menu.option:down background select.option.hover.png menu.option padding_left 6 menu.option padding_right 6 menu.option padding_top 1 menu.option padding_bottom 1 menu.option.label font Vera.ttf 16 menu.option.label color #000000 menu.options padding_left 1 menu.options padding_right 1 menu.options padding_top 1 menu.options padding_bottom 1 menu arrow select.arrow.tga scrollarea.content background #ffffff scrollarea.content padding_left 1 scrollarea.content padding_right 1 scrollarea.content padding_top 1 scrollarea.content padding_bottom 1 list.item background list.item.normal.png list.item:hover background list.item.down.png list.item:down background list.item.down.png list.item padding_left 4 list.item padding_right 4 list.item padding_top 2 list.item padding_bottom 2 list.item margin_bottom 1 list.item align -1 list.item.label font Vera.ttf 14 list.item.label color #000000 list background list.png list padding_left 1 list padding_right 1 list padding_top 1 list padding_bottom 1 list.content background #eeeeee list.content padding_left 1 list.content padding_right 1 list.content padding_top 1 list.content padding_bottom 1 filedialog.folder image filebrowser.folder.png filedialog.label font Vera.ttf 14 filedialog.label color #000000 filedialog.title.label font Vera.ttf 16 filedialog.title.label color #000000 filedialog.input font Vera.ttf 14 filedialog.input background input.normal.png filedialog.input color #000000 filedialog.input:focus background input.focus.png filedialog.input padding_left 6 filedialog.input padding_right 6 filedialog.input padding_top 3 filedialog.input padding_bottom 3 dialog.title.label font Vera.ttf 16 dialog.title.label color #000000 progressbar background progressbar.tga progressbar bar progressbar.bar.tga progressbar width 16 progressbar height 16 pybox2d-2.3.2/examples/data/themes/default/console.input.focus.png000066400000000000000000000003401276457661000252040ustar00rootroot00000000000000‰PNG  IHDRàw=ø§IDATH‰í–AÂ0 ×Eü£¶ûÇ#rír€šD™Tâ•|±”Ç—µD)w¯›_HU¥ìZÆv¶ˆ?à`" ’03â†G!XÏ÷fÆÕwo5n€VH€œsl%´yvŸ¾øEê>z¡€€€$Tµ{¨ê+Dª(ýY›çÑ‘)ïW…»sYÌ—94õtRÚ…¾´ÎU -î^íúqÒz§xaIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/console.input.normal.png000066400000000000000000000003401276457661000253550ustar00rootroot00000000000000‰PNG  IHDRàw=ø§IDATH‰í–1à ^†ü±»û˜µŸrëM[&‰"lK)‰æŠ¸fI’p$"Úá˜Y:ÎÒ^PƒK)=ù Ùˆ^‚ˆP >+ ¹I$ÁÝER.9$åî’„ ˲tÝø53¹»J)ÝkùI|¾àN†`†`þAI0³ËûÀ̶>H©©ÒÓÔÌÛ+³)ýu]1MS—`žgäœß—þ3ëú¶DD³ëé” „)ëIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/console.png000066400000000000000000000003401276457661000227300ustar00rootroot00000000000000‰PNG  IHDRàw=ø§IDATH‰í–1à ^†ü±»û˜µŸrëM[&‰"lK)‰æŠ¸fI’p$"Úá˜Y:ÎÒ^PƒK)=ù Ùˆ^‚ˆP >+ ¹I$ÁÝER.9$åî’„ ˲tÝø53¹»J)ÝkùI|¾àN†`†`þAI0³ËûÀ̶>H©©ÒÓÔÌÛ+³)ýu]1MS—`žgäœß—þ3ëú¶DD³ëé” „)ëIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/desktop.png000066400000000000000000000002651276457661000227450ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕC}k2tEXtCommentCreated with The GIMPïd%n+IDAT8Ëcüÿÿ?5•Ë?—‹GÃh4ŒFÃh4ŒFÃhÈ„Ãa#•ßžÔ†IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/desktop.xcf000066400000000000000000000036671276457661000227520ustar00rootroot00000000000000gimp xcf fileBœBœ/ gimp-commentCreated with The GIMPS gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) 5†b¤Empty Layer#2@      ³Ç×@@@1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ 5ÿEmpty Layer#1ÿ     ßó@@@þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿûÿÿþÿþÿþÿÿ ÿ ÿ Empty Layer      .BR@@@@ÿBackground copyÿ     "2þÿÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷þÿÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷þÿÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷Èÿþÿÿÿÿÿ ÿ Backgroundÿ     K_o/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷pybox2d-2.3.2/examples/data/themes/default/dialog.bar.png000066400000000000000000000005111276457661000232700ustar00rootroot00000000000000‰PNG  IHDR\é.&bKGDÿÿÿ ½§“ pHYs  šœtIMEÖ 4-x‡ètEXtCommentCreated with The GIMPïd%n­IDAT8ËcdÀþ3 üg```hZ±†,Óë"B0ÌE¶àÛºMpŽ®µ5I†_>zή òƒ›Íˆn8©ã²f Lâϯ_ Ú–– ¿~ü Èucc†«ÇÃùL ÿÉ s|jæ66Šƒ::ÂƒŠ‰Æ€þ”†=:øóë}ÀÂÆÆÀÆÁA]ƒÙØFã`Ä ¶"v4FóIqà7IÚá¶¢{IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/dialog.close.down.tga000066400000000000000000000012451276457661000245730ustar00rootroot00000000000000  („…ÿ„‚ÿÿ‡‡ ÿÐÐçÿööûÿÐÐçÿ‡‡ ÿÿÿ‚ÿSSfÿÌÌîÿÓÓóÿÔÔóÿÓÓóÿÔÔóÿÓÓóÿÌÌîÿSSfÿÿÿBBWÿ‰©©éÿBBWÿÿ€ ÿzzÖÿ~~ÞÿÿƒÞÿÿ~~ÞÿÞÿzzÖÿ ÿ€ÿ,,XÿTTÔÿ‚ÿTTÔÿ‚ÿTTÔÿ,,Xÿ€ÿÿ!!ÿ**Éÿ))Éÿ…ÿ))Éÿ**Éÿ""ÿ€ÿÿ²ÿƒ¿ÿƒÿƒ¿ÿ²ÿ€ÿÿ²ÿƒ¿ÿƒÿƒ¿ÿ²ÿ€ÿÿÿÉÿÉÿÉÿ…ÿ‚ÉÿŒÿ€ÿÿGÿ??Ôÿ‚ÿ??Ôÿ‚ÿ??ÔÿGÿ€ÿÿXXÔÿ^^Þÿ__Þÿÿ__Þÿ^^Þÿ__Þÿ^^Þÿÿ__Þÿ^^ÞÿXXÔÿÿ€ÿ3ÿ‰éÿ3ÿÿ€ÿ9ÿ””ìÿ‚ŸŸóÿžžóÿŸŸóÿ””ìÿ8ÿÿ‚ÿÿ55nÿÔÿ²²ùÿÔÿ55nÿÿÿ‚„…ÿ„pybox2d-2.3.2/examples/data/themes/default/dialog.close.hover.tga000066400000000000000000000012341276457661000247450ustar00rootroot00000000000000  („…???ÿ„‚???ÿSSTÿ¥¥¸ÿÜÜíÿøøüÿÜÜíÿ¥¥¸ÿSSTÿ???ÿ‚???ÿ~~ŒÿÙÙòÿÞÞöÿßßöÿÞÞöÿßßöÿÞÞöÿÙÙòÿ~~Œÿ???ÿ???ÿqqÿ‰¾¾îÿqqÿ???ÿ€JJJÿ››àÿžžæÿÿƒŸŸæÿÿžžæÿŸŸæÿ››àÿJJJÿ€???ÿaa‚ÿßÿ‚ÿßÿ‚ÿßÿaa‚ÿ€???ÿ???ÿYY«ÿ‚__Öÿ…ÿ‚__ÖÿYY¬ÿ€???ÿ???ÿ??Åÿƒ??Ïÿƒÿƒ??Ïÿ??Åÿ€???ÿ???ÿ??Åÿƒ??Ïÿƒÿƒ??Ïÿ??Åÿ€???ÿ???ÿOO©ÿWWÖÿVVÖÿWWÖÿ…ÿ‚WWÖÿOO©ÿ€???ÿ???ÿMMuÿooßÿ‚ÿooßÿ‚ÿooßÿMMuÿ€???ÿ??Aÿ‚‚ßÿ††æÿ‡‡æÿÿ‡‡æÿ††æÿ‡‡æÿ††æÿÿ‡‡æÿ††æÿ‚‚ßÿ@@Aÿ€???ÿMMfÿ‰ŸŸîÿMMfÿ???ÿ€???ÿQQkÿ¯¯ñÿ‚··öÿ¶¶öÿ··öÿ¯¯ñÿQQjÿ???ÿ‚???ÿAABÿhh’ÿŸŸßÿÅÅúÿŸŸßÿhh’ÿAABÿ???ÿ‚„…???ÿ„pybox2d-2.3.2/examples/data/themes/default/dialog.close.normal.tga000066400000000000000000000011061276457661000251100ustar00rootroot00000000000000  („@@@…@@@ÿ„@@@‚@@@@@@ÿTTUÿ¦¦¹ÿÝÝîÿùùýÿÝÝîÿ¦¦¹ÿTTUÿ@@@ÿ‚@@@@@@@@@ÿÿÚÚóÿßß÷ÿàà÷ÿßß÷ÿàà÷ÿßß÷ÿÚÚóÿÿ@@@ÿ@@@@@@@@@ÿrr‚ÿ‰¿¿ïÿrr‚ÿ@@@ÿ€@@@@@@KKKÿœœáÿ‚ŸŸçÿ„  çÿŸŸçÿ  çÿœœáÿKKKÿ€@@@@@@ÿbbƒÿ‹€€àÿbbƒÿ€@@@ÿ@@@ÿZZ¬ÿ‹``×ÿZZ­ÿ€@@@ÿ@@@ÿ@@Æÿ‹@@Ðÿ@@Æÿ€@@@ÿ@@@ÿ@@Æÿ‹@@Ðÿ@@Æÿ€@@@ÿ@@@ÿPPªÿXX×ÿWW×ÿ„XX×ÿWW×ÿ‚XX×ÿPPªÿ€@@@ÿ@@@ÿNNvÿ‹ppàÿNNvÿ€@@@ÿ@@@@@Bÿƒƒàÿ‡‡çÿ‚ˆˆçÿ‡‡çÿˆˆçÿ‡‡çÿˆˆçÿ‡‡çÿƒƒàÿAABÿ€@@@@@@@@@ÿNNgÿ‰  ïÿNNgÿ@@@ÿ€@@@@@@@@@ÿRRlÿ°°òÿ‚¸¸÷ÿ··÷ÿ¸¸÷ÿ°°òÿRRkÿ@@@ÿ@@@‚@@@@@@ÿBBCÿii“ÿ  àÿÆÆûÿ  àÿii“ÿBBCÿ@@@ÿ‚@@@„@@@…@@@ÿ„@@@pybox2d-2.3.2/examples/data/themes/default/dialog.png000066400000000000000000000005021276457661000225250ustar00rootroot00000000000000‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIMEÕõîºrtEXtCommentCreated with The GIMPïd%n¦IDATHÇí–1à EB¹SĘ8j&¶Lˆ‰ E^èЦ"­:¤NxÅzÆÿß (t, BèwÎ=ˆó<7…§”¸Ñ¹4€1†išš‚1Ü@Dض­)XD†ÃáÁðà´ëº6Ë„= ö ”÷¾ùÏŸL¥kÍrÎXk/cŒ/ýTõVêl>;(ÆxÈâ­Þú À²,Wd9pÕ—Þ_O™Þ1@ø‹ "IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/dot.down.png000066400000000000000000000010451276457661000230250ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ&~S-stEXtCommentCreated with The GIMPïd%n‰IDAT8Ë¥“;,ÃQÆ÷ŸÏ‰x$ˆ#1x³U"Dl»`&›ALlÒÉ`0• H<"1P<IEú Úþ=†zU[iã[ÎÍ99ß9ç;÷(bCâøÕo‡ñ;±¨¸D¦ç8¹qb¾¼b¾¼rrãdz~¢âùƒéÇGÎÜOræ~’ O¤uÜy¤{`8‚ä³%iíéghf–D07>Êβ @)€¬ìÙ8@§¦Å ôá>›XÛ›x|ð* H©¥ƒË@~E©¥ƒÓ›h_e^ÿ‡ü‚Šû+ž[aV5Š p]P^I!¿<î¨IAäÝ^‘YÓ‚(…’è5KX눘ïÒÁý'ÁÛþ&e–¶¤*Û·¿:Pî½-)Ô’žñC¿€¡Â¾ßÁ€ŸÝýíïHnu#‹ë U·öuâ:>Œ ÂÚf&–VÉLK™è3Ÿ™êíÂydyXbh-õƒc2i?—5WPÖ\A™´ŸKýà˜ZG“úï9¿싪±?›bIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/dot.hover.png000066400000000000000000000010441276457661000232000ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ&]L_tEXtCommentCreated with The GIMPïd%nˆIDAT8Ë¥“Í+DaÆw¼H³ð&$Y aCL³r³“¤(›òGXøØ`ce'R²¥$ÙH±›f(a1¢L¾ÆmÌu羓ÛÌex6oÞóœç<=GQU•,d‡’Y™å• ŒŽájo§¦´€Û§|~?›k«2òpŸF¤¤(=½ O D’ט)¯al¬,s¸»c‘|)­]¨/á˜üÕã%ú¦qrx EØívšG¸~{·>Ú”ïͦLÖ›G|hš†¤£ÍMH— Çù-mn®Žö¥x¯kà&#èõp´Ÿôà®´´xNWYFÿ  $¦ÈÙb™”ͼLcc¡Kž¿Ì‹ŽÖŽœ&_],ÊëY@– È+(LÛ)5D©ÁJèqNÏŽ±r€iâ_š§jáWÓ·gfâ{”ËœÍ OÏQTŸuÿ˜þÁúì$Ás+ÊJÆ5J[žÀÙ݇«»gm ÁÐ-¾½‚{Û˜ ãÇcúÓ9†Œ=OÏd"IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/dot.normal.png000066400000000000000000000005561276457661000233540ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÕ^1\£tEXtCommentCreated with The GIMPïd%nÖIDAT(ÏuѱJQ…áïÆËŠZ)ØYÄÁÂÎÖÎ7Ê+Ylµ²0ZZ  "A š±Èn²ÁÍ›9wæÌLêY«Pª‚\%]:R`æÍM¼—¢Ôƒ¸p®U+0wï–´¨gº¾­Ó5õRfOǧÿt¼˜Ê¢íC3mÏ‘)Œ+ãå@ÉöbŠ/³ ~Y³ÞHfËþZƒXîi²LoøýŠ, cg¹Ð:?†¤L¸sÕ ¸¥É4ÒWØ­½B߈TÝ‚h9uâcOÍK§Uó47ˆAùÿþ7³Ìié´IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/dot.xcf000066400000000000000000000036121276457661000220550ustar00rootroot00000000000000gimp xcf fileBB/ gimp-commentCreated with The GIMPS gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) ýqá{Empty Layer#3ÿ     §»Ë‘ ÿ ÿ ÿ ÿ ÿÿ‘ À À À À ÀÀ‘ À À À À ÀÀ‘ü+*++*+ûU Uùw€€÷€€wþªªþý!ÆÕÕÔüÕÆ ÷I«ïï«IEmpty Layer#2ÿ     /?ÿ ÿ ÿ ÿ ÿ ÿ‘ÿ ÿ ÿ ÿ ÿ ÿ‘ÿ ÿ ÿ ÿ ÿ ÿ‘÷ˆÑ÷÷шõTÍÔÔÕÔÕÔÍTþCªªþCý{€ø€{-U Uø-"++*++*ý+# Empty Layerÿ     ‰­À À À À À À À À À À À À ÀÀ÷I«ïï«Iý'íÿÿýí'þ'ÿÿþ'ýíÿÿúíIÿ ÿûI«ÿ ÿû«ïÿ ÿûïïÿ ÿûï«ÿ ÿû«Iÿ ÿúIíÿÿýíþ'ÿÿþ'ý'íÿÿýí'÷I«ïï«I Backgroundÿ     *>Nÿ ÿ ÿ ÿ ÿþÿ^ÿþÿ ÿ ÿ ÿ ÿÿpybox2d-2.3.2/examples/data/themes/default/down.png000066400000000000000000000003121276457661000222340ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ 4y»çtEXtCommentCreated with The GIMPïd%n2IDAT(Ïc`€JÿÇ%ÇçþÇ®•Iè?“Q ”0âvÓ¬®aÀj ÙP¿ Ò'¢dIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/filebrowser.folder.png000066400000000000000000000011721276457661000250670ustar00rootroot00000000000000‰PNG  IHDR/Ä<ðAIDAT8­ÔMKTQÀñÿÔ” M3ˆƒ‹Ç[HM‚/©Ì,Ú"—ÑÊe´ û~‚hш¢¸pÛÜ)ÂÊD-,˲73|IÆÇ;sï9çi¡CZ£nzàð8çüx8o>ᆿұm[²Ù,¶m³ð~ßÑì§ã•1*c¹\ŽL&C<÷U}"B:–Çc÷H´’èl¥ùtÙWŸ¸4x—Þö(½íQ.^h¦+ÖDvbžö###ûƒÃÃÃÒ×ÙF_ÓO”2h­PJã¹ ÏS(Oá)ç)Ê®¢ÿæCüÇëH¥RX–µöƒAž<Ÿ%<†ëþ”= ùÊÔG œŠ2a_aîÍ ²33X–õïÆãql;C¡ä'¿þ §èPÜ,s"%ÐØBk[=õ଀³ ’ãÑä$ÁpLJµ צ¹£{(.‚³ ²„¬-b Æ2ão¹uçzu0™LúÉçòœéì'Tz¬|#ˆŒÖh£·³V­™žûVYW½B§¸ÅÉZ…·áb´Æh…6JVZs¤&XíwƒBm Ï-SÚÌcŒBë]UíÀZkÖsE"‘Èa 44ÅØZ™§TÌï©ÊSŠrÙÅqÊÌ.¬2öì#‘H÷á`aí;u…|npy9ûƒw_Ö˜þ°Ì×5Ž®7ªz±D„øù˜8ùE¹wûª ^>+çZ …IJ,I¥R255%•¹5_åsH§Ó2::J("‘HL&÷}¯Åo{T{.wTºIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/generate.py000066400000000000000000000066561276457661000227440ustar00rootroot00000000000000import pygame from pygame.locals import * pygame.display.init() pygame.display.set_mode((80,80),32) def prep(name): fname = name+".png" img = pygame.image.load(fname) w,h = img.get_width()/2,img.get_height()/2 out = pygame.Surface((w*3,h*3),SWSURFACE|SRCALPHA,32) out.fill((0,0,0,0)) out.blit(img.subsurface(0,0,w,h),(0,0)) out.blit(img.subsurface(w,0,w,h),(w*2,0)) out.blit(img.subsurface(0,h,w,h),(0,h*2)) out.blit(img.subsurface(w,h,w,h),(w*2,h*2)) for i in range(0,w): img = out.subsurface((w-1,0,1,h*3)).convert_alpha() out.blit(img,(w+i,0)) for i in range(0,h): img = out.subsurface((0,h-1,w*3,1)).convert_alpha() out.blit(img,(0,h+i)) return out,w,h todo = [ ('button.normal','dot.normal',None,3,3,'789456123'), ('button.hover','dot.hover',None,3,3,'789456123'), ('button.down','dot.down',None,3,3,'789456123'), ('checkbox.off.normal','box.normal',None,2,2,'7913'), ('checkbox.on.normal','box.down','check',2,2,'7913'), ('checkbox.off.hover','box.hover',None,2,2,'7913'), ('checkbox.on.hover','box.hover','check',2,2,'7913'), ('radio.off.normal','dot.normal',None,2,2,'7913'), ('radio.on.normal','dot.down','radio',2,2,'7913'), ('radio.off.hover','dot.hover',None,2,2,'7913'), ('radio.on.hover','dot.hover','radio',2,2,'7913'), ('tool.normal','box.normal',None,3,3,'789456123'), ('tool.hover','box.hover',None,3,3,'789456123'), ('tool.down','box.down',None,3,3,'789456123'), ('hslider','idot.normal',None,3,3,'789456123'), ('hslider.bar.normal','dot.normal',None,3,3,'789456123'), ('hslider.bar.hover','dot.hover',None,3,3,'789456123'), ('hslider.left','sbox.normal','left',2,2,'7913'), ('hslider.right','sbox.normal','right',2,2,'7913'), ('vslider','idot.normal',None,3,3,'789456123'), ('vslider.bar.normal','vdot.normal',None,3,3,'789456123'), ('vslider.bar.hover','vdot.hover',None,3,3,'789456123'), ('vslider.up','vsbox.normal','up',2,2,'7913'), ('vslider.down','vsbox.normal','down',2,2,'7913'), ('dialog.close.normal','rdot.hover',None,2,2,'7913'), ('dialog.close.hover','rdot.hover','x',2,2,'7913'), ('dialog.close.down','rdot.down','x',2,2,'7913'), ('menu.normal','desktop',None,1,1,'7'), ('menu.hover','box.normal',None,3,3,'789456123'), ('menu.down','box.down',None,3,3,'789456123'), ('select.selected.normal','box.normal',None,3,3,'788455122'), ('select.selected.hover','box.hover',None,3,3,'788455122'), ('select.selected.down','box.down',None,3,3,'788455122'), ('select.arrow.normal','box.hover',None,3,3,'889556223'), ('select.arrow.hover','box.hover',None,3,3,'889556223'), ('select.arrow.down','box.down',None,3,3,'889556223'), ('progressbar','sbox.normal',None,3,3,'789456123'), ('progressbar.bar','box.hover',None,3,3,'789456123'), ] for fname,img,over,ww,hh,s in todo: print(fname) img,w,h = prep(img) out = pygame.Surface((ww*w,hh*h),SWSURFACE|SRCALPHA,32) out.fill((0,0,0,0)) n = 0 for y in range(0,hh): for x in range(0,ww): c = int(s[n]) xx,yy = (c-1)%3,2-(c-1)/3 out.blit(img.subsurface((xx*w,yy*h,w,h)),(x*w,y*h)) n += 1 if over != None: over = pygame.image.load(over+".png") out.blit(over,(0,0)) pygame.image.save(out,fname+".tga") pybox2d-2.3.2/examples/data/themes/default/hslider.bar.hover.tga000066400000000000000000000014101276457661000245730ustar00rootroot00000000000000  („@@@@@@ÿ„@@@‚@@@@@@ÿVUTÿ¹¶§ÿîëÞÿ‰ýüùÿîëÞÿ¹¶§ÿVUTÿ@@@ÿ‚@@@@@@@@@ÿ‹ÿóïÛÿ÷óßÿˆ÷óáÿ÷óßÿ÷óáÿ÷óßÿóïÛÿ‹ÿ@@@ÿ@@@@@@@@@ÿ‚rÿ‘ïæ¿ÿ‚rÿ@@@ÿ€@@@@@@KKKÿáÕÿ‚çÚŸÿŒçÛ¡ÿçÚŸÿçÛ¡ÿáÕÿKKKÿ€@@@@@@ÿ„~bÿ“àÏ€ÿ„~bÿ€@@@ÿ@@@ÿ¬Zÿ“×Âaÿ­Ÿ[ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿªšPÿ×ÁYÿ×ÀWÿŒ×ÁYÿ×ÀWÿ‚×ÁYÿªšPÿ€@@@ÿ@@@ÿvoNÿ“àÌpÿvoNÿ€@@@ÿ@@@BB@ÿàЄÿçÖ‡ÿ‚çÖ‰ÿˆçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿàЄÿCBAÿ€@@@@@@@@@ÿgcOÿ‘ïá¡ÿgcOÿ@@@ÿ€@@@@@@@@@ÿlgRÿòæ°ÿŠ÷ì¹ÿ÷ë·ÿ÷ì¹ÿòæ°ÿlgRÿ@@@ÿ@@@‚@@@@@@ÿDCBÿ“ŒiÿàÕ ÿ‰ûòÇÿàÕ ÿ“ŒiÿDCBÿ@@@ÿ‚@@@„@@@@@@ÿ„@@@pybox2d-2.3.2/examples/data/themes/default/hslider.bar.normal.tga000066400000000000000000000013311276457661000247420ustar00rootroot00000000000000  („ÿ„‚ÿ”””ÿÝÝÝÿùùùÿ‰ÿÿÿÿùùùÿÝÝÝÿ”””ÿÿ‚ÿ¿¿¿ÿøøøÿúúúÿøøøÿ¿¿¿ÿÿÿ´´´ÿ‘ðððÿ´´´ÿÿ€ŠŠŠÿáááÿ‘ãããÿáááÿŠŠŠÿ€ÿªªªÿ“ÒÒÒÿªªªÿ€ÿÿ°°°ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ±±±ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿªªªÿ»»»ÿºººÿŒ»»»ÿºººÿ‚»»»ÿªªªÿ€ÿÿ™™™ÿ“ËËËÿ™™™ÿ€ÿ€€€ÿÔÔÔÿ‘ØØØÿÔÔÔÿ€€€ÿ€ÿ•••ÿ‘åååÿ•••ÿÿ€ÿ™™™ÿëëëÿïïïÿëëëÿ™™™ÿÿ‚ÿÿ³³³ÿâââÿ‰ôôôÿâââÿ³³³ÿÿÿ‚„ÿ„pybox2d-2.3.2/examples/data/themes/default/hslider.left.tga000066400000000000000000000005641276457661000236500ustar00rootroot00000000000000  (þþþ~~~ÿ€þþþ~~~ÿþþþÿ€~~~ÿ~~~ÿûûûÿ€~~~ÿ~~~ÿ‡öööÿÿ„öööÿ€~~~ÿ~~~ÿ†ïïïÿÿ„ïïïÿ€~~~ÿ~~~ÿ…çççÿ‚ÿ„çççÿ€~~~ÿ~~~ÿ‚ÞÞÞÿÝÝÝÿƒÿÝÝÝÿÞÞÞÿ‚ÝÝÝÿ€~~~ÿ~~~ÿƒÓÓÓÿ„ÿ„ÓÓÓÿ€~~~ÿ~~~ÿƒÓÓÓÿ„ÿ„ÓÓÓÿ€~~~ÿ~~~ÿ„ÛÛÛÿƒÿ„ÛÛÛÿ€~~~ÿ~~~ÿ…ãããÿ‚ÿ„ãããÿ€~~~ÿ~~~ÿ†êêêÿÿ„êêêÿ€~~~ÿ~~~ÿ‡ðððÿÿ„ðððÿ€~~~ÿ~~~ÿõõõÿ€~~~ÿ~~~ÿùùùÿ€~~~ÿþþþ~~~ÿ€þþþpybox2d-2.3.2/examples/data/themes/default/hslider.right.tga000066400000000000000000000005641276457661000240330ustar00rootroot00000000000000  (þþþ~~~ÿ€þþþ~~~ÿþþþÿ€~~~ÿ~~~ÿûûûÿ€~~~ÿ~~~ÿ„öööÿÿ‡öööÿ€~~~ÿ~~~ÿ„ïïïÿÿ†ïïïÿ€~~~ÿ~~~ÿ„çççÿ‚ÿ…çççÿ€~~~ÿ~~~ÿ‚ÞÞÞÿÝÝÝÿƒÿÝÝÝÿÞÞÞÿ‚ÝÝÝÿ€~~~ÿ~~~ÿ„ÓÓÓÿ„ÿƒÓÓÓÿ€~~~ÿ~~~ÿ„ÓÓÓÿ„ÿƒÓÓÓÿ€~~~ÿ~~~ÿ„ÛÛÛÿƒÿ„ÛÛÛÿ€~~~ÿ~~~ÿ„ãããÿ‚ÿ…ãããÿ€~~~ÿ~~~ÿ„êêêÿÿ†êêêÿ€~~~ÿ~~~ÿ„ðððÿÿ‡ðððÿ€~~~ÿ~~~ÿõõõÿ€~~~ÿ~~~ÿùùùÿ€~~~ÿþþþ~~~ÿ€þþþpybox2d-2.3.2/examples/data/themes/default/hslider.tga000066400000000000000000000023171276457661000227150ustar00rootroot00000000000000  (‚€€€ÿÿÿ£££ÿªªªÿˆ®®®ÿ°°°ÿ®®®ÿªªªÿ‚ÿÿÿ€€€€€€ÿÿÿ£££ÿ®®®ÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿ¼¼¼ÿ®®®ÿÿÿÿ€€€€€€€ÿÿÿ£££ÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿµµµÿÿÿÿÿÿÿ£££ÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿµµµÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿ£££ÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€¼¼¼ÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ°°°ÿÎÎÎÿéééÿùùùÿýýýÿŠþþþÿÿÿÿÿ‚þþþÿýýýÿùùùÿéééÿ€ÎÎÎÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿÿÿÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿÿÿÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿÿÿÿ€€€ÿÿÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿ‚ÿÿÿ€€€‚ÿÿÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿƒÿÿÿ€€€€pybox2d-2.3.2/examples/data/themes/default/idot.normal.png000066400000000000000000000006301276457661000235160ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGD€G5  pHYs  šœtIMEÖ  &Pw6tEXtCommentCreated with The GIMPïd%nIDAT(ÏmÑMŠqð_ýÓ¦“Œ(…(Þb–s„ì\Ìy’œÅœÁÇB`hg|Ñéra´3`­¼÷¨zõb–Ød­Rô:kÄ K›¼óÎÔDHG/¾k±²´É¹Fcf¬èíµZ‹ Ò&ç>j¼W«„Ô9yÖÚZDÅFcnj$@åNˆ¯ùÉg¼U]iH_v~(µ©™úŸûÏ„‘ÚÌT©LŒ_¹ÿJ*c¥冾EE(½ÔË›íê¥Ò9:ënˆá̳£ò{'—W’tq²÷/×ÃÒÅÁ³‘ø–ÿÿä}PÖXÄÖÖΓÖO­';[÷ah¾çÐæÃ5íÚol^ae¢³ÂIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/input.focus.png000066400000000000000000000002651276457661000235510ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ(%¹tEXtCommentCreated with The GIMPïd%n+IDAT8Ëc` `d``øÿÿ?¥¦022QËE£4jШA£ ƒ¨;…,;)k“IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/input.normal.png000066400000000000000000000003201276457661000237120ustar00rootroot00000000000000‰PNG  IHDRoª¯bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ +–ðrctEXtCommentCreated with The GIMPïd%n4IDAT8Ëclhh` `a``HHH Ð” 01P Œ4jШA£4t bÔ”J”‘¡Å-IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/left.png000066400000000000000000000003211276457661000222170ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ tOuˆtEXtCommentCreated with The GIMPïd%n9IDAT(Ïc`ð™Ã„_SÁtõLø¥á þãÆæì þ300bSÀˆÕ‘Œ¸­`$9 èùl ¦’IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/list.item.down.png000066400000000000000000000002761276457661000241540ustar00rootroot00000000000000‰PNG  IHDRoª¯bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ)ïvŸtEXtCommentCreated with The GIMPïd%n"IDAT8Ëc<òõ?5•À¨A£4jШA£‘AÊè)£ðNIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/list.item.hover.png000066400000000000000000000002541276457661000243240ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/list.item.normal.png000066400000000000000000000002541276457661000244710ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/list.png000066400000000000000000000002011276457661000222350ustar00rootroot00000000000000‰PNG  IHDR„ž„HIDAT8íÔ± @!EÑ‹‹Á*LÆ*lƯLŒ•ÄîÇ[¿S‚TfV4ËLU-€ˆ8†îÀèÂu?Zjëá‡ç‰6÷ró >8‘Øîê¼IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/listitem.down.tga000066400000000000000000000042621276457661000240640ustar00rootroot00000000000000 $ôïÖÿôîÔÿôîÔÿôïÖÿôïÖÿôîÔÿôîÔÿôïÖÿôîÔÿôîÔÿôïÖÿôïÖÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôïÖÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿË®+ÿË®+ÿË®+ÿÊ®*ÿÊ®*ÿË®+ÿÊ®*ÿË®+ÿË®+ÿË®+ÿÊ®*ÿÊ®*ÿË®+ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿË®+ÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿʬ ÿË­ÿË­ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿË­ÿʬ ÿË­ÿË­ÿʬ ÿʬ ÿʬ ÿʬ ÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÉaÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÉaÿßÈ_ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿpybox2d-2.3.2/examples/data/themes/default/listitem.hover.tga000066400000000000000000000042621276457661000242400ustar00rootroot00000000000000 $÷óßÿ÷óßÿ÷óáÿ÷óáÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óáÿ÷óáÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÚŸÿçÚŸÿçÚŸÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿ×Âaÿ×Âaÿ×Â_ÿ×Â_ÿ×Âaÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Âaÿ×Âaÿ×Â_ÿ×Â_ÿ×Âaÿ×Â_ÿ×Â_ÿ×Â_ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿ×ÀWÿ×ÀWÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÀWÿ×ÀWÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‰ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‰ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿpybox2d-2.3.2/examples/data/themes/default/listitem.normal.tga000066400000000000000000000044221276457661000244030ustar00rootroot00000000000000 $ÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿpybox2d-2.3.2/examples/data/themes/default/menu.down.tga000066400000000000000000000010201276457661000231630ustar00rootroot00000000000000  (•ÿ€ÿ•ÿÿÿÿ€ÿÿôïÖÿôîÔÿôïÖÿ‰ôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿ€ÿÿ•êߪÿ€ÿÿ…ßÎÿˆßÎÿßÎÿ„ßÎÿ€ÿÿ•Õ¾Uÿ€ÿÿ‚Ë®+ÿÊ®*ÿË®+ÿˆÊ®*ÿË®+ÿÊ®*ÿË®+ÿ‚Ê®*ÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿʬ ÿË­ÿ‹Ê¬ ÿË­ÿʬ ÿË­ÿʬ ÿ€ÿÿ•Õ»Aÿ€ÿÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿ‹ßÈ_ÿßÉaÿßÈ_ÿ€ÿÿ•ê×€ÿ€ÿÿ•ôå ÿ€ÿÿ•ÿôÁÿ€ÿ•ÿ€pybox2d-2.3.2/examples/data/themes/default/menu.hover.tga000066400000000000000000000006711276457661000233520ustar00rootroot00000000000000  (•ÿ€ÿ•ÿÿÿÿ€ÿÿ•úúúÿ€ÿÿ•ðððÿ€ÿÿ•ãããÿ€ÿÿ•ÒÒÒÿ€ÿÿ‚ÀÀÀÿ¿¿¿ÿÀÀÀÿˆ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ‚¿¿¿ÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ»»»ÿºººÿ‹»»»ÿºººÿ»»»ÿºººÿ»»»ÿ€ÿÿ•ËËËÿ€ÿÿ•ØØØÿ€ÿÿ•åååÿ€ÿÿ•ïïïÿ€ÿÿ•÷÷÷ÿ€ÿ•ÿ€pybox2d-2.3.2/examples/data/themes/default/menu.normal.tga000066400000000000000000000001161276457661000235110ustar00rootroot00000000000000 (‹ÿÿÿÿ‹ÿÿÿÿ‹÷÷÷ÿ‹÷÷÷ÿ‹ÿÿÿÿ‹ÿÿÿÿ‹÷÷÷ÿ‹÷÷÷ÿ‹ÿÿÿÿ‹ÿÿÿÿ‹÷÷÷ÿ‹÷÷÷ÿpybox2d-2.3.2/examples/data/themes/default/notes.txt000066400000000000000000000001541276457661000224540ustar00rootroot00000000000000dot and box.xcf: color -170 .down .hover +64 brightness .normal, grayscale +127 brightness, +48 contrast pybox2d-2.3.2/examples/data/themes/default/out.tga000066400000000000000000000014331276457661000220700ustar00rootroot00000000000000  („``````ÿ„```‚``````ÿqqqÿ¹¹¹ÿæææÿ‰ûûûÿæææÿ¹¹¹ÿqqqÿ```ÿ‚`````````ÿ˜˜˜ÿæææÿêêêÿˆëëëÿêêêÿëëëÿêêêÿæææÿ˜˜˜ÿ```ÿ`````````ÿŽŽŽÿ‘ÖÖÖÿŽŽŽÿ```ÿ€``````iiiÿ¾¾¾ÿ‚ÁÁÁÿŒÂÂÂÿÁÁÁÿÂÂÂÿ¾¾¾ÿiiiÿ€``````ÿ„„„ÿ“­­­ÿ„„„ÿ€```ÿ```ÿŠŠŠÿ™™™ÿ˜˜˜ÿ™™™ÿ˜˜˜ÿ™™™ÿŠŠŠÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ„„„ÿ”””ÿ“““ÿŒ”””ÿ“““ÿ‚”””ÿƒƒƒÿ€```ÿ```ÿuuuÿ“¤¤¤ÿuuuÿ€```ÿ``````ÿ®®®ÿ³³³ÿ‚´´´ÿˆ³³³ÿ´´´ÿ³³³ÿ´´´ÿ³³³ÿ®®®ÿaaaÿ€`````````ÿrrrÿ‘ÄÄÄÿrrrÿ```ÿ€`````````ÿuuuÿÍÍÍÿŠÔÔÔÿÓÓÓÿÔÔÔÿÍÍÍÿuuuÿ```ÿ```‚``````ÿaaaÿŒŒŒÿÀÀÀÿ‰ÝÝÝÿÀÀÀÿŒŒŒÿaaaÿ```ÿ‚```„``````ÿ„```pybox2d-2.3.2/examples/data/themes/default/progressbar.bar.tga000066400000000000000000000010631276457661000243540ustar00rootroot00000000000000  (@@@•@@@ÿ€@@@@@@ÿ•ÿÿÿÿ€@@@ÿ@@@ÿ÷óáÿ÷óßÿ÷óáÿ‰÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ@@@ÿ•ïæ¿ÿ€@@@ÿ@@@ÿ…çÛ¡ÿˆçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ@@@ÿ•àÏ€ÿ€@@@ÿ@@@ÿ‚×Âaÿ×Â_ÿ×Âaÿˆ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ×ÁYÿ×ÀWÿ‹×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ@@@ÿ•àÌpÿ€@@@ÿ@@@ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿ‹çÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ@@@ÿ•ïá¡ÿ€@@@ÿ@@@ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿŠ÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ@@@ÿ•ÿ÷Ñÿ€@@@ÿ@@@•@@@ÿ€@@@pybox2d-2.3.2/examples/data/themes/default/progressbar.tga000066400000000000000000000006341276457661000236140ustar00rootroot00000000000000  (ÿÿÿ•ÿ€ÿÿÿÿ•ÿÿÿÿ€ÿÿ•üüüÿ€ÿÿ•÷÷÷ÿ€ÿÿ•ðððÿ€ÿÿ•èèèÿ€ÿÿ‚ßßßÿÞÞÞÿßßßÿˆÞÞÞÿßßßÿÞÞÞÿßßßÿ‚ÞÞÞÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÜÜÜÿ€ÿÿ•äääÿ€ÿÿ•ëëëÿ€ÿÿ•ñññÿ€ÿÿ•öööÿ€ÿÿ•úúúÿ€ÿÿÿÿ•ÿ€ÿÿÿpybox2d-2.3.2/examples/data/themes/default/radio.off.hover.tga000066400000000000000000000011061276457661000242470ustar00rootroot00000000000000  („@@@…@@@ÿ„@@@‚@@@@@@ÿVUTÿ¹¶§ÿîëÞÿýüùÿîëÞÿ¹¶§ÿVUTÿ@@@ÿ‚@@@@@@@@@ÿ‹ÿóïÛÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿóïÛÿ‹ÿ@@@ÿ@@@@@@@@@ÿ‚rÿ‰ïæ¿ÿ‚rÿ@@@ÿ€@@@@@@KKKÿáÕÿ‚çÚŸÿ„çÛ¡ÿçÚŸÿçÛ¡ÿáÕÿKKKÿ€@@@@@@ÿ„~bÿ‹àÏ€ÿ„~bÿ€@@@ÿ@@@ÿ¬Zÿ‹×Âaÿ­Ÿ[ÿ€@@@ÿ@@@ÿÆ®@ÿ‹Ð·@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ‹Ð·@ÿÆ®@ÿ€@@@ÿ@@@ÿªšPÿ×ÁYÿ×ÀWÿ„×ÁYÿ×ÀWÿ‚×ÁYÿªšPÿ€@@@ÿ@@@ÿvoNÿ‹àÌpÿvoNÿ€@@@ÿ@@@BB@ÿàЄÿçÖ‡ÿ‚çÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿàЄÿCBAÿ€@@@@@@@@@ÿgcOÿ‰ïá¡ÿgcOÿ@@@ÿ€@@@@@@@@@ÿlgRÿòæ°ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿòæ°ÿlgRÿ@@@ÿ@@@‚@@@@@@ÿDCBÿ“ŒiÿàÕ ÿûòÇÿàÕ ÿ“ŒiÿDCBÿ@@@ÿ‚@@@„@@@…@@@ÿ„@@@pybox2d-2.3.2/examples/data/themes/default/radio.off.normal.tga000066400000000000000000000010311276457661000244110ustar00rootroot00000000000000  („…ÿ„‚ÿ”””ÿÝÝÝÿùùùÿÿÿÿÿùùùÿÝÝÝÿ”””ÿÿ‚ÿ¿¿¿ÿøøøÿ…úúúÿøøøÿ¿¿¿ÿÿÿ´´´ÿ‰ðððÿ´´´ÿÿ€ŠŠŠÿáááÿ‰ãããÿáááÿŠŠŠÿ€ÿªªªÿ‹ÒÒÒÿªªªÿ€ÿÿ°°°ÿÀÀÀÿ¿¿¿ÿ…ÀÀÀÿ¿¿¿ÿÀÀÀÿ±±±ÿ€ÿÿ§§§ÿ‹ªªªÿ§§§ÿ€ÿÿ§§§ÿ‹ªªªÿ§§§ÿ€ÿÿªªªÿ»»»ÿºººÿ„»»»ÿºººÿ‚»»»ÿªªªÿ€ÿÿ™™™ÿ‹ËËËÿ™™™ÿ€ÿ€€€ÿÔÔÔÿ‰ØØØÿÔÔÔÿ€€€ÿ€ÿ•••ÿ‰åååÿ•••ÿÿ€ÿ™™™ÿëëëÿ…ïïïÿëëëÿ™™™ÿÿ‚ÿÿ³³³ÿâââÿôôôÿâââÿ³³³ÿÿÿ‚„…ÿ„pybox2d-2.3.2/examples/data/themes/default/radio.on.hover.tga000066400000000000000000000011751276457661000241170ustar00rootroot00000000000000  („…???ÿ„‚???ÿUTSÿ¸µ¦ÿíêÝÿüûøÿíêÝÿ¸µ¦ÿUTSÿ???ÿ‚???ÿŒŠ~ÿòîÚÿöòÞÿöòàÿöòÞÿöòàÿöòÞÿòîÚÿŒŠ~ÿ???ÿ???ÿ~qÿ‰îå¾ÿ~qÿ???ÿ€JJJÿàÔœÿ‚æÙžÿ„æÚ ÿæÙžÿæÚ ÿàÔœÿJJJÿ€???ÿƒ}aÿ„ßÎÿÿ„ßÎÿƒ}aÿ€???ÿ???ÿ«œYÿƒÖÁ`ÿƒÿƒÖÁ`ÿ¬žZÿ€???ÿ???ÿÅ­?ÿ‚϶?ÿ…ÿ‚϶?ÿÅ­?ÿ€???ÿ???ÿÅ­?ÿ‚϶?ÿ…ÿ‚϶?ÿÅ­?ÿ€???ÿ???ÿ©™OÿÖÀXÿÖ¿VÿÖÀXÿƒÿÖ¿Vÿ‚ÖÀXÿ©™Oÿ€???ÿ???ÿunMÿ„ßËoÿÿ„ßËoÿunMÿ€???ÿAA?ÿßσÿæÕ†ÿ‚æÕˆÿæÕ†ÿæÕˆÿæÕ†ÿæÕˆÿæÕ†ÿßσÿBA@ÿ€???ÿfbNÿ‰îà ÿfbNÿ???ÿ€???ÿkfQÿñå¯ÿ‚öë¸ÿöê¶ÿöë¸ÿñå¯ÿkfQÿ???ÿ‚???ÿCBAÿ’‹hÿßÔŸÿúñÆÿßÔŸÿ’‹hÿCBAÿ???ÿ‚„…???ÿ„pybox2d-2.3.2/examples/data/themes/default/radio.on.normal.tga000066400000000000000000000012061276457661000242570ustar00rootroot00000000000000  („…ÿ„‚ÿÿ œˆÿçãÑÿûú÷ÿçãÑÿ œˆÿÿÿ‚ÿgcSÿîèÌÿóíÓÿóîÕÿóíÓÿóîÕÿóíÓÿîèÌÿgcSÿÿÿXTBÿ‰éÞ©ÿXTBÿÿ€ ÿÖÆzÿ‚ÞÍ~ÿ„ÞÍ€ÿÞÍ~ÿÞÍ€ÿÖÆzÿ ÿ€ÿXP,ÿ„Ô½Tÿÿ„Ô½TÿXP,ÿ€ÿÿ|!ÿÊ­*ÿÉ­)ÿÊ­*ÿƒÿÊ­*ÿÉ­)ÿÊ­*ÿ}"ÿ€ÿÿ³“ÿ‚¿ÿ…ÿ‚¿ÿ³“ÿ€ÿÿ³“ÿ‚¿ÿ…ÿ‚¿ÿ³“ÿ€ÿÿŽxÿÉ«ÿʬÿÉ«ÿƒÿʬÿ‚É«ÿŒwÿ€ÿÿG=ÿ„Ôº@ÿÿ„Ôº@ÿG=ÿ€ÿÿÔ¾XÿÞÇ^ÿ‚ÞÈ`ÿÞÇ^ÿÞÈ`ÿÞÇ^ÿÞÈ`ÿÞÇ^ÿÔ¾Xÿÿ€ÿ4.ÿ‰éÖÿ4.ÿÿ€ÿ93ÿìÜ”ÿ…óäŸÿìÜ”ÿ93ÿÿ‚ÿÿoe5ÿÔÅ€ÿùì³ÿÔÅ€ÿoe5ÿÿÿ‚„…ÿ„pybox2d-2.3.2/examples/data/themes/default/radio.png000066400000000000000000000003051276457661000223650ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ=˜£htEXtCommentCreated with The GIMPïd%n)IDAT8Ëc`4ÿ¡'`$ ™ ZF"5ãTÏD©)öÅ8 ¨k:.=ßÝIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/rdot.down.png000066400000000000000000000010151276457661000232040ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  †tEXtCommentCreated with The GIMPïd%nqIDAT8Ë¥“±KQÇ?'WF‚ "('œý E´9GcCAqÍ945tsÒ`[S mƒâàTƒ§àPÐ,ˆBÂyšæk0;SPú.~ïý¾ßï{¿ï“˜ 1§.M|Ó1E÷†AÃ4Ú6CÛ¦ašÜ1EÓänF‘:>ÆH§Yñûw%ÂYý>××dŸžœÞ 8I&¹I¥XçÙ,ÅâD6‚Añªë¬É²Ë›4ãeÆnzƒ{™ ŸŽ$BSUFootYšªòP« `ײ°êuÊìÙÇÝ^¯Ç l}|,¥°9gŒKCx‡9æÛwYŸ bYÐlŽ òß߯ãK)ªUÇ”o·Ñ(ë««^®¹ƒÕýú¢P*y<‰D(DN×a&C¹Õú“±‰ð|y‰?˜yÿ¾eqtuÅK£ñ'ÊÎqÙçã,‘àTÓØÞÙà½Rá.—ã¶\f8yú¤ÿ~ç9ðŒ„-°IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/rdot.hover.png000066400000000000000000000010211276457661000233550ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ/÷ÙwtEXtCommentCreated with The GIMPïd%nuIDAT8Ë¥“±KaÆg' …Z9µe›G»®A‚DÿC[Sõ7D“Ð*sã¡ :ˆÃé’ˆ)Ò©×} êuÊ VÏòÂ÷ñ=ïó>ßóJªªâ;¤ùyþáF(ÄE*Åa<ÎZ4 À‡®SÔ4r9ñÞjÍI"™Hpyv†ìõNn%®æhÄýã#ùBÁ&™*'dT³ÑÀd12ªJ¿×ã¥\€$øý~ÒŠ‚Q¯;¦•\œ«I+ Z¥B¿ßGÄq8ŒÐu,ãp˜çZMÈ»†Á§³ûP†Cž§l5›¿ê°9©þ @__gßçûù27óæŒ­t:c‚’eq‰üªs©V³H¥nW ²*˳ !rk`š”^_±s`·Å"w©ÔRݯs9¬ éL”÷nÎÏñú|®ó ƒ«l–·vÛŽ²4·bÅãátg‡d<Îv,@£Z%¯i@AQ`²M qw%—´aÔ&»³;³#Kä_)š¢hšÛNØÁÔË\ÔC1‚|®Ùðƒ ÿ `CÙ:K¹‹jàÕÞö 1Í-›5§zSõ°/3¢€+g+øç²sc]¥R©§§Ô56'š,ȰïÈ.žÝ¸—µÒ&ÍH“œ¬ˆûå3<²6nÝJIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/right.png000066400000000000000000000003161276457661000224060ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ Ž@HëtEXtCommentCreated with The GIMPïd%n6IDAT(Ïc` 3ø)ÄDH !S˜°[ô¯†ÿŒp%L„Ü͈Õ~Fün`ÄïHFŠ[ OïtIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/sbox.normal.png000066400000000000000000000003501276457661000235310ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ =L‚åtEXtCommentCreated with The GIMPïd%nPIDAT(Ï¥Ñ1„P Ñ ·þ¹4bB¦¤".˜úÉC£Š×ªêJ¸èJ88ø;° ˆ@ØÚ… SÂú,ü˜È„»ûÞ30 ùIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/scroller.slide.bar.hover.tga000066400000000000000000000005261276457661000260740ustar00rootroot00000000000000 $ÿÿÿ•••ÿ•••ÿ•••ÿ•••ÿ•••ÿ•••ÿ•••ÿÿÿÿ•••ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ•••ÿ•••ÿ¾¾¾ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ¾¾¾ÿ•••ÿ•••ÿ¾¾¾ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ¾¾¾ÿ•••ÿ•••ÿ¾¾¾ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ¾¾¾ÿ•••ÿ•••ÿ¾¾¾ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ¾¾¾ÿ•••ÿ•••ÿ¾¾¾ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ¾¾¾ÿ•••ÿ•••ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ•••ÿÿÿÿ•••ÿ•••ÿ•••ÿ•••ÿ•••ÿ•••ÿ•••ÿÿÿÿpybox2d-2.3.2/examples/data/themes/default/scroller.slide.bar.normal.tga000066400000000000000000000005261276457661000262410ustar00rootroot00000000000000 $ÿÿÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿÿÿÿ€€€ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ€€€ÿÿÿÿÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿÿÿÿÿpybox2d-2.3.2/examples/data/themes/default/scroller.slide.h.tga000066400000000000000000000023761276457661000244420ustar00rootroot00000000000000 $ÿÿÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿÿÿÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿºººÿºººÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿÀÀÀÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿÀÀÀÿËËËÿËËËÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿËËËÿÿÿÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿÿÿÿpybox2d-2.3.2/examples/data/themes/default/scroller.slide.v.tga000066400000000000000000000023761276457661000244600ustar00rootroot00000000000000 $ÿÿÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿÿÿÿØØØÿËËËÿ»»»ÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿÀÀÀÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿÀÀÀÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿÀÀÀÿÒÒÒÿãããÿØØØÿËËËÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿÀÀÀÿÒÒÒÿãããÿÿÿÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿÿÿÿpybox2d-2.3.2/examples/data/themes/default/select.arrow.down.tga000066400000000000000000000005301276457661000246340ustar00rootroot00000000000000  (–ÿ€–ÿÿÿÿ€ÿôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿ€ÿ–êߪÿ€ÿßÎÿßÎÿ„ßÎÿ€ÿ–Õ¾Uÿ€ÿÊ®*ÿË®+ÿÊ®*ÿË®+ÿ‚Ê®*ÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿʬ ÿË­ÿʬ ÿË­ÿʬ ÿ€ÿ–Õ»Aÿ€ÿ’ßÈ_ÿßÉaÿßÈ_ÿ€ÿ–ê×€ÿ€ÿ–ôå ÿ€ÿ–ÿôÁÿ€ÿ–ÿ€pybox2d-2.3.2/examples/data/themes/default/select.arrow.hover.tga000066400000000000000000000005531276457661000250150ustar00rootroot00000000000000  (–@@@ÿ€@@@–ÿÿÿÿ€@@@ÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ–ïæ¿ÿ€@@@ÿçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ–àÏ€ÿ€@@@ÿ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ–àÌpÿ€@@@ÿ’çÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ–ïá¡ÿ€@@@ÿ÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ–ÿ÷Ñÿ€@@@ÿ–@@@ÿ€@@@pybox2d-2.3.2/examples/data/themes/default/select.arrow.normal.tga000066400000000000000000000005531276457661000251620ustar00rootroot00000000000000  (–@@@ÿ€@@@–ÿÿÿÿ€@@@ÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ–ïæ¿ÿ€@@@ÿçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ–àÏ€ÿ€@@@ÿ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ–àÌpÿ€@@@ÿ’çÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ–ïá¡ÿ€@@@ÿ÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ–ÿ÷Ñÿ€@@@ÿ–@@@ÿ€@@@pybox2d-2.3.2/examples/data/themes/default/select.arrow.png000066400000000000000000000002341276457661000237000ustar00rootroot00000000000000‰PNG  IHDR}Œß¬ pHYs  šœtIMEÕ 6·`;IDATÓcd````dÀÞÃwþcÀ»È*Ï IžA7j7’änlv­‚J®bÀf2üg˜É€t rò,!¿H:©IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/select.option.hover.png000066400000000000000000000002761276457661000252060ustar00rootroot00000000000000‰PNG  IHDRoª¯bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ)ïvŸtEXtCommentCreated with The GIMPïd%n"IDAT8Ëc<òõ?5•À¨A£4jШA£‘AÊè)£ðNIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/select.option.normal.png000066400000000000000000000002541276457661000253470ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/select.options.png000066400000000000000000000002651276457661000242450ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ(%¹tEXtCommentCreated with The GIMPïd%n+IDAT8Ëc` `d``øÿÿ?¥¦022QËE£4jШA£ ƒ¨;…,;)k“IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/select.selected.down.tga000066400000000000000000000005021276457661000252710ustar00rootroot00000000000000  (–ÿÿ–ÿÿÿÿÿôïÖÿôîÔÿôïÖÿ‘ôîÔÿÿ–êߪÿÿ…ßÎÿßÎÿÿ–Õ¾Uÿÿ‚Ë®+ÿÊ®*ÿË®+ÿÊ®*ÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿʬ ÿË­ÿ“ʬ ÿÿ–Õ»AÿÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿÿ–ê×€ÿÿ–ôå ÿÿ–ÿôÁÿ–ÿpybox2d-2.3.2/examples/data/themes/default/select.selected.hover.tga000066400000000000000000000005221276457661000254470ustar00rootroot00000000000000  (@@@–@@@ÿ@@@ÿ–ÿÿÿÿ@@@ÿ÷óáÿ÷óßÿ÷óáÿ‘÷óßÿ@@@ÿ–ïæ¿ÿ@@@ÿ…çÛ¡ÿçÚŸÿ@@@ÿ–àÏ€ÿ@@@ÿ‚×Âaÿ×Â_ÿ×Âaÿ×Â_ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ×ÁYÿ×ÀWÿ“×ÁYÿ@@@ÿ–àÌpÿ@@@ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿ@@@ÿ–ïá¡ÿ@@@ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿ’÷ë·ÿ@@@ÿ–ÿ÷Ñÿ@@@–@@@ÿpybox2d-2.3.2/examples/data/themes/default/select.selected.normal.tga000066400000000000000000000004321276457661000256140ustar00rootroot00000000000000  (–ÿÿ–ÿÿÿÿÿ–úúúÿÿ–ðððÿÿ–ãããÿÿ–ÒÒÒÿÿ‚ÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ»»»ÿºººÿ“»»»ÿÿ–ËËËÿÿ–ØØØÿÿ–åååÿÿ–ïïïÿÿ–÷÷÷ÿ–ÿpybox2d-2.3.2/examples/data/themes/default/slider.bar.hover.tga000066400000000000000000000014101276457661000244230ustar00rootroot00000000000000  („@@@@@@ÿ„@@@‚@@@@@@ÿVUTÿ¹¶§ÿîëÞÿ‰ýüùÿîëÞÿ¹¶§ÿVUTÿ@@@ÿ‚@@@@@@@@@ÿ‹ÿóïÛÿ÷óßÿˆ÷óáÿ÷óßÿ÷óáÿ÷óßÿóïÛÿ‹ÿ@@@ÿ@@@@@@@@@ÿ‚rÿ‘ïæ¿ÿ‚rÿ@@@ÿ€@@@@@@KKKÿáÕÿ‚çÚŸÿŒçÛ¡ÿçÚŸÿçÛ¡ÿáÕÿKKKÿ€@@@@@@ÿ„~bÿ“àÏ€ÿ„~bÿ€@@@ÿ@@@ÿ¬Zÿ“×Âaÿ­Ÿ[ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿªšPÿ×ÁYÿ×ÀWÿŒ×ÁYÿ×ÀWÿ‚×ÁYÿªšPÿ€@@@ÿ@@@ÿvoNÿ“àÌpÿvoNÿ€@@@ÿ@@@BB@ÿàЄÿçÖ‡ÿ‚çÖ‰ÿˆçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿàЄÿCBAÿ€@@@@@@@@@ÿgcOÿ‘ïá¡ÿgcOÿ@@@ÿ€@@@@@@@@@ÿlgRÿòæ°ÿŠ÷ì¹ÿ÷ë·ÿ÷ì¹ÿòæ°ÿlgRÿ@@@ÿ@@@‚@@@@@@ÿDCBÿ“ŒiÿàÕ ÿ‰ûòÇÿàÕ ÿ“ŒiÿDCBÿ@@@ÿ‚@@@„@@@@@@ÿ„@@@pybox2d-2.3.2/examples/data/themes/default/slider.bar.normal.tga000066400000000000000000000013311276457661000245720ustar00rootroot00000000000000  („ÿ„‚ÿ”””ÿÝÝÝÿùùùÿ‰ÿÿÿÿùùùÿÝÝÝÿ”””ÿÿ‚ÿ¿¿¿ÿøøøÿúúúÿøøøÿ¿¿¿ÿÿÿ´´´ÿ‘ðððÿ´´´ÿÿ€ŠŠŠÿáááÿ‘ãããÿáááÿŠŠŠÿ€ÿªªªÿ“ÒÒÒÿªªªÿ€ÿÿ°°°ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ±±±ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿªªªÿ»»»ÿºººÿŒ»»»ÿºººÿ‚»»»ÿªªªÿ€ÿÿ™™™ÿ“ËËËÿ™™™ÿ€ÿ€€€ÿÔÔÔÿ‘ØØØÿÔÔÔÿ€€€ÿ€ÿ•••ÿ‘åååÿ•••ÿÿ€ÿ™™™ÿëëëÿïïïÿëëëÿ™™™ÿÿ‚ÿÿ³³³ÿâââÿ‰ôôôÿâââÿ³³³ÿÿÿ‚„ÿ„pybox2d-2.3.2/examples/data/themes/default/slider.tga000066400000000000000000000023171276457661000225450ustar00rootroot00000000000000  (‚€€€ÿÿÿ£££ÿªªªÿˆ®®®ÿ°°°ÿ®®®ÿªªªÿ‚ÿÿÿ€€€€€€ÿÿÿ£££ÿ®®®ÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿ¼¼¼ÿ®®®ÿÿÿÿ€€€€€€€ÿÿÿ£££ÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿµµµÿÿÿÿÿÿÿ£££ÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿµµµÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿ£££ÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€¼¼¼ÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ°°°ÿÎÎÎÿéééÿùùùÿýýýÿŠþþþÿÿÿÿÿ‚þþþÿýýýÿùùùÿéééÿ€ÎÎÎÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿÿÿÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿÿÿÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿÿÿÿ€€€ÿÿÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿ‚ÿÿÿ€€€‚ÿÿÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿƒÿÿÿ€€€€pybox2d-2.3.2/examples/data/themes/default/tool.down.tga000066400000000000000000000010201276457661000231740ustar00rootroot00000000000000  (•ÿ€ÿ•ÿÿÿÿ€ÿÿôïÖÿôîÔÿôïÖÿ‰ôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿ€ÿÿ•êߪÿ€ÿÿ…ßÎÿˆßÎÿßÎÿ„ßÎÿ€ÿÿ•Õ¾Uÿ€ÿÿ‚Ë®+ÿÊ®*ÿË®+ÿˆÊ®*ÿË®+ÿÊ®*ÿË®+ÿ‚Ê®*ÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿʬ ÿË­ÿ‹Ê¬ ÿË­ÿʬ ÿË­ÿʬ ÿ€ÿÿ•Õ»Aÿ€ÿÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿ‹ßÈ_ÿßÉaÿßÈ_ÿ€ÿÿ•ê×€ÿ€ÿÿ•ôå ÿ€ÿÿ•ÿôÁÿ€ÿ•ÿ€pybox2d-2.3.2/examples/data/themes/default/tool.hover.tga000066400000000000000000000010631276457661000233570ustar00rootroot00000000000000  (@@@•@@@ÿ€@@@@@@ÿ•ÿÿÿÿ€@@@ÿ@@@ÿ÷óáÿ÷óßÿ÷óáÿ‰÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ@@@ÿ•ïæ¿ÿ€@@@ÿ@@@ÿ…çÛ¡ÿˆçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ@@@ÿ•àÏ€ÿ€@@@ÿ@@@ÿ‚×Âaÿ×Â_ÿ×Âaÿˆ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ×ÁYÿ×ÀWÿ‹×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ@@@ÿ•àÌpÿ€@@@ÿ@@@ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿ‹çÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ@@@ÿ•ïá¡ÿ€@@@ÿ@@@ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿŠ÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ@@@ÿ•ÿ÷Ñÿ€@@@ÿ@@@•@@@ÿ€@@@pybox2d-2.3.2/examples/data/themes/default/tool.normal.tga000066400000000000000000000006711276457661000235300ustar00rootroot00000000000000  (•ÿ€ÿ•ÿÿÿÿ€ÿÿ•úúúÿ€ÿÿ•ðððÿ€ÿÿ•ãããÿ€ÿÿ•ÒÒÒÿ€ÿÿ‚ÀÀÀÿ¿¿¿ÿÀÀÀÿˆ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ‚¿¿¿ÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ»»»ÿºººÿ‹»»»ÿºººÿ»»»ÿºººÿ»»»ÿ€ÿÿ•ËËËÿ€ÿÿ•ØØØÿ€ÿÿ•åååÿ€ÿÿ•ïïïÿ€ÿÿ•÷÷÷ÿ€ÿ•ÿ€pybox2d-2.3.2/examples/data/themes/default/up.png000066400000000000000000000003031276457661000217110ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ ”šœ–tEXtCommentCreated with The GIMPïd%n+IDAT(Ïc` 7øÏð¿4F0b5‚»‚ÿØ42ât#ªlîcd6¢r \¬IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/vbox.normal.png000066400000000000000000000003511276457661000235350ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ - ;tEXtCommentCreated with The GIMPïd%nQIDAT(Ï¥‘1 À0 ÏÚB ýÿCéPèÒAù€ƒk>¤3@¬ÄÏÇËÃÍ.:ÆÉÎÁ†Ih „kP‚% rõ Û@Á¡~E¦îÝÐ#}ŸIEND®B`‚pybox2d-2.3.2/examples/data/themes/default/vdot.down.png000066400000000000000000000010341276457661000232110ustar00rootroot00000000000000‰PNG  IHDRóÿabKGD€€€D(“M pHYs  šœtIMEÖ gÍtEXtCommentCreated with The GIMPïd%n€IDAT8Ë“;,CqÆ÷¦Õ"QƒW‚ ^ ‰ÆÈ "6‚M„0xÅ ¯ÒÄæ1"F›4ÒvÕ. $ .-Õöþ ­Û‡^gúç$ç;ß÷ÿÎ'‘¸„F_ú«!2L™54ã­6s“S @öý%A—ƒ7§ ÆÌEˆÆö.Ìc3\½+\¸½œ»=g¤QbJ'OöÑn^ÎŽÕYù{¸­w€þ¥eR ư†Ÿ*RRÓÚµ’W[¯Ê”ò ™X´  ]r˜ïôÞ²NÇ7€ž[À ×MIŠR'¤Ð[ “J7¨í2@sS“Šžlµt÷EVäf©è ½"F@Mey ã¤$Z"\==ÿÊ Ñ’ÓËëÀ¡ÍÙ’äXw6Uiev ŸßwËÚ”<>N¶×$àáþËäDÜkÛ8ßÑŠÄÚ¾¿µÎÆø߇¦ Ÿï^V;[x\ýƒ4™ÙÙ$~Uy#/ö ..aÚlTB­Žñ•-ݽzM ©¹…©ù¤ª¨×·M¯n`Ô˜šS³s˜æ7!J…ySù}¶ÛjqŒ(Àçõj÷j øF‚…©ÚõÚ½ì躀»£ÝÊU3,2ÔºØkü× Ê]½¸‹H¤$°¿piq|°O6›­:ÄTæ“hø@/ÏOííþšúÏ ×—‘¹¬å+‹ó³J¼'ñLÎT|…\&ÍÉöñÛ¨îƒ(j£.ÓGg7Î6K™Þ®/AJK™Äëü}Yz2c<~IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/vdot.normal.png000066400000000000000000000005421276457661000235350ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGD€G5  pHYs  šœtIMEÖ 9BÕÑ—tEXtCommentCreated with The GIMPïd%nÊIDAT(Ï}ѱJQ„áïÞHD¬lÄ">@ ÁÂÖN|!ßHìlMe!¦LDH°ˆ Ä‹ÍnXÙuªážŸÃ3éV¥ØX©4[åpW϶OtÌM"ÖPÄ™¾3_ØslÇÀ4$2âÒEal_;$È8פY\ɵŸEµå”ÈiÓ 2Ý?ÏUBûð¿2ß­ÃYŒ[WdéÁªáÖ,½2ïžcÞY­Oc¡_K±toJ*»HÏ1ÔÓõƒ¹‘‰zY¤…·Æºõ3m9}IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/vsbox.normal.png000066400000000000000000000003401276457661000237160ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ  û’tEXtCommentCreated with The GIMPïd%nHIDAT(ϵ‘A €0gEëþº¹øå¢HY_ ‹•æ<$0±¨¯‘¬†èÜ\œ4à8;…•ƒ…$ßË€øÝÀü‰˜ïaHµew?¬ž™Dl%¼IEND®B`‚pybox2d-2.3.2/examples/data/themes/default/vslider.bar.hover.tga000066400000000000000000000026041276457661000246170ustar00rootroot00000000000000  („@@@@@@ÿ„@@@‚@@@@@@ÿKKKÿ„~bÿ­Ÿ[ÿ‰Æ®@ÿªšPÿvoNÿCBAÿ@@@ÿ‚@@@@@@@@@ÿ‚rÿáÕÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿàЄÿgcOÿ@@@ÿ@@@@@@@@@ÿ‹ÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‡ÿïá¡ÿlgRÿ@@@ÿ€@@@@@@VUTÿóïÛÿïæ¿ÿçÚŸÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿòæ°ÿDCBÿ€@@@@@@ÿ¹¶§ÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÀWÿàÌpÿçÖ‡ÿïá¡ÿ÷ì¹ÿ“Œiÿ€@@@ÿ@@@ÿîëÞÿ÷óáÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÀWÿàÌpÿçÖ‡ÿïá¡ÿ÷ë·ÿàÕ ÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óáÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‡ÿïá¡ÿ÷ì¹ÿûòÇÿ€@@@ÿ@@@ÿîëÞÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ì¹ÿàÕ ÿ€@@@ÿ@@@ÿ¹¶§ÿ÷óßÿïæ¿ÿçÚŸÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ì¹ÿ“Œiÿ€@@@ÿ@@@VUTÿóïÛÿïæ¿ÿçÚŸÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿòæ°ÿDCBÿ€@@@@@@@@@ÿ‹ÿïæ¿ÿçÚŸÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÀWÿàÌpÿçÖ‡ÿïá¡ÿlgRÿ@@@ÿ€@@@@@@@@@ÿ‚rÿáÕÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿàЄÿgcOÿ@@@ÿ@@@‚@@@@@@ÿKKKÿ„~bÿ¬Zÿ‰Æ®@ÿªšPÿvoNÿBB@ÿ@@@ÿ‚@@@„@@@@@@ÿ„@@@pybox2d-2.3.2/examples/data/themes/default/vslider.bar.normal.tga000066400000000000000000000026041276457661000247640ustar00rootroot00000000000000  („ÿ„‚ÿŠŠŠÿªªªÿ±±±ÿ‰§§§ÿªªªÿ™™™ÿ€€€ÿÿ‚ÿ´´´ÿáááÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿÔÔÔÿ•••ÿÿÿ¿¿¿ÿðððÿãããÿÒÒÒÿ¿¿¿ÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿ™™™ÿÿ€”””ÿøøøÿðððÿãããÿÒÒÒÿ¿¿¿ÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿëëëÿÿ€ÿÝÝÝÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿºººÿËËËÿØØØÿåååÿïïïÿ³³³ÿ€ÿÿùùùÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿºººÿËËËÿØØØÿåååÿïïïÿâââÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿùùùÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿâââÿ€ÿÿÝÝÝÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿ³³³ÿ€ÿ”””ÿøøøÿðððÿãããÿÒÒÒÿ¿¿¿ÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿëëëÿÿ€ÿ¿¿¿ÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿºººÿËËËÿØØØÿåååÿ™™™ÿÿ€ÿ´´´ÿáááÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿÔÔÔÿ•••ÿÿ‚ÿŠŠŠÿªªªÿ°°°ÿ‰§§§ÿªªªÿ™™™ÿ€€€ÿÿ‚„ÿ„pybox2d-2.3.2/examples/data/themes/default/vslider.down.tga000066400000000000000000000015401276457661000236760ustar00rootroot00000000000000  (þþþ~~~ÿ€þþþ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿ‰ÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿ‡ÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿ…ÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿƒÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿþþþ~~~ÿ€þþþpybox2d-2.3.2/examples/data/themes/default/vslider.tga000066400000000000000000000023171276457661000227330ustar00rootroot00000000000000  (‚€€€ÿÿÿ£££ÿªªªÿˆ®®®ÿ°°°ÿ®®®ÿªªªÿ‚ÿÿÿ€€€€€€ÿÿÿ£££ÿ®®®ÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿ¼¼¼ÿ®®®ÿÿÿÿ€€€€€€€ÿÿÿ£££ÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿµµµÿÿÿÿÿÿÿ£££ÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿµµµÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿ£££ÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€¼¼¼ÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ°°°ÿÎÎÎÿéééÿùùùÿýýýÿŠþþþÿÿÿÿÿ‚þþþÿýýýÿùùùÿéééÿ€ÎÎÎÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿÿÿÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿÿÿÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿÿÿÿ€€€ÿÿÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿ‚ÿÿÿ€€€‚ÿÿÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿƒÿÿÿ€€€€pybox2d-2.3.2/examples/data/themes/default/vslider.up.tga000066400000000000000000000015401276457661000233530ustar00rootroot00000000000000  (þþþ~~~ÿ€þþþ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿƒÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿ…ÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿ‡ÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿ‰ÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿþþþ~~~ÿ€þþþpybox2d-2.3.2/examples/data/themes/default/x.png000066400000000000000000000003071276457661000215400ustar00rootroot00000000000000‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÕ"í{ftEXtCommentCreated with The GIMPïd%n/IDAT(Ïc`\à?#š # EŠ>„8#VKD™9Œ+p8’ 7}ú ß°ñIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/000077500000000000000000000000001276457661000201015ustar00rootroot00000000000000pybox2d-2.3.2/examples/data/themes/gray/Vera.ttf000066400000000000000000002006141276457661000215200ustar00rootroot00000000000000OS/2´_ôcëpVPCLTÑŠ^—ëÈ6cmap¤Ãè ±lXcvt ÿÓ9üüfpgmç´ñÄ&`‹gaspH glyf tAÏ&ìŠ~hdmx4ð!ìHheadÝ„¢ÐT6hheaEoëL$hmtx ÆŽ²´Ä0kernÜRÕ™½ -ŠlocaóËÒ=»„maxpG:ë, nameټȵßpost´Z/»¸ôŽprep;ñ øh::_:: dM0­l  ƒ p t › &   Y &  &   c . 5 ` õ s 0¡ & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5¸ËËÁªœ¦¸fqË ²…u¸Ãˉ-˦ðÓª‡ËªJ3ËÙôT´œ99N´R¸çÍ7sÍ`s3¢V¦V9Åɸßsºé3¼Dßͪåªˤ{¸o{RÇÍššoËÍžÓðºƒÕ˜HžÕÁËöƒT3fÓǤ͚sÕ þ+¤´œbœ-ÕÕÕð{T¤¸#Ӹ˦Ãì“ Ó\qÛ…#¨H99`Õš#fy```{œw`ªé`b{Å{´RÍf¼fwÍ;…‰{ÍJ/œœ}oo5jo{®²-–{öƒT7öœáföÍD)fîs¸€@ÿûþúù%ø2÷–öõþôþó%òñ–ð%ïŠAïþî–í–ìúëúêþé:èBçþæ2åäSå–äŠAäSãâ/ãúâ/áþàþß2ÞÝ–ÜþÛÚ}Ù»ØþÖŠAÖ}ÕÔGÕ}ÔGÓÒÓþÒÑþÐþÏþÎþÍ–ÌËÌþËÊ2ÉþÆ…ÆÅÄþÃþÂþÁþÀþ¿þ¾þ½þ¼þ»þº¹†%¹þ¸·»¸þ·¶]·»·€¶µ%¶]@ÿ¶@µ%´þ³–²þ±þ°þ¯þ®d­¬«%¬d«ª«%ª©ŠA©ú¨þ§þ¦þ¥¤þ£¢£2¢¡d ŠA –Ÿþž žþ œ›œd›š›š™ ˜þ—– —þ– •ŠA•–”“”(“’ú‘»‘þ]»€Ž%]@Ž%þŒ‹.Œþ‹.І%ŠA‰ˆ ‰ˆ ‡†%‡d†…†%…„þƒ‚ƒþ‚þ€þþ@ÿ~}}~þ}}|d{T{%zþyþxw v uþtúsúrúqúpþoþnþl!kþjBjSiþh}gBfþeþdþcþbþa:`ú^ ]þ[þZþYX YúX WW2VþUTUBTSSRQJQþP OþNMNþMLþKJKþJIJI IH GþF–E–DþC-CúB»AK@þ?þ>=>=<=<; <@ÿ; :þ9þ878ú76765 65 43 21 2þ1 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $þ#þ"!! dú d BþúBBþdþþþþBþ-B}dþ  þ   þ  þ-þdþ@-þ-þ¸d…++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++¶, °%Id°@QX ÈY!-,°%Id°@QX ÈY!-,  °P° y ¸ÿÿPXY°°%°%#á °P° y ¸ÿÿPXY°°%á-,KPX °ýEDY!-,°%E`D-,KSX°%°%EDY!!-,ED-fþ–f¤@ ûû/ÄÔì1ÔìÔì0!%!!füsüåþ–øòr)5Õ @@ƒ ü<ì2991/äüÌ0K° TX½ @ ÿÀ878Y¶ P ]%3#3#5ËËË¢þþÕýqþ›eŪéÕM@„üüÜì1ô<ì20K°TK°T[X½@ÿÀ878Y@0 @ P ` p   ¿ ]#!#oª$ªÕýÕ+ýÕ+ž¾`@1 ‡  ‡   üÌ91/<Ô<<ü<<Ô<<Ä2ì220@   ]!! !3!!!!#!#!5!!5!þÝT%Dh$i g8þ¡R>þ›h gþÛg¡hþÅ`Tþ¾if…þ²‡þaŸþašþ²™þbžþbž™NšŸªþÓm!(/Õ@U" '&( /)/))/B" ) *!††#Љ*Љ- ) " & 0ü<ìô<ü<ôäì1/äìÄÔäì2Äîî99990KSXíí9í9íY"K° TX½0@00ÿÀ878YK° TK°T[K°T[X½0ÿÀ00@878Y#.'5.546753.'>54&´diÒjfÑoÝÉÚÌd]®SS¯\ãÖãÖdtzqá{þÓ---´@AÈ$¬–£¼ëè¯*.þU#´œ©Ãš jXV`ÕþOnZXhqÿã)ð #'3•@6$%&%&'$'B’ ’.’$’ &Œ($‘4'!%   ! + 1 4üÄìôìîöî991ä2ô<äìîöîî0KSXííY"K° TK° T[K° T[K°T[K°T[K° T[X½4@44ÿÀ878Y"32654&'2#"&546"32654&%3#2#"&546ÑWccWUccUžº» º»ü—VcbWWcd1 üZ ž¼»ŸŸ¹º‘”„‚••‚ƒ•Ü»»ÛÛ»¼Ûa•‚„””„–ùó Û»½ÚÛ¼ºÜÿãþð 0Í@–  † †  † †††  !         B  (('•+•'”$‘Œ .  .'.'!!1üìÄÔÔìÆî99999991/ÆäöæîîÆ9990KSXíí9í9í9í9í9íí9í9ííí9Y"²2]@² " ) **&:4D ^YZ UZZY0g{›š™—• “••"™-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z““—•œœŸš › š 2 2°29]]3267 >73#'#"5467.54632.#"ò[UÔ _¦Iþ{ü;Bº h]ühäƒñþΆ†02Þ¸S¥UWžDiƒ;#Q¡X’Â?@ýøYËr„þþ~þã“YW×€ác?}<¢Å$$¶/1oX3gŪoÕB@ „üì1ôì0K°TK°T[X½@ÿÀ878Y@ @P`p ]#oªÕýÕ+°þò{ O@˜—  Üä2ì991üì0K°TX½@ÿÀ878YK°TX½ÿÀ@878Y#&547{†‚ƒ… –•”—æþ>ççþ;åëÆàßÄì¤þòo @˜— Ü<ôì991üì03#654¤ –••– …ƒƒìþ<ßàþ:ëåÅççÂ=JÃðN@,  ™ ™ ‘    Ô<ä2Ü<ä2991ôÔ<ì2Äì2990%#'%%73%Ãþ™g:þ°rþ°:gþ™:PrPßÂÃbËþ‡yËbÃÂcËyþ‡ËÙÛ #@ œ  Üü<ü<ì1/Ô<ü<Ä0!!#!5!®-ýÓ¨ýÓ-ýÓªýÓ-ª-žÿÃþ@ žƒüìÔÌ1üì073#ðÓ¤Rþ¬þÀ@d߃¶œÜÌ1Ôì0!!dý僤ۮþ·ƒüì1/ì073#ÛÓÓþþÿB²Õ-@BŸ/Ä991ôì0KSXííY"3#ªýøªÕùm‡ÿãð #@   ‘Œ üìôì1äôìî0"32'2#"‹œœû þ÷ûûþ÷ PþÍþÌþÍþÍ3343 þsþ†þ‡þsyzáZÕ K@B     ÔìÄüì1/ì2ôìÔì0KSXY"K°TX½ ÿÀ @878Y´]7!5%3!!þJþ™eÊJü¤ªsH¸HúÕª–Jð¥@'B¡”  ‘   üÄÔìÀÀ91/ì2ôìôì0KSXíí9Y"K°TK°T[K°T[X½@ÿÀ878Y@2UVVzzv‡tvust‚†‚‚‚¨¨]]%!!567>54&#"5>32‰ÁüLs3aM§†_ÓxzÔXèE[þôªªªw‘:m—Iw–BCÌ12èÂ\¥pþëœÿãsð({@. † †     “  “#‘Œ£)&  )üÄÄÔìôì991ìäôäìæîîîî90K°TK°T[X½)@))ÿÀ878Y@ daa d!]!"&'532654&+532654&#"5>32?‘£þÐþè^ÇjTÈm¾Ç¹¥®¶•ž£˜S¾rsÉYæ Ž%ÄÝò%%Ã12–„•¦wps{$&´ Ѳ|«d¤Õ Œ@   B     ÜÔ<Äì291/äÔ<ì290KSXÉÉY"K° TK° T[X½@ÿÀ878Y@* *HYiwŠ+&+6NO O Vfuz… ]] !33##!5þþ5þÕÕÉý^%üãÍü3¨þ `ÞÿãdÕu@#†  ‰   Œ¤  üÄÔìÄî1ääôìæîþÄî90K°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y!!>32!"&'532654&#"Ýý ,X,ú$þÔþï^ÃhZÀk­ÊÊ­Q¡TÕªþ’þîêñþõ Ë10¶œœ¶$&ÿã–ð $X@$ †   ¥  ‰"‘Œ% " !%üììôìä1äôäüäîîî90@ËËÍÍÍËˤ²]]"32654&.#">32# !2¤ˆŸŸˆˆŸŸ L›LÈÓ;²káþðâþýþîPL›;º¢¡»»¡¢ºy¸$&þòþïW]þïëæþêyb¥¨hÕc@B üÌÄ991/ôì0KSXííY"K°TX½@ÿÀ878Y@X9Hg°°]]!#!¨ÀýâÓþý3ÕVú+‹ÿã‹ð #/C@%  ' - ‘Œ'£0 $*$ !0üÄìôÄìîî991ìäôìîî990"32654&%&&54632#"$54632654&#"‹¥¥¦¥þ¥‚‘ÿÞßþ‘’£þ÷÷÷þ÷¤H‘ƒ‚““‚ƒ‘Åš‡‡š›†‡šV ²€³Ðг€² "ÆÙèèÙÆat‚‚tt‚‚ÿã‡ð$X@#†  ¥ ‰ ‘Œ%!"" %üìäôìì1äôìæþõîî90@ÄÂÀÀÀÂμé]]7532#"543 !"&2654&#"áLœKÈÓ:²làþûâþ±þåLœ>ˆŸŸˆˆŸŸ¸$& V\ëæþsþ†þŸþ[—º¢¡»»¡¢ºðÃ#@ƒ¦ƒü<ì21/ìôì073#3#ðÓÓÓÓþþ#þžÿÃ# %@ƒžƒ¦  ü<ì2ÔÌ1äüìî03#3#ðÓÓÓ¤R#þýÙ¬þÀ@Ù^Û¦M@*œœœœB¨§$#üì291ôì90KSXííííY" 5Ûûøúþðþ‘þ“¶ѦÑÙ`Û¢@ œœ#ü<Ä21ÔìÔì0!!!!Ùúþúþ¢¨ðªÙ^Û¦O@+œœœœB¨§$#ü<ì91ôì90KSXííííY"55Ùúþð¶þ/¦þ/¶m“°ð$p@+$  †ˆ•‘ƒ   &%ÜÄüìÔìî99991/îöþôîÍ9990K° TX½%@%%ÿÀ878Y¶y z z ]%3##546?>54&#"5>32‡ËËÅ¿8ZZ93ƒlO³a^Ág¸ßHZX/'þþ‘še‚VY5^1YnFC¼98ŸL‰VV/5<4‡þœq¢ L•@2  ©©L43¬0©7¬$©7CM34( (+(I+*(I,=MÜìüìþýþ<Æî991ÔÄüìþíÔÆÅî2Äî990K° TK° T[K°T[K°T[K°T[X½MÿÀMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32úŽ|{zy!<›g¬×Ø«gœ;’¥?@hþÕ°{â`±smiùhZ}þÙ˜¹þ¸€€†ˆ~R½Ôk{KOþÂþè£¤ŽŒ¥¤þHMIùÈÈúKLƒý ß±k¼Pƒ‹A@fþµÁŸþêjhmWQoagƒ}}I½¶J}‡® bæ{þùþÐhÕ º@A       B•    ÔÄ91/<äÔì90KSXííííííííY"² ]@:XvpŒ VXP ghxv|rwx‡ˆ€ ˜™–]] !3#!#¼þî%þ{å9Òˆý_ˆÕý®ú+þÉìÕ C@#• •• ­ . !üì2üìÔì9991/ììôìî90²"]!2654&#!2654&#%!2#!“D££þ¼+”‘‘”þ çú€|•¥þðûýèÉý݇‹Œ…fþ>orqp¦À±‰¢ ˘ÈÚsÿã'ð6@ ¡® •¡®•‘Œ 0üì2ì1äôìôìîöî0´].# !267# !2'fç‚ÿþð‚çfjí„þ­þz†S†íbÕ_^þÇþØþÙþÇ^_ÓHHŸghŸGɰÕ.@• •  2 üìôì99991/ìôì0²`]3 !%! )“ô5þáþËþBŸ²–þhþPþa/ûw.,¦þ—þ€þ~þ–É‹Õ .@•••­   üì2ÔÄÄ1/ììôìî0² ]!!!!!!ɰýÇý9øü>ÕªþFªýãªÉ#Õ )@••­ üì2ÔÄ1/ìôìî0² ]!!!!#ÉZýpPý°ÊÕªþHªý7sÿã‹ð9@ ••¡®•‘Œ43 üìüäüÄ1äôìôìþÔî990%!5!# !2&&# !26Ãþ¶uþæ þ¢þu‹^’opü‹þîþík¨Õ‘¦ýSU™mn™HF×_`þÎþÑþÒþÎ%É;Õ ,@•­ 8  üì2üì21/<ä2üì0²P ]3!3#!#ÉÊÞÊÊý"ÊÕýœdú+Çý9É“Õ9·¯üì1/ì0K°TX½ÿÀ@878Y@ 0@P`Ÿ]3#ÉÊÊÕú+ÿ–þf“Õ M@ •° 9 üìä991äüì990K°TX½ ÿÀ @878Y@ 0 @ P ` Ÿ ]3+53265ÉÊÍãM?†nÕú“þòôª–ÂÉjÕ ï@(B¯  üì2ÔÄ91/<ì290KSXííííY"²]@’ ((764GFCUgvwƒˆ”›ç    (+*66650 A@E@@@ b`hgwp ‹‹Ž š¶µÅÅ×Öèéèê÷øù,]q]q3! !#ÉÊžýþöý3ÊÕý‰wýHüãÏý1ÉjÕ%@ •:üìì1/äì0@ 0P€€]3!!ÉÊ×ü_ÕúÕªÉÕ ¿@4  B ¯   >  üìüì91/<Äì290KSXííííY"²p]@V   && & 45 i|{y €‚‚  #,'( 4<VY ej vy •›]]! !###É-}-ÅþËþÄÕüøú+üúáÉ3Õ y@B¯6 üìüì991/<ì2990KSXííY"² ]@068HGif€ FIWXeiy…Š•šŸ ]]!3!#É–ÄþðýjÄÕûáú+áûsÿãÙð #@•• ‘Œ 3üìüì1äôìî0"32' ! 'ÜþýÜÜþÿÜ:xþˆþÆþÅþ‡yLþ¸þåþæþ¸HH¤þ[þžþŸþ[¤bb¥ÉÕ:@••   ? üì2üì91/ôìÔì0@ ?_¯]32654&#%!2+#“þššþ8ÈûþÿûþÊ/ýÏ’‡†’¦ãÛÝâý¨sþøÙð R@*  B ••‘Œ    3üìüì9991Ääôìî990KSXíí9Y""32#'# ! 'ÜþýÜÜþÿ? ôÝ!#þÅþ‡y;:xÑLþ¸þåþæþ¸HHúÏþÝï¥ab¥þ[þžþüþŽÉTÕ±@5  B• •   ?  üì2üÄì99991/<ôìÔì9990KSXíí9Y"²@]@Bz%%%&'&&& 66FFhuuwˆˆ˜˜]]#.+#! 32654&#A{>ÍÙ¿J‹xÜÊÈüƒý‰þ’••’¼~þh–bý‰ÕÖØºOýƒ…‡ÿã¢ð'~@<    B ¡”••”%‘Œ( "-"(ÜÄìüìä99991äôäìîöîÆ90KSXí9í9Y"²)]¶)/)O)].#"!"&'532654&/.54$32HsÌ_¥³w¦zâ×þÝþçjï€{ìr­¼‡š{âÊõiÚ¤Å76€vce+Ù¶Ùà0/ÐEFˆ~n|-À«Æä&ÿúéÕJ@•@@Ôäüä1/ôì20K° TX½@ÿÀ878Y@  @ p Ÿ ]!!#!ïýîËýîÕªúÕ+²ÿã)ÕK@ •Œ  8Aüìüì1ä2ôì99990K°TX½@ÿÀ878Y¶Ÿ]332653! ²Ë®Ã®ËþßþæþåþßÕüuðÓÓð‹ü\þÜþÖ*$hÕ·@'B¯ÔÄ91/ì290KSXííííY"²P]@b*GGZ}ƒ *&&))% 833<<7HEEIIGYVfiizvvyyu€˜—)]]!3 3JýÆÓÙÚÒýÇÕûéú+D¦Õ {@I      B ¯    ÔÌ91/<ì2290KSXííííííííY"²]@ò  ($ >>4 0 LMB @ Yjkg ` {|€ –•     !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx  †‡ˆ‰… Š —Ÿ¯[]]3 3 3# #DÌ:9ã:9Íþ‰þþÅþÂþÕûîûîú+úð=;Õ ]@F      B ¯   ÔÄÜÄ91/<ì290KSXííííííííY"K° TK° T[K°T[X½ ÿÀ @878Y@¸ '' 486 KX[fkww †€‡‹… ”—–     &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x €€ƒˆ…„ƒ ”——•“ Ÿ ¯ @]]3 3 # #ÙsuÙþ Ùþ\þYÚÕýÕ+ý3üø{ý…ÿüçÕ”@(B¯@@ Ôäüä91/ì290KSXííííY"² ]@<5000F@@@QQQe„“ &)78@ ghxp Ÿ ]]3 3#Ùž›ÙýðËÕýšfüòý9Ç\Õ ›@B••B ÜÄÔä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878Y@@ )&8HGH    / 59? GJO UYfio wx Ÿ ]]!!!5!s•üPÇû=°ügÕšûoªš‘°þòXS@©²©±CÜüÌ21üìôì0K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y!#3!°¨ððþXùüÿB²Õ-@BŸ/Ä991ôì0KSXííY"#ªªýøÕùm“Çþòo<@©²©±Cü<Üì1üìôì0K°TK°T[X½ÿÀ@878Y!53#5oþXïïøÞÙ¨ÛÕ@ ÜÌ91ôÌ290##¼ÉþHþHÉÕýÓ‹þu-ÿìþþ¬µ©ÄÄ1Ôì0!5ûØþ¬ªð‰f1@ ´³DÜì1ôì0K° TK°T[X½ÿÀ@878Y #o™þºfþŠv{ÿã-{ %¼@'  ©¹ †º¹#¸Œ   E&üìÌÔì22991/ÄäôüôìÆîî9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p'…‡‡‡ ‡!…"' 'ð'000 0!@@@ @!PPP P!``` `!ppp p!€€€ €!]]"326=7#5#"&5463!54&#"5>32¾ß¬o™¹¸¸?¼ˆ¬Ëýû§—`¶Te¾Zóð3f{bsÙ´)LýªfaÁ¢½À‹..ª''üºÿ㤠8@¹  ¹Œ¸—G Füì22ôì1/ìäôÄìÆî0¶`€ ]4&#"326>32#"&'#3å§’’§§’’§ýŽ:±{ÌÿÿÌ{±:¹¹/ËççËËççRdaþ¼þøþøþ¼ad¨qÿãç{?@†ˆ† ˆ ¹¹¸Œ HEüä2ì1äôìþôîõî0@ € ].#"3267#"!2çNP³ÆÆ³PNM¥]ýþÖ-U¢5¬++ãÍÍã++ª$$>:#qÿãZ8@¹¹Œ¸—G Eüìôì221/ìäôÄìÄî0¶`€ ]3#5#"3232654&#"¢¸¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶^ùì¨daDDaþËççËËççqÿã{p@$ †ˆ©¹ »¹¸ ŒKEüìôìÄ91äôìäîîôî90@)?p Ðð?????,// , ooooo ]q]!3267# 32.#"ü² Í·jÇbcÐkþôþÇ)ü⸥ˆš¹^Z¾Ç44®*,8 CþÝÄ—´®ž/øp@ ©‡—¼    Lü<Äü<ÄÄ991/ä2üìî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y¶@P ]#"!!##535463ø°cM/þѹ°°®½™Phcü/ÑN»«qþVZ{ (J@#  †¹¹&#¸'¼ ¹½& G E)üÄìôì221/ÄäìäôÄìþÕî990¶`*€* *]4&#"326!"&'5326=#"3253¢¥•”¥¥”•¥¸þþúa¬QQžRµ´9²|ÎüüÎ|²9¸=ÈÜÜÈÇÜÜëþâþé³,*½¿[cb::bcªºd4@ ‡¸ — N  Füì2ôì1/<ìôÄì90²`]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡ýžedïÁy+@¾±¼Fü<ì21/äüì0@  @ P ` p ]3#3#Á¸¸¸¸`û éÿÛþVy D@ ¾ ‡½¼ ±O  Fü<ì2ä991ìäôìî990@ @P`p]3+532653#Á¸£µF1iL¸¸`ûŒÖÀœa™(麜 ¼@)B¼— F üì2ÔÄ91/<ìä90KSXííííY"² ]@_ ')+Vfgsw‚‰Ž“–—£    ('(++@ h` ‰…‰š—ª§¶ÅÖ÷ð÷ð]q]33 ##º¹%ëý®kðýǹüiãýôý¬#ýÝÁy"·—Füì1/ì0@ @P`pð]3#Á¸¸ùìº{"Z@&  ‡ ¸¼PPF#üì2üüüì91/<<äô<Äì290@0$P$p$$ $ $¿$ß$ÿ$ ]>32#4&#"#4&#"#3>32)EÀ‚¯¾¹ru¦¹rw¦¹¹?°yz«‰|võâý\ž¡œ¾¤ý‡ž¢›¿£ý‡`®gb|ºd{6@ ‡¸ ¼ N  Füì2ôì1/<äôÄì90´`Ï]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡`®edïqÿãu{ J@¹¹ ¸Œ QEüìôì1äôìî0@#?{{   {  { ð]"32654&'2#"s”¬«•“¬¬“ðþîðñþïßçÉÉçèÈÇéœþÈþìþíþÇ98ºþV¤{>@¹¹¸Œ½¼ GFüì22ôì1äääôÄìÄî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý® ªdaþ¼þøþøþ¼aëËççËËççqþVZ{ >@¹  ¹¸Œ½¼ GEüìôì221äääôÄìÆî0@ `€ à]32654&#"#"3253#/§’’¨¨’’§s:±|ËÿÿË|±:¸¸/ËççËËççý®daDDadªùöºJ{0@  ‡¸ ¼ FüÄì21/äôìÄÔÌ90´PŸ].#"#3>32JI,œ§¹¹:º….´˾ý²`®fcoÿãÇ{'ç@<  S  SB †‰†‰¹¹%¸Œ( R"E(üÄìÔìä99991äôìþõîõî90KSXí9í9Y"²']@m   . , , , ; ; ; ; $( ( *//*(() )!$'† † † †      '/)?)_))€)) )ð)]]q.#"#"&'532654&/.54632‹N¨Z‰‰b”?Ä¥÷ØZÃlfÆa‚Œe«@«˜àÎf´?®((TT@I!*™‰œ¶##¾55YQKP%$•‚ž¬7òž8@©¼‡  Fü<Äü<Ä2991/ìô<Äì2990²¯]!!;#"&5#53w{þ…Ks½½Õ¢‡‡žþÂý ‰NšŸÒ`>®ÿãX`6@ ‡Œ ¼  NFüìôì21/ä2ôÄì90´`Ï]332653#5#"&®¸||•­¸¸C±uÁȺ¦ýaŸŸ¾¤{û ¬fcð=`@'B¿ÔÄ91/ì290KSXííííY"K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@ŽHj{†€‘¤  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz……‰‰‰†––—š˜˜—¨§°Àßÿ>]]3 3#=Ã^^Ãþ\ú`üT¬û V5` @IU U U U   B ¿    ÔÌ91/<ì2290KSXííííííííY"K° TK°T[K°T[K°T[K° T[X½ ÿÀ @878YK° TK° T[K°T[X½ @ ÿÀ878Y@ÿ" 5 IIF @ [[U P nnf yy‡™˜” ¼¼ÎÇÏ         %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } ‡ˆ——”“œ›˜˜™@/– Ÿ¦¦¤¤««©©«¤ ¯µ±½»¸ ¿ÄÃÌÊy]]333# #V¸æåÙæå¸þÛÙñòÙ`ü–jü–jû –üj;y` Z@F      B ¿  ÔÄÔÄ91/<ì290KSXííííííííY"K° TK°T[K°T[K°T[X½ ÿÀ @878YK°TX½ @ ÿÀ878Y@˜   & =1 UWX f vzvt ‚ ™Ÿ—’ ¦©¯¥£       )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x ›”«¤° Ï ß ÿ /]] # # 3 dþkªÙþºþºÙ³þrÙ))`ýßýÁ¸þHJþq=þV`¢@C        B  ‡½ ¼  ÔÄÄ91ä2ôì9990KSXíííííí2Y"K° TK°T[X½ÿÀ@878YK°TX½@ÿÀ878Y@ð     # 5 I O N Z Z j ‡ € “        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx‰Š … … ‰ ‰‰™ • • šš¤ ¤ ««°Ïßÿe]]+5326?3 3“N”|“lLT3!þ;Ã^^ÃhÈzšH†TNü”lXÛ` ´@B©¼© ÜÄ2Ä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878YK°TX½ ÿÀ @878Y@B&GI  + 690 @@E@@CWY_ ``f``b € ¯ ]]!!!5!qjýL´ü}´ýe`¨üÛ“¨%þ²$‚@4 %   ! © ©À ©±% $  C %Ô<Äü<Ä299999991üìÄôìî99999990K° TX½%ÿÀ%%@878Y²&]#"&=4&+5326=46;#"3>ù©lŽ==k©ù>DV[noZV¾”Ýï—ts•ðÝ“XøŽŽœøXþ®·±Ôì1üÌ0#®ªøþ²$ž@6%   ©©#À©±%#C %Ô<Ä2ü<Ä99999991üìÄôìî99999990K° TX½%@%%ÿÀ878YK°TX½%ÿÀ%%@878Y²&]326=467.=4&+532;#"+FŒUZooZUŒF?ù§lŽ>>Žl§ù?¾VøœŽŽøŽW“Ýð•st—ïÝ”ÙÓÛ1#@ œœ ÔÄ1ÔüÔìÀ990#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©1²OD;>MS²OE<>LÿÿhN'$¼uhm !Ë@T   !!  ! !!!B  Á • Ž  !  VV!"ÔÄÔì2Ôî299999991/<æÖîÔî9990KSXííííííííY"² #]@  s › P#f iu {yyv v!€# ]]4&#"326!.54632#!#TY?@WX??Y˜þð!þX=>Ÿsr¡?<Òˆý_ˆÕZ?YWA?XXþóýN)sIs ¡rFv)ú‹þÿÿsþu'ð'&Ý-ÿÿÉ‹k'(žuÿÿÉ3^'1þuÿÿsÿãÙN'2'uÿÿ²ÿã)N'8îuÿÿ{ÿã-f'DRÿÿ{ÿã-f'DCRÿÿ{ÿã-f'D×Rÿÿ{ÿã-'DŽRÿÿ{ÿã-7'DØRÿÿ{ÿã-'DÜRÿÿqþuç{'FÝÿÿqÿãf'H‹ÿÿqÿãf'HC‹ÿÿqÿãf'H׋ÿÿqÿã'HŽ‹ÿÿof'ÖÿÿÿÿǦf'ÖCÿÿÿÿÞ\f'Ö×ÿÿÿÿôF'ÖŽÿÿÿºd7'Qؘÿÿqÿãuf'Rsÿÿqÿãuf'RCsÿÿqÿãuf'R×sÿÿqÿãu'RŽsÿÿqÿãu7'RØsÿÿ®ÿãXf'X{ÿÿ®ÿãXf'XC{ÿÿ®ÿãXf'X×{ÿÿ®ÿãX'XŽ{9ÿ;ÇÕ '@¹  YW Y Ô<ìü<ì1äôÔ<ì203!!#!5!¨°oþ‘°þ‘oÕþ\™û£]™Ãu=ð  @ÃÄà ‘ Z[ZÜìüì1ôìüì0"32654&'2#"&546PnnPPnoO@v+..¹†‡´¸ooPOmmOOp1.-rB„·´‡†º¬þÇ#˜!Q@+  †ˆ †ˆ ¹ ¹¸Œ"  "ÜìÔ<Ô<<ì221äô<ÄìÄþôîõî9990%&&'667#&73¦“¤¤JˆDF‰HA‰Mfñþ÷ ñfI‰ƒX⸹⡬)*ü *'ª#þä 32þá!bð`@!† ©  ”‘   Ü<ÌÌü<ÄÔÄ1/ì2ôäìÔ<î2î990K° TX½ÿÀ@878Y´66].#"!!!!53#535632NLˆ=”t‡þy-üìÇÇÖè=—´¶))›Ô×þ/ªªÑîó\ÿ=¢ð >‘@54&.#"#"&'532654/.5467.54632{?>‹ú?>ÌS8alÎÓƒ\]>9Ì­IšXW”:fqÝÖ€][;;ȦI™¨.Z.L…‡-[.Kˆ“¤''PGZswšeZŒ54m@ލ¤''TLf{x™f[1,pE‚Ÿ3Ñ…! · Ç \ Ôì1Ôì04632#"&3­~|«¬}}¬ú|««|}¬¬žÿ;9Õ %@Á]] ÔÔüÜì91Ä2ôì90!###&&54$yÀ¾Ž×ëÕùfùáNݸ¾èºÿã¬/š@0-'!  *†¹*¹—Œ.  !' $'$-F0üÄüÌÆîÔîî99991/äþîþÕî990@@'(Š Š     ! "&  : :!MM I!I"jj ¥¥¦ ]]4632#"&'532654&/.5467.#"#ºïÚÐÛ—¨:A9¦`áÓ@ˆIPŒAtx;e\`W§—ƒq‚ˆ»qÈÛèàs`/Q*%jŽd¬·¤_[?T>7;‡[¬gp‹ƒû“åÍ/8L`@6EBC?2ÉH0É9JCÊ 9ÊÉÈ É$HE301BKL?gwyVpMIßÑ`3þœDåÍ/IC@&=Ë>:ÌAÊ$1Ë04ÌGÊÉÈ$É 7aD=0^* D^ JÜÌüìþí2î1/îöþýîÖîýîÖî02#"$'&5476$"32676654&'&&&&#"3267#"&54632˜mmllmmþù˜˜þùmmllmm˜ƒâ^^``^^⃄ã^]]^\^ã§B‚B•§«›@zBC‰FØûûØIˆÍnmmþúš˜þûmmnnmm˜šmmng^^^å‚ã^^__^]⃅ã]^^õ! ¯Ÿ®"ôÐÑò'“FÕ >@!  É  b b cbcÔäüäÔìÔì91ô<<ì2Ô<<Ä903#######5J®¤ªqÃ7ËrqËrÉÕÿý¾äþÑ/þB^þä^sîRf1@ ´³DÔì1ôì0K° TK°T[X½ÿÀ@878Y3#‹Çþº™fþˆ×F)’@ÎÍddÜüÔì1ü<ì20K° TK° T[X½@ÿÀ878YK° TK° T[K°T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@````pppp]3#%3#^ËËþyËËÊÊÊÙ'ÛÝ>@" Ïœ Ï œ  Ü<Ä291Ô<Ì2ü<ìþ<ì990!!!!!'7!5!7!Ù}®/þHÃ{üúþþ}®þÕ¶Ãý‡¢;fÕ¨ðªþÇfÓªðHÕ‡@9  B• ••••­    ÔÔ<ì2ÔÄÄ91/<ììÄôììîî0KSXííííY"²€]@gww† …– ¿ ]!!!!!!#!5ýÇý9øü=ýð Íq‹þ¶ËÕªþFªýãªþÕžüðfÿºå +ž@< +,  )&  *&•& •‘&Œ,+,* # )#3,üìüìÀ999999991äôìîÀÀ99999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''¶ý3>¡_Ü'y=¡_Üþý''†NOy;‚ÝW¢fªNPþˆþÆ€Ý[¢gXü²@CHp¸¸@Cþ¸þåp¼Džf b¥MK¿YÆgþöžþŸþ[KK¿XÝÝÏî /ÿ@- !$'!!0 $*0ÔÄÔÄ99991ÔÄÔÄÀ9990@¾     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV´° °!°"°&°'°(´)]]32654&#".#"326#"&54632>32#"&“1†Te€vYR…Ä1…UfvYR†F^ˆº§†_™HDža†¼§†^•/XZ‡ie†‡7XX„je†ˆ‡ߦ¯Ø~ŠŠƒá§¯ÖwÙÛ .@МР œ   Ô<ì2ü<ì21/ìÔ<ìü<ì0!!#!5!!!®-ýÓ¨ýÓ-ýÓúþþ}ªþ}ƒªƒû¦ªÙÛ¨ T@.œœœœBѧœ $# ü<ì2291/ìôì90KSXííííY" 5!!Ûü@Àúþúþúþøþëþî²pªoüªÙÛ¨ V@/œœœœBѧœ$ # ü<<ì291/ìôì90KSXííííY"55!5ÙúþÁAúþø°þ‘ªþ²ýǪªRÃÕÆ@F  B Ó Ó   fe f eÔ<ì2ìüì2ì99991/ä2Ô<ì2Ô<ì290KSXííííY"K° TX½ÿÀ@878Y@(†¦ µ' ' ')((79‡ ˆ¦ ¥ª©]]!#!5!5'!5!3 3!!!þcÉþ` Tþ´þþ{y¿þÂþµTŸÇþ9Ç{3›{JýD¼ý¶{›3®þVå` M@% ‡Œ ¼½!   NF!üì2ôìÄ91ää2ô<ìÜÄ990¶"`"Ï"]3326533267#"&'#"&'®¸Š‡”•¸#% )I#ER2‘bf*þV ýH‘”¨¨ü¢<9 ”NPOONNý×hÿçÁ-)b@'! '!Õ* $$*ÔÌÜÌ9991äÌÜÌÎÎ990K° TK° T[K°T[K°T[K°T[X½*@**ÿÀ878Y>54&#"#"&54632#"&54324&#"32ôIH7$$0e´ÖþßÕ˜ËÝ¢e‚ WOmVPmmW£Kƒt,>bþÊþùþ±þFØ£Æ[àt}þþÏt{þw;Á ]@    ÔÄ91ÄÔÌÎ990@0QVPZ spvupz €€ Z pp{ t €€ ]]!! !!5 7êüA ýJïúÞÕýIÁÁý3ýÀ•!ãœþwqÁ@×Ö¯ggÔìÔì1üìì20!#!#œÕðý ïÁø¶}ùƒÿáÿðª/#Ë@1 ÚÙ"ØÕ $ #" #h#$ÔÔÔì9999991/<äôì22î9990K° TX½$ÿÀ$$@878Y@V             ##(]]#3267#"&5467!##"#>3!‡¶i/7.%7vy"PþºÂµÃ)6<  ¥y‘þJ\:1fd.¡xüo‘@E¦}/þú%&@ Û Ûܱ& iji&Üìüì1üìÜäÞä026732#"&'&&#"#"&546327j ¾ÊPd@7*8  k½ÄOeD=!0 þú°l9¼TA6?&#Hý•Ánþ!þbSA8?SsÕ;ð)_@3(%ãÝá%Ý ßÞÝ à‘* "(kl"k *ÜìÌüì22ÀÀ9991ôäüôìÄîíÖîî99990!!#5#"&5463354&#"56632"32655‹°ýP®•,]€˜¿¼¶uu>ˆDI‘E·³þì¡~bRh‚P{¸þ@p?D‡q‡Š[[""°ðCO@Mr`Õdð.@ãáÝ àÝ‘ klk Üìüì991ôìôìüì0!!2#"&546"32654&‹°ýPX³Îγ³Ðгi~hi}|P{Ý¿¿Ûܾ¿Ýs¡ˆ…  …‰ NÏç@@" å‘å  mm  ÔììÔììÀÀ9991/<ì2ôì0%!5654#"!5!&5! Ïý¨±ÆþøØØþ÷Dzý¨?ž‘1/Ž¡²²²aLÊð"þÝïÊþ´a²²‹*¸>ŠþwþËÂþØ{ÿão{3>@C'-%= 4©%†ˆ©:¹.†-º*¹»1 ¸Œ%?47&%7& =&-7"E?üìÌÔü<ÔìÄ999991Ää2ô<Ääü<ôìÄî2îôîî9990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0…+…0€@@ @°@À@Ð@à@à@ð@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/€,€-€.€/]q].#">32!3267#"&'#"&5463!54&#"5>32"326=¶¥‰™¹DJÔ„âü² Ì·hÈddÐj§øMIؽÒýû§—`¶Te¾ZŽÕï߬o™¹”—´®ž0Z^þÝúZ¿È55®*,ywxx»¨½À‹..ª''`þf{bsÙ´)Hÿ¢œ¼ +ä@<+,&  )&  *&¹& ¹¸&Œ,+,* # #Q)E,üì2ôì2À9999991äôìîÀÀ99999990@p(?-YVUV jf!{    { z{ {!"#$%{&›•%¨ -ð-&YVUZ(ifej(ztvz(‰•š$¢­$]] 32654&'.#".5327#"&''‰þ)gA“¬\*g>—©}66ñ]ŸC‹_’56þîð`¡?‹`!ý°*(èÈOuš))ëÓHn.—MÅw834¨O³MÆxþíþÇ43¨Nÿã¬Õ $†@/ †ˆ !ƒ# •Œ#%" " "!& %ÜìÔüìÔì99991äôìþÍôî9990K°TK°T[K°T[X½%ÿÀ%%@878Y@ ttttv]33267#"&546?>7>5#53ô¾7ZZ:3ƒmN´`^Àg¸àIYX0&ÄÊÊDœe‚WX5^1YnFC¼98ŸL‰VV/5<6þ5Õ b@ƒ ü<ì2991/ôüÌ0K° TX½ @ ÿÀ878YK°TK°T[K°T[X½ ÿÀ @878Y¶ P ]#53#3ËËË¢×þú+eþ›ÙÛ^@ œÜÔì1ÔÄì0!#!Ù¨û¦^ýÁ•=ÿ×} *@    ÔÌ91ÔÌÄ903##'%\½sý®BþÁ}}`ùºs-Pbý;þV#Š@@   B   ©Šæ©Šæ©!—$  $ÔÌ91Ä2Äüìôìîöîî299990KSXí2í9Y"K° TX½$ÿÀ$$@878Y.#"!!#"&'53267#5!>32&P,`r<þÃ:¼º:d/4a/am"‰ø?$Æ—5dð¤z„þÉý…þãÓ¦!!‰¦­J·ÃÙÛô;?@.9*-" *œ19œ"œ œ<-<Ô<Ä21ÔìÔìÜüÔìÀ9999990#"'&'&'&#"56632326#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©gi³an’ ›^X¬bi³an“ ›^V©o³NE;=LT³NE;=KÚ²OE;=LS²NE;=Kÿú`Á8@ÔÌ91/ÄÌ90@cmpxyvn]] !3!¬þ^DýïàCúšîûÄú?ž%# †@Ièèèè è è è  è B  ç¦ o o nüü<Ôì2991ô<ì2990KSXííííííííY"55%þÓ-þ+#þÓ-þ+#¿þôþô¿¢R¢¿þôþô¿¢RÁH# †@I è è è è èèèèB  ç¦ o opü<üÔ<ì991ô<ì2990KSXííííííííY"5%5ÁÕþ+-þÓ²Õþ+-þÓ#þ^Rþ^¿  ¿þ^Rþ^¿  ìþ #@ƒ   ÔüÔìÔì1/<<ì220%3#%3#%3#–ÔÔ©ÕÕú­ÕÕþþþþþþÿÿhk'$¼uÿÿh^'$¼uÿÿsÿãÙ^'2'us Õ;@•••­   üìÔÄÄÔì299991/ìì2ôì2î0!!!!! !# !3úýÇý9øû×þOþA¿±gþ¿þÀ@AÕªþFªýãª|pm|ªþáþàþßþßqÿãÃ{'3„@1†ˆ ©. ¹(¹»"%¸Œ4"1 K1 Q+E4üìôüôìÄ9991ä2ô<Ääì2Äî2îôî90@%?5_5p5Ÿ5Ï5Ð5ð5????? ooooo ]q].#"!3267#"&'#"32>32%"32654& ¤‰™¹Hü² Ì·jÈbdÐj òQGÑŒñþïñŒÓBNèâú°”¬«•“¬¬”˜³®ž5Z¾Ç44®*,nmnm98olkpþ݇çÉÉçèÈÇééy¶©é/Æ1üì0!!üyéyµ©/Ì1Ôì0!!øy®émÕ '@ž   ÜüÌÔÌþÔÎ1ô<ì20#53#53Ó¤RšÓ¤Ré­?þÁ­­?þÁ®émÕ '@ ž  ÜìÔÌÜîÔÎ1ô<ì203#%3#Ó¤RšÓ¤RÕ¬þÀ@¬¬þÀ@®éÓÕ@ žÜüÔÌ1ôì0#53Ó¤Ré­?þÁ²þ×Õ@ žqÜìÔÌ1ôì03#Ó¤RÕ˜þÁ?Ù–Ûo )@êêœ r ÜÔ<ü<Ä1ÔÄüÄîî03#3#!!ßööööýúúþoöþõAªþ#îu"@ÔÌ91ÔÌ990 úþþôþ þ üÏüÇ9%ûÛûÓ-ÿÿ=þV'\Ž^ÿÿÿüçN'<suþ‰ÿãÍð+@BŒ‘ÔÌ1ää0KSXííY"3#- ü\ ðùó^R¼²#/ƒ@I -'! - -¹ëì'¹ë!0 *$0* $ $(st*(s0Üäìôäì9999999991ÔäìôäìÀ9999999907'#"&''7&&5467'766324&#"326{ÏrÎ%$&(ÑrÏ;t=:x=ÏqÏ%%&&ÏsÏ7t@?s9ÏqÏ(&%%ÏsÎ>v:@t8ÎsÏ'%$þ|pššprœžs#G@%èèèèBç¦onüì291ôì90KSXííííY"5sþÓ-þ+#¿þôþô¿¢RÁ–#I@&èèèèBç¦opü<ì91ôì90KSXííííY"5ÁÕþ+-þÓ#þ^Rþ^¿  /J›@( ©‡¾±— ¼ Lü<Ä2Äü<Äî2991/<æ2îþîîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€€€ Ðï]]#!##53546;#"3#J¹þ¹°°­³¹°cMù¹¹`û Ñü/ÑN·¯™Phc²é/J„@! © ‡— ¼   Lü<ÄÄü<Äî991/<æ2þîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€ € € Ðï]!#!"!!##53546J¹þ·cM/þѹ°°®ùì{Phcü/ÑN»«9ÿ;ÇÕ>@ ¹¹  ÂY W Y Ô<<ì2ü<<ì21äôÄ2Ä2î2î20%!#!5!!5!3!!!Çþ‘°þ‘oþ‘o°oþ‘oßþ\¤š™¤þ\™ýáÛH®F·ƒÔì1Ôì03#ÛÓÓFþ®ÿÓþ@ žƒÔìÔÌ1üì0%3#Ó¤Rþ¬þÀ@®ÿmþ '@ žƒ   ÜìÔÌÜîÔÎ1ü<ì20%3#%3#šÓ¤RþfÓ¤Rþ¬þÀ@¬¬þÀ@qÿã Lð #'3?K®@D$%&%&'$'B@’ .’(’F’4 :&Œ$‘L%IC'1+C =  1 =I 7+ ! LüäìÔÄìäîîöîî991ä2ô<<ä2ì2îöîî20KSXííY"K°TK° T[K° T[K° T[K° T[K°T[X½L@LLÿÀ878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&ôWddWUccUžº» º»ùtž¼»ŸŸ¹º% üZ VcbWWcd²žº» º»ŸWccWUcc‘”„‚••‚ƒ•Ü»»ÛÛ»¼ÛàÛ»½ÚÛ¼ºÜùóŽ•‚„””„–ýŸÜ»»ÛÛ»¼Û”„‚••‚ƒ•ÿÿhm'$¼uÿÿÉ‹m'(žuÿÿhk'$¼uÿÿÉ‹N'(žuÿÿÉ‹k'(žuÿÿ¢k',ÿ/uÿÿÿþ`m',ÿ/uÿÿXN',ÿ/uÿÿ;ºk',ÿ/uÿÿsÿãÙk'2'uÿÿsÿãÙm'2'uÿÿsÿãÙk'2'uÿÿ²ÿã)k'8îuÿÿ²ÿã)m'8îuÿÿ²ÿã)k'8îuÁy` ·¿Füì1/ì0@ @P`p]3#Á¸¸`û Áî?f7@ ´³uÜì91ôì290K° TK°T[X½ÿÀ@878Y3#'#¶”õ‹´´‹fþˆõõ¶J7c@$  Ãà íVwVvôìüì99991ü<üÔ<ì99990K° TK° T[X½ÿÀ@878Y'.#"#>3232673#"&ü9! &$}f[&@%9! &$}f[&@Z7IR‡“!7IR‡“Õb+ö/·ïîÔÌ1üì0K° TK°T[X½ÿÀ@878Y!!ÕVýªö”Ç)9H W@ ð³VVÜìÔì1ô<Ôì0K° TX½ÿÀ@878YK°TK°T[K°T[X½@ÿÀ878Y332673#"&Çv aWV` v ž‘‘žHKKJLšDf,@ ÎÍdÔì1üì0K° TX½ÿÀ@878Y3#šÌÌÌîá _@Áò ÁñV xVÔìôì1ôìôì0K° TK° T[X½ÿÀ@878YK° TK° T[K° T[X½ÿÀ@878Y4&#"3267#"&54632˜X@AWWA@XzŸssŸŸssŸô?XW@AWX@s  ssŸŸ#þuÁ@  ó' ÜÔìÔÌ1/ÔüÄ90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ ƒ0.W=ðî®fB@´³ÔÜÔÌ991ô<ì20K° TK°T[X½ÿÀ@878Y3#3#ü²ø‡ªß‰fþˆxþˆLþuÁ @  óô 'ÔìÄÔÌ1/üüÄ90!33267#"&546¸w-+76 >&Dzs5=X..… W]0iÁî?f7@ ´³uÜì91ô<ì90K° TK°T[X½ÿÀ@878Y373¶õ‹´´‹õîxõõþˆÿòuÕ ?@ •  : yô<ìÄü<Ä991/äì90´0P]3%!!'7ÓË9Pþw×ü^”MáÕý˜Ûoþîýãª;jnžH ^@ — z z Ô<äü<ä991/ì90K°TX½ @ ÿÀ878Y@ @ P ` sz p à ð ]37#'7Ǹ}Lɸ{JÅý¦ZjüãšXjÿÿ‡ÿã¢m'6‹uÿÿoÿãÇf'Vàÿÿ\m'=¾uÿÿXÛf']àþ¢®˜@ õõÜ<ì21ÔìÔì0##®ªªª˜ý öý ö ºÕ g@  © ••  2  yô<ì2ÄôìÄ91/Æ2îöîî20@( °Ÿ Ÿ Ÿ Ÿ ŸŸŸŸ¿ ¿ ¿ ¿ ¿¿¿¿]]! )#53!!3 !Ó ±–þiþPþ`ÉÉËPþ°ó5þáþËÕþ—þ€þ~þ–¼ãþýê.,qÿãu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ##¹ ¹Œ#±)&' ! (%#" QE)üìôì99999991ìÄôìî9990KSXÉÉÉÉííííY"²?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x" *ð*']].#"32654&#"5432''%'3%F2X)§¹®’‘®6 ~rþäæçþåÝ4*ŸþÁ!µäM!þÙ“ØÃ¼ÞÞ¼z¼&þà­ÿþÉ7ÿú7´kc\Ì‘oabÿÿÿüçk'<suÿÿ=þVf'\^ÉÕ =@• •ö  ? üì22üì91/ôüìÔì0@ ?_]332+#32654&#ÉÊþûþÿûþÊÊþš™ŽÕþøáÜÜâþ®'ýÑ’††‘ºþV¤>@¹¹Œ¸½— GFüì22ôì1ìääôÄìÆî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý®¾ý¢daþ¼þøþøþ¼aëËççËËççÙ-Û×¶œÔÄ1Ôì0!!Ùúþת?œÅ …@M œ  œœœœœ œ œ B   Ô<Ì291Ô<Ì290KSXííííííííY" '7œþ7Éwþ5þ5vÈþ8vËËLþ5þ7yËþ5yÉËyþ5ˉœÅß ,@Ý ÝÝ ÷‘ |]|| Üôäüä1ôììÔìî2035733!œÌßæ‰Íý× c)t'ý+n^œ´ðJ@$}}BÝÝ÷ Ý‘~ÜÄÔÄì91ôÄìüìî90KSXí2íY"!!56754&#"56632 ¨ýª"?XhU4zHM…9‘®þµ8rn81^BQ##{„l‹þä0bÍð(H@' Ý Ý Ý Ý ø÷Ý ø#‘)~&~ )ÜÄÄÔìÔì9991ôäìüäìÔìîî90#"&'532654&##532654&#"56632 \e¾±9}F4wCmxolV^^ad_(fQI€7©Z`mR|†yOFJLl?<:=svcE`ÿÿ‰ÿãð'ð'¼5 ‹ýdÿÿ‰ÿã?ð'ð'¼5ñ‹ýdÿÿbÿãð'ò'¼5 ‹ýdÿÿsÿã‹m'* uÿÿqþVZH'JÚ‹ÿÿÉ•P', ÿ/uÿÿ‡þu¢ð'6Ý‹ÿÿoþuÇ{'VÝÿÿsÿã'k'&-uÿÿqÿãçf'F‰ÿÿsÿã'm'&-uÿÿqÿãçf'Fà‰qÿãô$J@$Ó ù"¹¹ Œ¸—   GE%üìô<Äü<Ä1/ìäôÄìÄîý<î20¶`&€& &]!5!533##5#"3232654&#"¢þºF¸šš¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶N}““}úü¨daDDaþËççËËççd߃¶œÜÌ1Ôì0!!dý僤ÛH®F·ƒÔì1Ôì03#ÛÓÓFþÿãð1@: Ó"+Ó ¡®•¡®•/‘Œ) 2+"!)#&  , & &*!/<ÔÄ2üÄÄ99999999991Ä2äôìôìîöîî2Ý<î20K° TK° T[K° T[K°T[K°T[K°T[X½2ÿÀ22@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-ŸŸŸ Ÿ Ÿ Ÿ Ÿ ŸŸŸŸŸŸ–Ÿ Ÿ!Ÿ"Ÿ#Ÿ$Ÿ%Ÿ&Ÿ'Ÿ(Ÿ)Ÿ*Ÿ+Ÿ,-2   USjg ]].#"!!!!3267#"#734&5465#7332[©fÊ A7ýæ¾8þŠ Êf©[Y¹`íþË(Ó7‹Â7œ(6ìb¹bÕiZÈ»{.# .{»ÊZiÓHH"{/ #/{"G×)Ù¥@ ÎddÔüÜì1Ô<ì20K°TK°T[X½@ÿÀ878YK°TK° T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y@````pppp]3#%3#^ËËþyËËÙËËËsîðö@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@ %%6FVjg //]]3#7¹ä™öþø¶Jéu@!  ÃÃúVV ÔìÔì99991ô<ìÔì2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y´ ]'.#"#4632326=3#"&ü9 $(}gV$=09" (}gT";9! 2-ev 3)dw î‹ö‰@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@*$$5CUUŸŸ¯¯//]]#ÇÄ™æöþøÏî1øw@ úÔÄ91ô<Ä90K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ //- ]3#'#¢¼Ó‹¦¦‹øþö²²Ïî1ø†@ úÔÄ91ôÄ290K° TK° T[K° T[K° T[X½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ "  ]373¢Ó‹¦¦‹Óî ²²þö?œôß Ô@ Ý ÷‘ ] ÜÔ<Äì291ôüÔ<ì290K°TK°T[K°T[K°T[K° T[K° T[X½@ÿÀ878YK°TK°T[X½ÿÀ@878Y@T /9IFYi‹«»       "5GK S[ e„¥µ]] !33##5!5ÝþË5¦‡‡þbfþ]ýämººyÇ9ø j@à úVVÔìÔì1ôüÄ20K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TK°T[X½ÿÀ@878Y332673#"&Çv cSRav  Ÿø6978w{zšfÛ¶úÔÌ1ôÌ03#šÌÌÛÍ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßà>: ~ÿ1BSax~’ÇÝ©À & 0 : ¬!""""+"H"e%Êûÿÿ   0AR^x}’ÆØ©À  0 9 ¬!""""+"H"`%ÊûÿÿÿãÿõÿØÿ ÿ^ÿCÿhÿüöüÛà–à…àVßjÞqÞ_Úï¿8ôüúúü (B¬£„…½–熎‹©¤ŠÙƒ“ñò—ˆÃÝðžªóôõ¢­ÉÇ®bcdËeÈÊÏÌÍÎèfÒÐѯgï‘ÕÓÔhêì‰jikmln oqprsutvwéxzy{}|¸¡~€ëíºýþÿøÖùúãä×àÚÛÜßØÞ²³¶·Ä´µÅ‚‡«˜¨š™î¼¥’”•Íf‹‹55®Å´žªšq=3ۤ=´Ù‹žãd‹Û²‡á–œdž¨‹²ð²ž´Ù´Ù´Ù?“‡y}É–s)ÉÉšÉ3sÉ\É\ÿ–?ÉuÉçÉüÉLsÓÉLsɇãÿúÛ²yéD{=ãÿü{\°²Ç´Ùÿìªç{ºfqqìqÑ/qº9Á9ÿÛ¢º9Á˺ºåqºqJº+o#7®¼=‹V¼;¼=3X²´Ùyy–sÉüÉLsÛ²ç{ç{ç{ç{ç{ç{fqìqìqìqìq99ÿÇ9ÿÞ9ÿôºåqåqåqåqåq®®®®9ì\¸3ž º's×´ÙËLfªÝ´Ù´Ù´ÙR®#hdœ¶ÿá+/ÅsÅ`NÛ{åH?55´Ù=´ÙZÿúåžåÁìyyLss/q%®%®‹®‹²´Ùô¼=ãÿüVþ‰^3ž3Á / /9‹Û‹®%® ¼qyÉyÉÉ\¢\ÿþ\\;LsLsLsÛ²Û²Û²9ÁÁ¶ÕÇšî#ðLÁÿòF‡+o{\3X²3 åqãÿü¼=×ɺ´Ù´5‰5^5bÁ‰Á‰Áb3sq\ɇ+o–sfq–sfqqãd‹Û×s¶ ÏÏ5?Çšÿ+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóõôöøùúûüýþÿ     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""X“ÿ¶Oƒ²ö!n˜´ÊÞE‚~áL·üeÏî  R s ®  ß X ° û : i “ æ  = z /¬E…ëuñ)pཊëP‹±á@Ö"m¹#{ßC€øw³R¡Ø‡Äº‡wè [ r ó!5!B!â!ï!ü" ""#"0"="J"W"d"q"~"‹"˜"¥"²"¿"Ì"Ù"æ"ó## ##'#4#A#N#[#h#”#Ï$4$%3%S%&&º'K''·((X(Ã)_*%*\*£*é+z+Ó,D,,±-P- ..R.ª/‡0A0½11!1P1Ï2H2z2ß3F3p3p3}3Š3—3æ4z44£4Ñ4ÿ5595g5‘5ž5«5Ï6[6“6Í7C7©7ë888J999)969C9P9]9j9w9„9‘9ž9«9¸9Å9Ò9ï::{: :å;;^;Ž;Ä;ô<"<_<§<´<Á<Î<Û<þ=c>;>H>U>˜>ç>ý?a??Ü@:@K@\@m@z@‡@”@¡@®@»@È@Õ@âA@AVAkBEBªB÷C_C²CÿDUDÛE*E?-†” x$ÿÓ%ÿ·&')*K+-r./2934K57ÿD9ÿˆ:ÿ­;ÿš<ÿ =IQR&UYÿÉZ\ÿÜbÿÓdg9xy&z&{&|&}&‰­ÿÓ®ÿÓ¯9ºÿÜ»ÿ ÇÿÓÉÿÓÐ9Ñ9Ò9åéêÿ ëÿÜìöKûý$ÿÓ$ÿÜ$ÿÜ$$9$&ÿÜ$*ÿÜ$2ÿÜ$4ÿÜ$6$7ÿa$8$9ÿ}$:ÿ$;$<ÿa$FÿÜ$GÿÜ$HÿÜ$Iÿ·$RÿÜ$TÿÜ$WÿÜ$X$Yÿˆ$Zÿ­$\ÿu$b9$dÿÜ$gÿÜ$h$oÿÜ$pÿÜ$qÿÜ$rÿÜ$sÿÜ$yÿÜ$zÿÜ${ÿÜ$|ÿÜ$}ÿÜ$~$$€$$©ÿ·$ª$­9$®9$¯ÿÜ$´þø$µÿ$ºÿu$»ÿa$Å/$Ç9$É9$ÐÿÜ$ÑÿÜ$ÒÿÜ$Ó$Ô$Õ$ã$êÿa$ëÿu$öÿÜ$ù$ûÿÜ$üÿÜ$ýÿÜ$þÿÜ%%&ÿÜ%*ÿÜ%2ÿÜ%6ÿÜ%9ÿÁ%:ÿ·%<ÿ%dÿÜ%gÿÜ%©ÿÁ%ªÿÜ%¯ÿÜ%´ÿ%µÿ%»ÿ%Åÿ­%ÐÿÜ%ÑÿÜ%ÒÿÜ%ãÿÜ%êÿ%öÿÜ%ùÿÜ%ûÿÜ%ýÿÜ&&$&6&<ÿÜ&b&©ÿÜ&ªÿÜ&­&®&´&µ&&»ÿÜ&Å&Ç&É&ã&êÿÜ&ù''$ÿÜ'9ÿÜ':'<ÿ'bÿÜ'©ÿÜ'ªÿÜ'­ÿÜ'®ÿÜ'´ÿÓ'µÿÉ'»ÿ'ÅÿD'ÇÿÜ'ÉÿÜ'êÿ))þ·)ÿa)$ÿD)6ÿÜ)7ÿÜ)DÿD)Hÿ)Lÿk)Rÿ·)Uÿk)Xÿ)\ÿD)bÿD)iÿD)jÿD)kÿD)lÿD)mÿD)nÿD)pÿ)qÿ)rÿ)sÿ)yÿ·)zÿ·){ÿ·)|ÿ·)}ÿ·)~ÿ)ÿ)€ÿ)ÿ)©)ª)­ÿD)®ÿD)´ÿÓ)µ)ºÿD)Åþˆ)ÇÿD)ÉÿD)ãÿÜ)ëÿD)ùÿÜ**$*7ÿ·*:*<ÿš*b*©ÿÜ*ªÿÜ*­*®*´ÿÓ*µÿÓ*»ÿš*ÅÿÉ*Ç*É*êÿš++ÿÜ++©+ª+´ÿ·+µÿÁ+Åÿ·-ÿ·-$ÿÜ-bÿÜ-©ÿÜ-ªÿÜ-­ÿÜ-®ÿÜ-´ÿ·-µÿÁ-Åÿ-ÇÿÜ-ÉÿÜ.ÿ).$ÿÜ.&ÿ.2ÿ.7ÿa.8ÿÉ.:ÿ·.<ÿ·.DÿÜ.Hÿš.Rÿš.Xÿš.\ÿk.bÿÜ.dÿ.gÿ.hÿÉ.iÿÜ.jÿÜ.kÿÜ.lÿÜ.mÿÜ.nÿÜ.pÿš.qÿš.rÿš.sÿš.yÿš.zÿš.{ÿš.|ÿš.}ÿš.~ÿš.ÿš.€ÿš.ÿš.©ÿ}.ª.­ÿÜ.®ÿÜ.¯ÿ.´ÿÁ.µÿÁ.ºÿk.»ÿ·.Å.ÇÿÜ.ÉÿÜ.Ðÿ.Ñÿ.Òÿ.ÓÿÉ.ÔÿÉ.ÕÿÉ.êÿ·.ëÿk.ûÿ.ýÿ/ÿÜ/$//2ÿ·/7þæ/8ÿš/9ÿ/:ÿD/<þð/D/HÿÜ/RÿÜ/XÿÜ/\ÿD/b//gÿ·/hÿš/i/j/k/l/m/n/pÿÜ/qÿÜ/rÿÜ/sÿÜ/yÿÜ/zÿÜ/{ÿÜ/|ÿÜ/}ÿÜ/~ÿÜ/ÿÜ/€ÿÜ/ÿÜ/©/ª/­//®//¯ÿ·/´þa/µýæ/ºÿD/»þð/Å/Ç//É//Ðÿ·/Ñÿ·/Òÿ·/Óÿš/Ôÿš/Õÿš/êþð/ëÿD292ÿ­2ÿÜ2$ÿÜ29ÿÜ2;ÿ}2<ÿ2bÿÜ2©ÿÜ2ª2­ÿÜ2®ÿÜ2´ÿÓ2µÿÜ2»ÿ2ÅÿD2ÇÿÜ2ÉÿÜ2êÿ3ÿÓ3þÁ33$ÿ}383:3<ÿÓ3Dÿ¤3Hÿ·3LÿÓ3QÿÜ3Rÿ·3UÿÜ3VÿÜ3XÿÜ3\3bÿ}3h3iÿ¤3jÿ¤3kÿ¤3lÿ¤3mÿ¤3nÿ¤3pÿ·3qÿ·3rÿ·3sÿ·3xÿÜ3yÿ·3zÿ·3{ÿ·3|ÿ·3}ÿ·3~ÿÜ3ÿÜ3€ÿÜ3ÿÜ3©ÿÜ3ª3­ÿ}3®ÿ}3´&3µ&3º3»ÿÓ3Åþ·3Çÿ}3Éÿ}3Ó3Ô3Õ3äÿÜ3êÿÓ3ë3úÿÜ494©4ª4´ÿÓ4µÿÜ4Åÿ}5ÿ­5ÿ·5ÿÁ5$ÿ­5&ÿš57ÿk59ÿ5:ÿ­5<ÿ}5DÿÓ5Hÿ¤5Rÿ¤5Xÿ¤5\ÿ5bÿ­5dÿš5iÿÓ5jÿÓ5kÿÓ5lÿÓ5mÿÓ5nÿÓ5pÿ¤5qÿ¤5rÿ¤5sÿ¤5yÿ¤5zÿ¤5{ÿ¤5|ÿ¤5}ÿ¤5~ÿ¤5ÿ¤5€ÿ¤5ÿ¤5©ÿ5ªÿÜ5­ÿ­5®ÿ­5´ÿk5µÿ}5ºÿ5»ÿ}5ÅÿÜ5Çÿ­5Éÿ­5êÿ}5ëÿ5ûÿš5ýÿš6$&6&6*6264666b&6d6g6­&6®&6¯6Ç&6É&6Ð6Ñ6Ò6ã6ö6ù6û6ý7ÿD7ÿ 7ÿ7$ÿa7&ÿˆ77ÿÜ7Dþ­7Fþ¤7Hþ¤7LÿÁ7Rþ¤7UþÓ7Vþ­7XþÉ7Zþ­7\þÁ7bÿa7dÿˆ7iþ­7jþ­7kþ­7lþ­7mþ­7nþ­7oþ¤7pþ¤7qþ¤7rþ¤7sþ¤7yþ¤7zþ¤7{þ¤7|þ¤7}þ¤7~þÉ7þÉ7€þÉ7þÉ7©ÿD7ªÿ7­ÿa7®ÿa7´7µÿÓ7ºþÁ7Åþø7Çÿa7Éÿa7äþ­7ëþÁ7úþ­7ûÿˆ7üþ¤7ýÿˆ7þþ¤8$8-8=ÿÜ8b8­8®8Ç8É8åÿÜ9ÿˆ9þø9ÿY9$ÿ}92ÿÜ9Dÿa9Hÿa9LÿÓ9Rÿa9Xÿu9\ÿÉ9bÿ}9gÿÜ9iÿa9jÿa9kÿa9lÿa9mÿa9nÿa9pÿa9qÿa9rÿa9sÿa9yÿa9zÿa9{ÿa9|ÿa9}ÿa9~ÿu9ÿu9€ÿu9ÿu9©ÿN9ªÿ9­ÿ}9®ÿ}9¯ÿÜ9´9µ9ºÿÉ9Åþæ9Çÿ}9Éÿ}9ÐÿÜ9ÑÿÜ9ÒÿÜ9ëÿÉ:ÿ­:ÿ:ÿˆ:$ÿ:Dÿ}:Hÿˆ:LÿÓ:Rÿˆ:Uÿ¤:Xÿ·:\ÿÜ:bÿ:iÿ}:jÿ}:kÿ}:lÿ}:mÿ}:nÿ}:pÿˆ:qÿˆ:rÿˆ:sÿˆ:yÿˆ:zÿˆ:{ÿˆ:|ÿˆ:}ÿˆ:~ÿ·:ÿ·:€ÿ·:ÿ·:©ÿ:ªÿÜ:­ÿ:®ÿ:´ÿÜ:µ:ºÿÜ:Åþø:Çÿ:Éÿ:ëÿÜ;ÿš;$;&ÿk;2ÿ};7ÿÜ;Hÿ¤;b;dÿk;gÿ};pÿ¤;qÿ¤;rÿ¤;sÿ¤;©ÿ;ª;­;®;¯ÿ};´ÿa;µÿ­;ÅÿÓ;Ç;É;Ðÿ};Ñÿ};Òÿ};ûÿk;ýÿk<ÿ <þa<þð<$ÿa<&ÿ<2ÿ<Dþæ<Hþð<Lÿ·<Rþð<Xÿ<bÿa<dÿ<gÿ<iþæ<jþæ<kþæ<lþæ<mþæ<nþæ<pþð<qþð<rþð<sþð<yþð<zþð<{þð<|þð<}þð<~ÿ<ÿ<€ÿ<ÿ<©ÿ<ªÿk<­ÿa<®ÿa<¯ÿ<´ÿ<µÿÜ<Åþø<Çÿa<Éÿa<Ðÿ<Ñÿ<Òÿ<ûÿ<ýÿ=ÿÜ=©=ª=´ÿÜ=µÿÜ=ÅÿÜH[ÿÜIÿIÿkIÿ·IWÿÜIZÿÜI\ÿÜI©ÿ·IªÿÜI´AIµIºÿÜIÅÿIëÿÜNDÿÜNHÿ·NRÿ·NXÿÁN\ÿ·NiÿÜNjÿÜNkÿÜNlÿÜNmÿÜNnÿÜNpÿ·Nqÿ·Nrÿ·Nsÿ·Nyÿ·Nzÿ·N{ÿ·N|ÿ·N}ÿ·N~ÿÁNÿÁN€ÿÁNÿÁNºÿ·Nëÿ·QQQQ©QªQ´ÿkQµÿQÅÿ¤R&RÿÜRR[ÿÁR©RªR´ÿkRµÿ·RÅÿ}Uÿ}UÿDUÿÜUFÿÓUGÿÜUHÿÓUIUJÿÜUKÿÜUPÿÜUQÿÜURÿÓUTÿÜUUÿÜUXUYUZU[ÿÉU\U]UoÿÓUpÿÓUqÿÓUrÿÓUsÿÓUxÿÜUyÿÓUzÿÓU{ÿÓU|ÿÓU}ÿÓU~UU€UU©ÿ·UªU´UµVUºUÅþÉUæUëU÷ÿÜUüÿÓUþÿÓYÿÉYÿaYÿY©ÿÜYªÿÜY´YµÿÜYÅþðZZÿDZÿZ©ÿÜZªÿÜZ´ZµZÅÿ)[FÿÜ[HÿÁ[RÿÁ[oÿÜ[pÿÁ[qÿÁ[rÿÁ[sÿÁ[yÿÁ[zÿÁ[{ÿÁ[|ÿÁ[}ÿÁ[üÿÜ[þÿÜ\ÿÜ\þÜ\ÿk\©ÿÜ\ªÿÜ\´\µ\ÅþÓbÿÓbÿÜbÿÜb$9b&ÿÜb*ÿÜb2ÿÜb4ÿÜb6b7ÿab8b9ÿ}b:ÿb;b<ÿabFÿÜbGÿÜbHÿÜbIÿ·bRÿÜbTÿÜbWÿÜbXbYÿˆbZÿ­b\ÿubb9bdÿÜbgÿÜbhboÿÜbpÿÜbqÿÜbrÿÜbsÿÜbyÿÜbzÿÜb{ÿÜb|ÿÜb}ÿÜb~bb€bb©ÿ·bªb­9b®9b¯ÿÜb´þøbµÿbºÿub»ÿabÅ/bÇ9bÉ9bÐÿÜbÑÿÜbÒÿÜbÓbÔbÕbãbêÿabëÿuböÿÜbùbûÿÜbüÿÜbýÿÜbþÿÜdd$d6d<ÿÜdbd©ÿÜdªÿÜd­d®d´dµ&d»ÿÜdÅdÇdÉdãdêÿÜdùg9gÿ­gÿÜg$ÿÜg9ÿÜg;ÿ}g<ÿgbÿÜg©ÿÜgªg­ÿÜg®ÿÜg´ÿÓgµÿÜg»ÿgÅÿDgÇÿÜgÉÿÜgêÿh$h-h=ÿÜhbh­h®hÇhÉhåÿÜp[ÿÜq[ÿÜr[ÿÜs[ÿÜxxxx©xªx´ÿkxµÿxÅÿ¤y&yÿÜyy[ÿÁy©yªy´ÿkyµÿ·yÅÿ}z&zÿÜzz[ÿÁz©zªz´ÿkzµÿ·zÅÿ}{&{ÿÜ{{[ÿÁ{©{ª{´ÿk{µÿ·{Åÿ}|&|ÿÜ||[ÿÁ|©|ª|´ÿk|µÿ·|Åÿ}}&}ÿÜ}}[ÿÁ}©}ª}´ÿk}µÿ·}Åÿ}‰&‰©‰ª‰´ÿ‰µÿ‰Åÿ­©ª´ÿ­µÿ¤Åÿ©$©%ÿÜ©&ÿÜ©'ÿÜ©)©*ÿÜ©+©-ÿÜ©.©/©2©3©4©5©7ÿ©9ÿ©:ÿÜ©;©<ÿk©=©I©Q©R©U©YÿÜ©ZÿÜ©\ÿÜ©b©dÿÜ©g©x©y©z©{©|©}©‰©—©­©®©¯©ºÿÜ©»ÿk©Ç©É©Ð©Ñ©Ò©å©é©êÿk©ëÿÜ©ì©öÿÜ©ûÿÜ©ýÿܪ$ÿ·ª%ÿ·ª&ÿܪ'ÿܪ)ª*ª+ª-ÿܪ.ª/ª2ÿܪ3ª4ª5ª7ÿDª9ÿNª:ÿª;ÿª<ÿª=ªIªQªRªUªYÿܪZÿܪ\ÿܪbÿ·ªdÿܪgÿܪxªyªzª{ª|ª}ª‰ªª­ÿ·ª®ÿ·ª¯ÿܪºÿܪ»ÿªÇÿ·ªÉÿ·ªÐÿܪÑÿܪÒÿܪåªéªêÿªëÿܪìªöªûÿܪýÿÜ­ÿÓ­ÿÜ­ÿÜ­$9­&ÿÜ­*ÿÜ­2ÿÜ­4ÿÜ­6­7ÿa­8­9ÿ}­:ÿ­;­<ÿa­FÿÜ­GÿÜ­HÿÜ­Iÿ·­RÿÜ­TÿÜ­WÿÜ­X­Yÿˆ­Zÿ­­\ÿu­b9­dÿÜ­gÿÜ­h­oÿÜ­pÿÜ­qÿÜ­rÿÜ­sÿÜ­yÿÜ­zÿÜ­{ÿÜ­|ÿÜ­}ÿÜ­~­­€­­©ÿ·­ª­­9­®9­¯ÿÜ­´þø­µÿ­ºÿu­»ÿa­Å/­Ç9­É9­ÐÿÜ­ÑÿÜ­ÒÿÜ­Ó­Ô­Õ­ã­êÿa­ëÿu­öÿÜ­ù­ûÿÜ­üÿÜ­ýÿÜ­þÿÜ®ÿÓ®ÿÜ®ÿÜ®$9®&ÿÜ®*ÿÜ®2ÿÜ®4ÿÜ®6®7ÿa®8®9ÿ}®:ÿ®;®<ÿa®FÿÜ®GÿÜ®HÿÜ®Iÿ·®RÿÜ®TÿÜ®WÿÜ®X®Yÿˆ®Zÿ­®\ÿu®b9®dÿÜ®gÿÜ®h®oÿÜ®pÿÜ®qÿÜ®rÿÜ®sÿÜ®yÿÜ®zÿÜ®{ÿÜ®|ÿÜ®}ÿÜ®~®®€®®©ÿ·®ª®­9®®9®¯ÿÜ®´þø®µÿ®ºÿu®»ÿa®Å/®Ç9®É9®ÐÿÜ®ÑÿÜ®ÒÿܮӮԮծã®êÿa®ëÿu®öÿÜ®ù®ûÿÜ®üÿÜ®ýÿÜ®þÿܯ9¯ÿ­¯ÿܯ$ÿܯ9ÿܯ;ÿ}¯<ÿ¯bÿܯ©ÿܯª¯­ÿܯ®ÿܯ´ÿÓ¯µÿܯ»ÿ¯ÅÿD¯ÇÿܯÉÿܯêÿ´$þø´%ÿÁ´&ÿ·´'ÿÁ´)ÿÁ´*ÿ·´+ÿÁ´-ÿÁ´.ÿÁ´/ÿÁ´2ÿ·´3ÿÁ´4ÿ·´5ÿÁ´7´9´:´;ÿˆ´<´=ÿÜ´Iÿ·´Qÿ´Rÿk´Uÿ´Yÿ·´Zÿ·´\ÿ·´bþø´dÿ·´gÿ·´xÿ´yÿk´zÿk´{ÿk´|ÿk´}ÿk´‰ÿÁ´þ}´­þø´®þø´¯ÿ·´ºÿ·´»´Çþø´Éþø´Ðÿ·´Ñÿ·´Òÿ·´åÿÜ´éÿ·´ê´ëÿ·´ìÿÁ´öÿ·´ûÿ·´ýÿ·ºÿܺþܺÿkº©ÿܺªÿܺ´ºµºÅþÓ»ÿ »þa»þð»$ÿa»&ÿ»2ÿ»Dþæ»Hþð»Lÿ·»Rþð»Xÿ»bÿa»dÿ»gÿ»iþæ»jþæ»kþæ»lþæ»mþæ»nþæ»pþð»qþð»rþð»sþð»yþð»zþð»{þð»|þð»}þð»~ÿ»ÿ»€ÿ»ÿ»©ÿ»ªÿk»­ÿa»®ÿa»¯ÿ»´ÿ»µÿÜ»Åþø»Çÿa»Éÿa»Ðÿ»Ñÿ»Òÿ»ûÿ»ýÿÅ$&Å%ÿ·Å&ÿÅ'ÿ·Å)ÿ·Å*ÿ·Å+ÿ·Å-/Å.ÿ·Å/ÿ·Å2ÿÅ3ÿ·Å4ÿÅ5ÿ·Å7þæÅ9þˆÅ:ÿÅ;ÿ·Å<þˆÅ=ÅIÿÜÅQÿ·ÅRÿ·ÅUÿ·ÅYÿÅZÿ<Å\ÿÅb&ÅdÿÅgÿÅxÿ·Åyÿ·Åzÿ·Å{ÿ·Å|ÿ·Å}ÿ·Å‰ÿ·Å&Å­&Å®&ůÿźÿÅ»þˆÅÇ&ÅÉ&ÅÐÿÅÑÿÅÒÿÅåÅéÿ·ÅêþˆÅëÿÅìÿ·Åöÿ·ÅûÿÅýÿÇÿÓÇÿÜÇÿÜÇ$9Ç&ÿÜÇ*ÿÜÇ2ÿÜÇ4ÿÜÇ6Ç7ÿaÇ8Ç9ÿ}Ç:ÿÇ;Ç<ÿaÇFÿÜÇGÿÜÇHÿÜÇIÿ·ÇRÿÜÇTÿÜÇWÿÜÇXÇYÿˆÇZÿ­Ç\ÿuÇb9ÇdÿÜÇgÿÜÇhÇoÿÜÇpÿÜÇqÿÜÇrÿÜÇsÿÜÇyÿÜÇzÿÜÇ{ÿÜÇ|ÿÜÇ}ÿÜÇ~ÇÇ€ÇÇ©ÿ·ÇªÇ­9Ç®9ǯÿÜÇ´þøÇµÿǺÿuÇ»ÿaÇÅ/ÇÇ9ÇÉ9ÇÐÿÜÇÑÿÜÇÒÿÜÇÓÇÔÇÕÇãÇêÿaÇëÿuÇöÿÜÇùÇûÿÜÇüÿÜÇýÿÜÇþÿÜÉÿÓÉÿÜÉÿÜÉ$9É&ÿÜÉ*ÿÜÉ2ÿÜÉ4ÿÜÉ6É7ÿaÉ8É9ÿ}É:ÿÉ;É<ÿaÉFÿÜÉGÿÜÉHÿÜÉIÿ·ÉRÿÜÉTÿÜÉWÿÜÉXÉYÿˆÉZÿ­É\ÿuÉb9ÉdÿÜÉgÿÜÉhÉoÿÜÉpÿÜÉqÿÜÉrÿÜÉsÿÜÉyÿÜÉzÿÜÉ{ÿÜÉ|ÿÜÉ}ÿÜÉ~ÉÉ€ÉÉ©ÿ·ÉªÉ­9É®9ɯÿÜÉ´þøÉµÿɺÿuÉ»ÿaÉÅ/ÉÇ9ÉÉ9ÉÐÿÜÉÑÿÜÉÒÿÜÉÓÉÔÉÕÉãÉêÿaÉëÿuÉöÿÜÉùÉûÿÜÉüÿÜÉýÿÜÉþÿÜÐ9Ðÿ­ÐÿÜÐ$ÿÜÐ9ÿÜÐ;ÿ}Ð<ÿÐbÿÜЩÿÜЪЭÿÜЮÿÜдÿÓеÿÜлÿÐÅÿDÐÇÿÜÐÉÿÜÐêÿÑ9Ñÿ­ÑÿÜÑ$ÿÜÑ9ÿÜÑ;ÿ}Ñ<ÿÑbÿÜÑ©ÿÜѪѭÿÜÑ®ÿÜÑ´ÿÓѵÿÜÑ»ÿÑÅÿDÑÇÿÜÑÉÿÜÑêÿÒ9Òÿ­ÒÿÜÒ$ÿÜÒ9ÿÜÒ;ÿ}Ò<ÿÒbÿÜÒ©ÿÜÒªÒ­ÿÜÒ®ÿÜÒ´ÿÓÒµÿÜÒ»ÿÒÅÿDÒÇÿÜÒÉÿÜÒêÿÓ$Ó-Ó=ÿÜÓbÓ­Ó®ÓÇÓÉÓåÿÜÔ$Ô-Ô=ÿÜÔbÔ­Ô®ÔÇÔÉÔåÿÜÕ$Õ-Õ=ÿÜÕbÕ­Õ®ÕÇÕÉÕåÿÜã$&ã&ã*ã2ã4ã6ãb&ãdãgã­&ã®&ã¯ãÇ&ãÉ&ãÐãÑãÒãããöãùãûãýåÿÜå©åªå´ÿÜåµÿÜåÅÿÜéé©éªé´ÿ¤éµÿéÅÿ·êÿ êþaêþðê$ÿaê&ÿê2ÿêDþæêHþðêLÿ·êRþðêXÿêbÿaêdÿêgÿêiþæêjþæêkþæêlþæêmþæênþæêpþðêqþðêrþðêsþðêyþðêzþðê{þðê|þðê}þðê~ÿêÿê€ÿêÿê©ÿêªÿkê­ÿaê®ÿaê¯ÿê´ÿêµÿÜêÅþøêÇÿaêÉÿaêÐÿêÑÿêÒÿêûÿêýÿëÿÜëþÜëÿkë©ÿÜëªÿÜë´ëµëÅþÓììÿkìÿ·ì©ìªì´ÿÜìµìÅÿDöö$ö7ÿ·ö:ö<ÿšöbö©ÿÜöªÿÜö­ö®ö´ÿÓöµÿÓö»ÿšöÅÿÉöÇöÉöêÿšù$&ù&ù*ù2ù4ù6ùb&ùdùgù­&ù®&ù¯ùÇ&ùÉ&ùÐùÑùÒùãùöùùùûùýûû$û6û<ÿÜûbû©ÿÜûªÿÜû­û®û´ûµ&û»ÿÜûÅûÇûÉûãûêÿÜûùýý$ý6ý<ÿÜýbý©ÿÜýªÿÜý­ý®ý´ýµ&ý»ÿÜýÅýÇýÉýãýêÿÜýù MB@hmþ ¼þ‰þ‰ L GÌþBGÌSf €¯ JBits@ ûþšmãB±‹`#cÕVeraSansÿÿÿÿ6ÿÿþ628R00@                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "                      "       #                       #     $               $    &              &    ÿÿ P ì_<õº¹ð¸ºÂg‘þ‰þ Lmpybox2d-2.3.2/examples/data/themes/gray/box.down.png000066400000000000000000000003411276457661000223430ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  1)2#ôTtEXtCommentCreated with The GIMPïd%nEIDAT8ËíÓ¡€0Ñ_^‡C"(!l‡kk=§’‚Û’tÉIÞìÛÚ$çƒÌÀ ü#P¿Ûn¥ŒÞùÃ^ 77i$IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/box.normal.png000066400000000000000000000003461276457661000226710ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  0à©ötEXtCommentCreated with The GIMPïd%nJIDAT8Ëcd``øÏ@`b```øÿÿ?ÉØÁÁfÒÕ‹'‰¶u͆¨. Ø £Œ@©,Ø’'É8::’íFJ³3Å1ó]IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/button.down.png000066400000000000000000000002771276457661000230760ustar00rootroot00000000000000‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  6OºpLIDATHÇíÖ¡À0 Á“GŸ /ÈÀÐÝ% ,Ø"ž¿~¡ÀCa ©d\ÒôûÚ:>æ Qœ 0pÿº»¨~[^¼Ë G¸k'IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/button.normal.png000066400000000000000000000003071276457661000234110ustar00rootroot00000000000000‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  4.Ñ0•²TIDATHÇíÖ!€@ DÑ¿dÖÞä Hç) ± ²ã¦IõëÔ´(„µTU{Gó“žûj›z?Î5|E 0`À€˜g®ÈLY‚¡~[^ ÅIÓ3IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/checkbox.off.down.png000066400000000000000000000002451276457661000241150ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ :Ž~ÜJDIDAT8Ëí“! ¿7‰Dð ý¬ 0N6饦ÉÝÅ!fFˆˆíro` Ö`—Ì%_ð N$éfÁLÇ_¨`WãIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/checkbox.off.normal.png000066400000000000000000000002621276457661000244350ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ  :C4ºQIDAT8ËíÓ¡À0@ÑŸ^öYY‘}ÀVVt"z€ÄTä{Þ! ¨j0™ˆPÜ==Ü®àÌ,¼Ï ÀÁbØÀ?€:cÜv¶±²A‰´ÐÂAÉIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/checkbox.on.down.png000066400000000000000000000003251276457661000237560ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ :$"Â% tIDAT8ËclhhøÏ@&¨¯¯g`a```8pàÉš§Lè````€€,@*`b Ð× ò À¦§èŠqiÆë˜&dÍW.œ Í „4ã4]1.Íx]Ó„O3A/ÒL½„Dn>`````üÿÿÿJ\Ô¼$_óƒÙIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/checkbox.on.normal.png000066400000000000000000000003301276457661000242730ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ  8â{MfwIDAT8˽“1 €0 E_¤÷nGGïÓ®Žž'Rb[£âŸó?HAyï= ¥d†çi81F“`[^æ_ˆ<\ÁUA9\ƒ› 2t†UÕ¶B® ÊáÜl¡Ü]¡rH.?F¾mkDïôld f)Ð1…¶IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/config.txt000066400000000000000000000142551276457661000221160ustar00rootroot00000000000000desktop background desktop.png input font Vera.ttf 16 input background input.normal.png input color #000000 input:focus background input.focus.png input padding_left 6 input padding_right 6 input padding_top 3 input padding_bottom 3 label font Vera.ttf 16 label color #000000 document font Vera.ttf 16 document color #000000 div font Vera.ttf 16 div color #000000 td font Vera.ttf 16 td color #000000 th font Vera.ttf 16 th color #000000 h1 font Vera.ttf 24 h1 color #000000 h2 font Vera.ttf 20 h2 color #000000 h3 font Vera.ttf 16 h3 color #000000 h4 font Vera.ttf 14 h4 color #000000 h5 font Vera.ttf 12 h5 color #000000 h6 font Vera.ttf 10 h6 color #000000 ul font Vera.ttf 16 ul color #000000 ol font Vera.ttf 16 ol color #000000 li font Vera.ttf 16 li color #000000 li padding_left 32 pre font mono 16 pre color #000000 code font mono 16 code color #000000 checkbox off checkbox.off.normal.png checkbox on checkbox.on.normal.png checkbox:down off checkbox.off.down.png checkbox:down on checkbox.on.down.png switch off checkbox.off.normal.png switch on checkbox.on.normal.png switch:down off checkbox.off.down.png switch:down on checkbox.on.down.png radio off radio.off.normal.png radio on radio.on.normal.png radio:down off radio.off.down.png radio:down on radio.on.down.png button background button.normal.png button:down background button.down.png button padding_left 8 button padding_right 8 button padding_top 1 button padding_bottom 1 button.label font Vera.ttf 16 button.label color #000000 slider background slider.png slider bar slider.bar.normal.png slider:down bar slider.bar.down.png slider width 16 slider height 16 hslider background slider.png hslider bar slider.bar.normal.png hslider:down bar slider.bar.down.png hslider width 16 hslider height 16 vslider background slider.png vslider bar slider.bar.normal.png vslider:down bar slider.bar.down.png vslider width 16 vslider height 16 select.selected background select.selected.normal.png #select.selected:down background select.selected.down.png select.selected padding_left 4 select.selected padding_right 4 select.selected padding_top 1 select.selected padding_bottom 1 select.arrow background select.arrow.normal.png select.arrow:down background select.arrow.down.png select.arrow padding_left 1 select.arrow padding_right 1 select.options background select.options.png select.option background select.option.normal.png #select.option:hover background select.option.hover.png select.option padding_left 4 select.option padding_right 4 select.option padding_top 1 select.option padding_bottom 1 #select.option border_top 1 #select.option border_right 1 #select.option border_bottom 1 #select.option border_left 1 select.option.label font Vera.ttf 16 select.option.label color #000000 select.options padding_left 1 select.options padding_right 1 select.options padding_top 1 select.options padding_bottom 1 select arrow select.arrow.png dialog.bar background dialog.bar.png dialog.bar padding_left 8 dialog.bar padding_right 8 dialog.bar padding_top 2 dialog.bar padding_bottom 1 dialog.bar.close image dialog.close.normal.png dialog.bar.close:down image dialog.close.down.png dialog.main background dialog.png dialog.main padding_left 8 dialog.main padding_right 8 dialog.main padding_top 4 dialog.main padding_bottom 4 keysym font helvetica 16 keysym background input.normal.png keysym color #000000 keysym:focus background input.focus.png keysym padding_left 6 keysym padding_right 6 keysym padding_top 3 keysym padding_bottom 3 tool background tool.normal.png tool:down background tool.down.png tool padding_left 4 tool padding_right 4 tool padding_top 1 tool padding_bottom 1 tool.label font Vera.ttf 16 tool.label color #000000 menu background menu.normal.png menu:hover background menu.hover.png menu:down background menu.down.png menu padding_left 6 menu padding_right 6 menu padding_top 3 menu padding_bottom 3 menu.label font Vera.ttf 16 menu.label color #000000 menu-open background menu.down.png menu-open:down background menu.down.png menu-open padding_left 6 menu-open padding_right 6 menu-open padding_top 3 menu-open padding_bottom 3 menu.options background select.options.png menu.option background menu.option.normal.png menu.option:hover background menu.option.hover.png #menu.option.label color #FF0000 menu.option padding_left 6 menu.option padding_right 6 menu.option padding_top 1 menu.option padding_bottom 1 menu.option.label font Vera.ttf 16 menu.option.label color #000000 menu.options padding_left 1 menu.options padding_right 1 menu.options padding_top 1 menu.options padding_bottom 1 menu arrow select.arrow.png scrollarea.content background #ffffff scrollarea.content padding_left 1 scrollarea.content padding_right 1 scrollarea.content padding_top 1 scrollarea.content padding_bottom 1 hscrollbar height 15 ##hscrollbar background scroller.slide.h.png hscrollbar background slider.png ##hscrollbar bar scroller.slide.bar.normal.png hscrollbar bar slider.bar.normal.png ##hscrollbar:down bar scroller.slide.bar.down.png vscrollbar width 15 ##vscrollbar background scroller.slide.v.png vscrollbar background slider.png ##vscrollbar bar scroller.slide.bar.normal.png vscrollbar bar slider.bar.normal.png ##vscrollbar:down bar scroller.slide.bar.down.png list.item background list.item.normal.png #list.item:down background list.item.down.png list.item padding_left 4 list.item padding_right 4 list.item padding_top 2 list.item padding_bottom 2 list.item margin_bottom 1 list.item align -1 list.item.label font Vera.ttf 14 list.item.label color #000000 list background list.png list padding_left 1 list padding_right 1 list padding_top 1 list padding_bottom 1 list.content background #eeeeee list.content padding_left 1 list.content padding_right 1 list.content padding_top 1 list.content padding_bottom 1 filedialog.folder image filebrowser.folder.png filedialog.label font Vera.ttf 14 filedialog.label color #000000 filedialog.title.label font Vera.ttf 16 filedialog.title.label color #000000 filedialog.input font Vera.ttf 14 filedialog.input background input.normal.png filedialog.input color #000000 filedialog.input:focus background input.focus.png filedialog.input padding_left 6 filedialog.input padding_right 6 filedialog.input padding_top 3 filedialog.input padding_bottom 3 pybox2d-2.3.2/examples/data/themes/gray/console.input.focus.png000066400000000000000000000003401276457661000245220ustar00rootroot00000000000000‰PNG  IHDRàw=ø§IDATH‰í–AÂ0 ×Eü£¶ûÇ#rír€šD™Tâ•|±”Ç—µD)w¯›_HU¥ìZÆv¶ˆ?à`" ’03â†G!XÏ÷fÆÕwo5n€VH€œsl%´yvŸ¾øEê>z¡€€€$Tµ{¨ê+Dª(ýY›çÑ‘)ïW…»sYÌ—94õtRÚ…¾´ÎU -î^íúqÒz§xaIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/console.input.normal.png000066400000000000000000000003401276457661000246730ustar00rootroot00000000000000‰PNG  IHDRàw=ø§IDATH‰í–1à ^†ü±»û˜µŸrëM[&‰"lK)‰æŠ¸fI’p$"Úá˜Y:ÎÒ^PƒK)=ù Ùˆ^‚ˆP >+ ¹I$ÁÝER.9$åî’„ ˲tÝø53¹»J)ÝkùI|¾àN†`†`þAI0³ËûÀ̶>H©©ÒÓÔÌÛ+³)ýu]1MS—`žgäœß—þ3ëú¶DD³ëé” „)ëIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/console.png000066400000000000000000000003401276457661000222460ustar00rootroot00000000000000‰PNG  IHDRàw=ø§IDATH‰í–1à ^†ü±»û˜µŸrëM[&‰"lK)‰æŠ¸fI’p$"Úá˜Y:ÎÒ^PƒK)=ù Ùˆ^‚ˆP >+ ¹I$ÁÝER.9$åî’„ ˲tÝø53¹»J)ÝkùI|¾àN†`†`þAI0³ËûÀ̶>H©©ÒÓÔÌÛ+³)ýu]1MS—`žgäœß—þ3ëú¶DD³ëé” „)ëIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/desktop.png000066400000000000000000000002031276457661000222530ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ  "³¬û"IDAT8Ëc¼rá5•À¨A£4jШA£‘:kœÆËºÜIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/dialog.bar.png000066400000000000000000000002121276457661000226040ustar00rootroot00000000000000‰PNG  IHDRÓ‹¹q pHYs  šœtIMEÕ R¶I~)IDAT8Ëc` `d``¨–BSš™¨å¢QƒF 5hÔ Qƒp>(azB7IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/dialog.close.down.png000066400000000000000000000004161276457661000241210ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ  8”­­IDAT8Ë¥’1‚@E߮ܠ:(§´1¡ð &`)¥³°ÞcÈZÍÄ Yßíßü—ý³ãD$ò§Bd"²:|jo€6ÖʳQ& ¬ʪY䛀ûíú è°¾KVйpr:`…“«Âb€~¶5“ä/ÌUø…d©î)ßoÙBcŒ[6Ñ郈Ä÷´EÁ±®Ùç9qäÒ÷œ‡ç4Ñu3dù:øÑ ŒÖDÇ3 }òIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/dialog.close.normal.png000066400000000000000000000003311276457661000244360ustar00rootroot00000000000000‰PNG  IHDR&/œŠ pHYs  šœtIMEÕ  7£ë¾xIDAT(Ï¥’1€ E?†ã002–û:8zÝ$ÑóÔÍ4á%ï¥-5ÌÌèLŒ®´ÿ†çeLL&p>Àù€Öz&8í$,ßTÁ[¢Áê$PƒUAi„fl»´“Ï_¨P’Xmö–úð!Yy–=1DÄ#ÜT2^áº5IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/dialog.png000066400000000000000000000002121276457661000220410ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ùŽ‚)IDAT8Ëcd``¸ráe@ÇÀ‚‰J`Ô QƒF 5hÔ hÕþŠ.7ƒKIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/filebrowser.folder.png000066400000000000000000000011721276457661000244050ustar00rootroot00000000000000‰PNG  IHDR/Ä<ðAIDAT8­ÔMKTQÀñÿÔ” M3ˆƒ‹Ç[HM‚/©Ì,Ú"—ÑÊe´ û~‚hш¢¸pÛÜ)ÂÊD-,˲73|IÆÇ;sï9çi¡CZ£nzàð8çüx8o>ᆿұm[²Ù,¶m³ð~ßÑì§ã•1*c¹\ŽL&C<÷U}"B:–Çc÷H´’èl¥ùtÙWŸ¸4x—Þö(½íQ.^h¦+ÖDvbžö###ûƒÃÃÃÒ×ÙF_ÓO”2h­PJã¹ ÏS(Oá)ç)Ê®¢ÿæCüÇëH¥RX–µöƒAž<Ÿ%<†ëþ”= ùÊÔG œŠ2a_aîÍ ²33X–õïÆãql;C¡ä'¿þ §èPÜ,s"%ÐØBk[=õ଀³ ’ãÑä$ÁpLJµ צ¹£{(.‚³ ²„¬-b Æ2ão¹uçzu0™LúÉçòœéì'Tz¬|#ˆŒÖh£·³V­™žûVYW½B§¸ÅÉZ…·áb´Æh…6JVZs¤&XíwƒBm Ï-SÚÌcŒBë]UíÀZkÖsE"‘Èa 44ÅØZ™§TÌï©ÊSŠrÙÅqÊÌ.¬2öì#‘H÷á`aí;u…|npy9ûƒw_Ö˜þ°Ì×5Ž®7ªz±D„øù˜8ùE¹wûª ^>+çZ …IJ,I¥R255%•¹5_åsH§Ó2::J("‘HL&÷}¯Åo{T{.wTºIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/input.focus.png000066400000000000000000000002651276457661000230670ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ(%¹tEXtCommentCreated with The GIMPïd%n+IDAT8Ëc` `d``øÿÿ?¥¦022QËE£4jШA£ ƒ¨;…,;)k“IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/input.normal.png000066400000000000000000000003201276457661000232300ustar00rootroot00000000000000‰PNG  IHDRoª¯bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ +–ðrctEXtCommentCreated with The GIMPïd%n4IDAT8Ëclhh` `a``HHH Ð” 01P Œ4jШA£4t bÔ”J”‘¡Å-IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/list.item.normal.png000066400000000000000000000002541276457661000240070ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/list.png000066400000000000000000000002011276457661000215530ustar00rootroot00000000000000‰PNG  IHDR„ž„HIDAT8íÔ± @!EÑ‹‹Á*LÆ*lƯLŒ•ÄîÇ[¿S‚TfV4ËLU-€ˆ8†îÀèÂu?Zjëá‡ç‰6÷ró >8‘Øîê¼IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/menu.down.png000066400000000000000000000002251276457661000225200ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ;3¼‡í>4IDAT8Ëclhh` Ô×׳000„xPn•À¨A£4jШACÇ ÆÿÿÿSÅ ›¾9CKIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/menu.hover.png000066400000000000000000000002261276457661000226750ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ wSµ5IDAT8Ëcüÿÿ?Å ±±‘…áêÅ“”›ÅÄ@%0jШA£4jÐÐ1ˆ¥±±‘*kq¦Js«IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/menu.normal.png000066400000000000000000000001701276457661000230400ustar00rootroot00000000000000‰PNG  IHDR Ù˰ pHYs  šœtIMEÕ ô€‘rIDATÓc¼rá!ÀÄ@UDoEEL„JRåöIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/menu.option.hover.png000066400000000000000000000002231276457661000242010ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ cRHú2IDAT8ËcäRÉb `a``8µ&ŽBSÌB11P Œ4jШA£4t b¤VuBua4Î ¥IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/menu.option.normal.png000066400000000000000000000002031276457661000243440ustar00rootroot00000000000000‰PNG  IHDRoª¯ pHYs  šœtIMEÕ $¢3UQ"IDAT8Ëc¼rá5•À¨A£4jШA£‘:kœÆËºÜIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/radio.off.down.png000066400000000000000000000003401276457661000234210ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ 9¡Þó;IDAT8ËcdÀþãgDcĦñÀØô38880üÿÿŸ¡±±‘À†††ÿ0S&t`5 § ‚ÁÞÞn#²f\±5v0444021PɱÙ»`Ô€Á˜`™ÄÁÁdÛqf¦œÑs%#¥Ù‰¾En.P–«IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/radio.off.normal.png000066400000000000000000000003561276457661000237510ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ 9ØKŸIDAT8Ëí“¡Ã0C}Sÿf`p0—?»üÏÀàXò?Š´¶×jRÈÀŒ¢“l? ™î²½‰g,¥x~¨*H"¥$»3ã0æœÝ€# „° ™QUù­z«´LjèGØž®·ûxršàð ÿ`EÑ[eoõ´ù³–ÍÒxVòx¾v«”Ù9¿ëÛ¹N pœIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/radio.on.down.png000066400000000000000000000003701276457661000232660ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ 8/ƒ«â²—IDAT8ËcdÀþãgDcĦñÀØô38880üÿÿŸ¡±±‘À†††ÿ0S&t`5 § ‚ÁÞÞn#²f\±5v0444021PqÙ®c`¿ráVW`uºf\b {a€-À°‰ ŽtÀË$$ÛŽ33…xàÔˆž+)ÍάNnNÌ)^IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/radio.on.normal.png000066400000000000000000000003721276457661000236110ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs  šœtIMEÕ 7:iî–™IDAT8ËÍS;à ó«r›;7{ܧCÇn022pw¢ „ Jé7Zò §ªÜÁ¥ÇdDŒ1Žø°Ö‚$¼÷²PUVba(àœc¨*­µüõJN¬i/8xKÞÇiû"¿½^o÷0IDATHÇíÏ¡ ÄÀß2$‚}Êàªêš\¦ €¯æs>]D (P à¤ [™TYOÍthIEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/tool.down.png000066400000000000000000000002501276457661000225270ustar00rootroot00000000000000‰PNG  IHDRàw=ø pHYs  šœtIMEÕ  .5êºÌ²GIDATHÇíÕ¡ ÁƒIqH¥óG`(€æOFd'* EI"2óùò5ÀîÁë:Å0`À€Uÿ $•^°Ws s®9IEND®B`‚pybox2d-2.3.2/examples/data/themes/gray/tool.normal.png000066400000000000000000000002501276457661000230500ustar00rootroot00000000000000‰PNG  IHDRàw=ø pHYs  šœtIMEÕ  +#c¦GIDATHÇíÖ¡ Á Cÿ• ´€DPÏc‘âþ ÈNT’DRAØk~Þú œ 0`à©zè”ÏP汎 È"IpIEND®B`‚pybox2d-2.3.2/examples/data/themes/tools/000077500000000000000000000000001276457661000202775ustar00rootroot00000000000000pybox2d-2.3.2/examples/data/themes/tools/config.txt000066400000000000000000000004651276457661000223120ustar00rootroot00000000000000tool.draw image icons48.draw.tga tool.pixel image icons48.pixel.tga tool.line image icons48.line.tga tool.fill image icons48.fill.tga tool.select image icons48.select.tga tool.eraser image icons48.eraser.tga tool.tile image icons48.tile.tga tool.code image icons48.code.tga tool.bkgr image icons48.bkgr.tga pybox2d-2.3.2/examples/data/themes/tools/icons48.bkgr.tga000066400000000000000000000030731276457661000232120ustar00rootroot00000000000000 00 (¯¯¯¯¯¯¯¯¯¯¯–…ÿ’”ÿªÿ‚UÿUÿÿ‘“ÿªÿ„UÿUÿÿ“ÿªÿ†UÿUÿÿ„ÿŠ’ÿ‚ªÿ†UÿUÿ‚ÿªÿUÿUÿÿ‰’ÿªÿ‡UÿUÿÿªÿ‚UÿUÿÿˆ’ÿªÿˆUÿUÿÿªÿ„UÿUÿÿˆ‘ÿ‚ªÿˆUÿUÿÿ„UÿUÿÿ‡‘ÿ‚ªÿ‰UÿUÿÿ…UÿUÿÿ‡‘ÿ‚ªÿ‰UÿUÿÿ…UÿUÿÿ‡Œ…ÿ‚ªÿ‰UÿUÿÿ…UÿUÿÿ‡Š‚ÿªÿUÿUÿÿ‚ªÿ‰UÿUÿÿ…UÿUÿÿ‡Šÿ‚ªÿ‚UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ„UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ„UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ…UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ…UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ…UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡†£ÿ„¯¯¯ÿ†ÿˆÿ†ÿˆÿ†ÿˆÿ‚ÿ‡ÿÿ‚ÿ‰†ÿˆÿÿ†„ÿ‚ƒÿ††ÿˆÿÿ†ÿ‚ÿ‚ÿˆ†…ÿƒÿÿ†ÿƒÿ‚ÿ‰‡ÿƒÿ‚ƒÿ†ÿƒÿ‚ÿ‰‡ÿƒÿ‚ÿÿ„ÿƒÿ‚ÿ‰‡ÿƒÿ‚ÿ‚‚ÿƒÿ‚ÿ‚ÿ‰‡ÿƒÿ‚ÿ…ÿ„ÿÿÿ‰‡ÿ‚ÿ‚ÿˆÿ„ÿ‚ÿ‰‡„ÿ†ÿ¯¯pybox2d-2.3.2/examples/data/themes/tools/icons48.code.tga000066400000000000000000000025201276457661000231730ustar00rootroot00000000000000 00 (¯¯¯¯†ÿ§†ÿ§†ÿ™‚ÿІÿœÿ‰†ÿœÿ‰†ÿ›ÿ‰†ÿšƒÿˆ†ÿ‚ÿŠÿˆ†ÿŽÿÿ‰ÿˆšÿ‰ÿˆšÿ…ƒÿ‰šÿ“™ÿ“˜ÿ”ÿˆ†ÿŒ‚ÿŸ‹ÿ‚ÿžŠÿÿÿŠÿÿ“ÿŠÿ”‚ÿˆÿ–ÿ‡ÿŽŠÿ†ÿ–ÿ‡ÿ•ÿˆ£ÿ‰¯¯ÿÿÿÿÿ†„ÿ‚„ÿƒ„ÿÿ‚„ÿˆ…ÿ‚ÿÿ‚ÿÿ‚‚ÿÿ‚ÿ‡…ÿ†ÿ„ÿÿ„ÿÿ„ÿ‡…ÿ†ÿ…ÿÿ…ÿÿ„ÿ‡…ÿ†ÿ…ÿÿ„ÿ†ÿ‡…ÿ†ÿ…ÿÿ„ÿÿ…ÿ†ÿ…ÿÿƒÿÿŒ…ÿ†‚ÿ‚ÿƒ‚ÿÿ‚ÿƒÿ†……ÿƒ„ÿ†ƒÿƒ„ÿ†ˆÿ“ÿ¯¯pybox2d-2.3.2/examples/data/themes/tools/icons48.draw.tga000066400000000000000000000026431276457661000232240ustar00rootroot00000000000000 00 (¯¯¯¯œ¹¿ÿÿ›ÿÿÿÿ¹¿ÿÿ›ÿÿÿÿªªªÿ¹¿ÿÿš‘Ùÿÿªªªÿš‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ“˜‘Ùÿÿe­ôÿ“—‘Ùÿÿe­ôÿ”—‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ–•‘Ùÿÿe­ôÿ–”‘Ùÿÿe­ôÿ—Œ„ÿ‚‘Ùÿÿe­ôÿ˜‹ÿƒÿ‘Ùÿÿe­ôÿ˜Šÿ„ÿ‘Ùÿÿe­ôÿ™Šÿ†ÿe­ôÿ™Šÿ†ÿe­ôÿ‡ˆÿ‰Šÿ‹„ÿ†ÿˆ‹ÿ‡‚ÿŒÿˆ‡ÿÿ‡¦ÿ‡¦ÿ‡¦ÿ‡¦ÿ‡•„ÿŠÿ‡“‚ÿ‚ÿˆÿˆ’ÿ†ÿ…ÿ‰†ÿ‰ÿˆ‡ÿІÿ§†ÿ§†ÿ£ÿ‚‡ÿÿ’ÿ‚‡ÿƒƒÿƒƒÿƒÿ„ÿ„ÿƒ‡ÿƒÿ…ÿÿ„ÿ‚‚ÿƒÿƒƒ„ÿ‚ÿ…ÿ‚‚ÿ„ÿ‚ÿÿ‚ÿ„ƒÿÿ‚ÿ…ÿ‚ÿÿ„ÿÿÿÿ„‚ÿ‚ÿ‚ÿ…ÿ‚ÿÿ„ÿÿƒÿÿ„‚ÿ‚ÿ‚ÿ…ÿ‚ÿÿƒ‚ÿƒ‚ÿ…‚„ÿƒÿ†ƒÿˆÿ…ÿ…¯¯¯pybox2d-2.3.2/examples/data/themes/tools/icons48.eraser.tga000066400000000000000000000025451276457661000235510ustar00rootroot00000000000000 00 (¯¯¯¯ŸÿŽžÿŽe­ôÿÿŽe­ôÿ‘Ùÿÿœe­ôÿ‘Ùÿÿœe­ôÿ‘Ùÿÿ›e­ôÿ‘Ùÿÿše­ôÿ‘Ùÿÿ‘še­ôÿ‘Ùÿÿ’™e­ôÿ‘Ùÿÿ’™e­ôÿ‘Ùÿÿ“˜e­ôÿ‘Ùÿÿ“—e­ôÿ‘Ùÿÿ”—e­ôÿ‘Ùÿÿ•–e­ôÿ‘Ùÿÿ•–e­ôÿ‘Ùÿÿ–”ªªªÿ‘Ùÿÿ–Œ…ÿ¹¿ÿÿªªªÿÿÿÿÿ—‰ˆÿ¹¿ÿÿÿÿÿÿ—„Œÿ‚¹¿ÿÿÿ”ƒŒÿ†ƒÿ“‚Œÿ†…ÿ’‚‹ÿ†‡ÿ†…ÿ„‚Šÿ†˜ÿ‹ÿ…™ÿŠÿ…›ÿ€‰ÿ…œÿ€‚‡ÿ…ÿ€žÿ€ŽŸÿ€ŸÿŽŠÿ„ÿ‚†ÿ‰ˆÿ…¯‚…ÿƒÿ¡ÿƒÿ‚ÿ„ƒÿ†…ÿ‚…ÿ‚ÿ…ÿ‚‚ÿÿÿ„ÿƒÿ‚ÿƒÿÿ…ÿÿƒÿƒÿ„ÿ‡ÿ„ÿˆÿÿ‚ÿƒÿ„‚ÿ…‡ÿÿ‰ÿ‚ÿ„ÿ‡ƒÿÿˆÿ‰ÿ‚ÿƒÿŠÿÿˆ‚ÿ‡ÿ‚‚ÿ‚ÿƒÿ„ÿÿ„ÿ„ƒÿ‰‚ÿ‚ÿ…ÿƒ†ÿ¯pybox2d-2.3.2/examples/data/themes/tools/icons48.fill.tga000066400000000000000000000023051276457661000232100ustar00rootroot00000000000000 00 (¯¯¯¯œ‚ªªªÿšªªªÿUUUÿªªªÿÿÿÿÿªªªÿ™ªªªÿ‚UUUÿªªªÿ‚ÿÿÿÿªªªÿ‹™ªªªÿ‚UUUÿªªªÿ„ÿÿÿÿªªªÿ‰˜ªªªÿƒUUUÿªªªÿ…ÿÿÿÿªªªÿ‡˜ªªªÿƒUUUÿƒªªªÿ…ÿÿÿÿªªªÿ…—ªªªÿƒUUUÿ†ªªªÿ„ÿÿÿÿªªªÿ…—ªªªÿ‚UUUÿ‰ªªªÿƒÿÿÿÿªªªÿ„—ªªªÿ‚UUUÿ‹ªªªÿÿÿÿÿªªªÿ„–ªªªÿUUUÿÿªªªÿ„–ªªªÿÿªªªÿ„–‚ÿªªªÿ‚UUUÿŠªªªÿ…–ÿ‚ªªªÿ„UUUÿˆªªªÿ…•‚ÿ‚‚ªªªÿƒUUUÿ…ªªªÿ†•‚ÿ…‚ªªªÿ‚UUUÿªªªÿˆ•ƒÿ‡ƒªªªÿ‰‹ÿ•†•ÿ’…™ÿ„šÿ„…ÿ„„¦ÿƒ„§ÿ‚„§ÿ‚„§ÿ‚…¦ÿ‚‘šÿ‚’‰ÿ„‰ÿƒ£…ÿ…¯¯ƒ…ÿˆÿ†ÿ“ƒÿÿ†ÿ“ƒÿÿ†ÿ“ƒÿˆÿƒÿ†ÿ“ƒÿÿ†ÿ“ƒÿˆÿƒÿ†ÿ“ƒÿˆÿƒÿ†ÿ“‚„ÿ…ÿƒÿ†ÿ“ƒÿˆÿƒÿ†ÿ“ƒÿˆÿƒÿ†ÿ“ƒÿÿ†ÿ’’ÿš¯¯pybox2d-2.3.2/examples/data/themes/tools/icons48.line.tga000066400000000000000000000021651276457661000232150ustar00rootroot00000000000000 00 (¯¯¯¯œ¹¿ÿÿ›ÿÿÿÿ¹¿ÿÿ›ÿÿÿÿªªªÿ¹¿ÿÿš‘Ùÿÿªªªÿš‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ“˜‘Ùÿÿe­ôÿ“—‘Ùÿÿe­ôÿ”—‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ–•‘Ùÿÿe­ôÿ–”‘Ùÿÿe­ôÿ—”‘Ùÿÿe­ôÿ˜“‘Ùÿÿe­ôÿ˜“‘Ùÿÿe­ôÿ™’ÿe­ôÿ™’ÿš’ÿ›‘‚ÿš”‚ÿ——‚ÿ”šÿ’œ‚ÿŸ‚ÿŒ¢ÿФ‚ÿ‡§‚ÿ„„ÿ¤ÿ‚„ÿ†ÿ¡„ÿ™ƒÿ‹„ÿÿ„ÿƒÿ‚ÿ‰„ÿ†ÿ…‚ÿ‚ÿ‚ÿ„ÿˆ„ÿ†ÿ…ÿ…ÿ‚ÿ…ÿˆ„ÿ†ÿ…ÿ…ÿ‚ÿ…ÿ‡„ÿ†ÿ…ÿ…ÿ‚ˆÿ‡„ÿ†ÿ…ÿ…ÿ‚ÿ„ÿ†ÿ…ÿ…ÿ‚ÿŽ„ÿ†ÿ…ÿ…ÿƒ‡ÿ‡„ÿ“ÿ“¯¯¯pybox2d-2.3.2/examples/data/themes/tools/icons48.pixel.tga000066400000000000000000000022721276457661000234060ustar00rootroot00000000000000 00 (¯¯¯¯œ¹¿ÿÿ›ÿÿÿÿ¹¿ÿÿ›ÿÿÿÿªªªÿ¹¿ÿÿš‘Ùÿÿªªªÿš‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ“˜‘Ùÿÿe­ôÿ“—‘Ùÿÿe­ôÿ”—‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ–•‘Ùÿÿe­ôÿ–”‘Ùÿÿe­ôÿ—ÿƒ‘Ùÿÿe­ôÿ˜“‘Ùÿÿe­ôÿ˜‹ÿ†‘Ùÿÿe­ôÿ™“ÿe­ôÿ™’ÿ‡ÿ‚ÿ“ÿƒÿŠÿ‰¯ÿ“ÿ‡¯¯¯¯¯¤ÿ‰¤ÿ‰¤ÿ‰ÿ•ÿ‰—ÿƒ‚ÿ„ÿ‰†ƒÿ†ÿƒÿ‚ÿÿƒÿ‰ƒ‚ÿ‚ÿ‚ÿ‚‚ÿÿƒÿ‚ÿƒÿ‰ƒÿ„ÿ‚ÿ„ƒÿ‚ÿƒÿ‚ÿ‰ƒÿ„ÿ‚ÿ…ÿƒ†ÿ‚ÿ‰ƒÿƒÿ‚ÿ…‚ÿ‚ÿˆÿ‰„ÿ‚ÿƒÿ„ÿÿÿ‡ÿ‰„‚ÿ…ÿƒÿ‚ÿ‚…ÿ‚ÿˆ„ÿ‹ÿÿˆ„ÿ©„ÿ©¯¯pybox2d-2.3.2/examples/data/themes/tools/icons48.select.tga000066400000000000000000000026611276457661000235460ustar00rootroot00000000000000 00 (¯¯¯¯…¡ÿÿÿÿ‡…¡ÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…¡ÿÿÿÿ‡…¡ÿÿÿÿ‡“ÿ”ÿ„“ÿ”ÿ„“ÿ”ÿ„„‚ÿ„ÿ„ÿ’…ÿƒÿÿƒÿÿ‚ÿ…„ÿ‰ÿ„ƒÿ…ÿ‚ÿ‚ÿ…ÿƒÿƒÿ‚ÿ„ƒÿ…ÿƒÿ‚ÿ„ÿƒÿÿ…ÿ„ƒƒÿ‚…ÿ‚ÿ„†ÿÿ…ÿ„†ÿÿ†ÿ„ÿ†ÿ†ÿ„‡ÿ‚ÿ†ÿƒÿ…ÿ†ÿ„‡ÿ‚‚ÿ…ÿ„ÿ„ÿ…ÿƒƒÿÿ„ƒÿ‚ÿ…‚ÿ„ƒÿ‚‚ÿƒƒÿŒ‚ÿ—¯¯pybox2d-2.3.2/examples/data/themes/tools/icons48.tile.tga000066400000000000000000000023641276457661000232240ustar00rootroot00000000000000 00 (¯¯¯¯¯¯…‡ÿÿÿÿ¡…ªªªÿ…ÿÿÿÿªªªÿ¡…ªªªÿƒÿÿÿÿªªªÿ¡…‚ªªªÿÿÿÿÿ‚ªªªÿ¡…‡ªªªÿˆ‡ÿÿÿÿ…‚ªªªÿUUUÿ‚ªªªÿˆªªªÿ…ÿÿÿÿªªªÿ…ªªªÿƒUUUÿªªªÿˆªªªÿƒÿÿÿÿªªªÿ…ªªªÿ…UUUÿªªªÿˆ‚ªªªÿÿÿÿÿ‚ªªªÿ…‡UUUÿˆ‡ªªªÿ–‚ªªªÿUUUÿ‚ªªªÿ–ªªªÿƒUUUÿªªªÿ–ªªªÿ…UUUÿªªªÿ–‡UUUÿ¯‡ÿÿÿÿ—ªªªÿ…ÿÿÿÿªªªÿ—ªªªÿƒÿÿÿÿªªªÿ—‚ªªªÿÿÿÿÿ‚ªªªÿ—‡ªªªÿ—‚ªªªÿUUUÿ‚ªªªÿ…‡ÿÿÿÿ‰ªªªÿƒUUUÿªªªÿ…ªªªÿ…ÿÿÿÿªªªÿ‰ªªªÿ…UUUÿªªªÿ…ªªªÿƒÿÿÿÿªªªÿ‰‡UUUÿ…‚ªªªÿÿÿÿÿ‚ªªªÿ‰‡ªªªÿ‰‚ªªªÿUUUÿ‚ªªªÿ‰ªªªÿƒUUUÿªªªÿ‰ªªªÿ…UUUÿªªªÿ‰‡UUUÿ‰‰ÿÿ’‰ÿÿ’‰ÿ†ÿˆÿ……ÿ†‰ÿÿ…ÿƒÿ†‰ÿÿ…ÿ„ÿ††‡ÿƒÿ†ÿ…ÿ…ÿ…‰ÿ‡ÿ†ÿ…‡ÿ…‰ÿ‡ÿ†ÿ…ÿŒ‰ÿ†ÿ†ÿ„ÿŒŠÿÿ„ÿ†ÿ„‚ÿ‚ÿ†Šƒÿ”„ÿ†¯¯¯pybox2d-2.3.2/examples/distance.py000066400000000000000000000073311276457661000171110ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2Color, b2Distance, b2PolygonShape, b2Transform, b2Vec2, b2_pi) class Distance (Framework): name = "Distance" description = ("Use WASD to move and QE to rotate the small rectangle.\n" "The distance between the marked points is shown.") point_a_color = b2Color(1, 0, 0) point_b_color = b2Color(1, 1, 0) poly_color = b2Color(0.9, 0.9, 0.9) def __init__(self): super(Distance, self).__init__() # Transform A -- a simple translation/offset of (0,-0.2) self.transformA = b2Transform() self.transformA.SetIdentity() self.transformA.position = (0, -0.2) # Transform B -- a translation and a rotation self.transformB = b2Transform() self.positionB = b2Vec2(12.017401, 0.13678508) self.angleB = -0.0109265 self.transformB.Set(self.positionB, self.angleB) # The two shapes, transformed by the respective transform[A,B] self.polygonA = b2PolygonShape(box=(10, 0.2)) self.polygonB = b2PolygonShape(box=(2, 0.1)) def Step(self, settings): super(Distance, self).Step(settings) # Calculate the distance between the two shapes with the specified # transforms dist_result = b2Distance(shapeA=self.polygonA, shapeB=self.polygonB, transformA=self.transformA, transformB=self.transformB) pointA, pointB, distance, iterations = dist_result self.Print('Distance = %g' % distance) self.Print('Iterations = %d' % iterations) # Manually transform the vertices and draw the shapes for shape, transform in [(self.polygonA, self.transformA), (self.polygonB, self.transformB)]: new_verts = [self.renderer.to_screen( transform * v) for v in shape.vertices] self.renderer.DrawPolygon(new_verts, self.poly_color) self.renderer.DrawPoint(self.renderer.to_screen(pointA), 4, self.point_a_color) self.renderer.DrawPoint(self.renderer.to_screen(pointB), 4, self.point_b_color) def Keyboard(self, key): if key == Keys.K_a: self.positionB -= (0.1, 0) elif key == Keys.K_d: self.positionB += (0.1, 0) elif key == Keys.K_w: self.positionB += (0, 0.1) elif key == Keys.K_s: self.positionB -= (0, 0.1) elif key == Keys.K_q: self.angleB += 0.1 * b2_pi elif key == Keys.K_e: self.angleB -= 0.1 * b2_pi self.transformB.Set(self.positionB, self.angleB) if __name__ == "__main__": main(Distance) pybox2d-2.3.2/examples/edge_shapes.py000066400000000000000000000123001276457661000175560ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2BodyDef, b2CircleShape, b2Color, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2RayCastCallback, b2Vec2, b2_dynamicBody, b2_pi) from math import cos, sin, pi, sqrt from random import random VERTEX_COUNT = 80 def get_sinusoid_vertices(x1, vertices): y1 = 2.0 * cos(x1 / 10.0 * pi) for i in range(vertices): x2 = x1 + 0.5 y2 = 2.0 * cos(x2 / 10.0 * pi) yield (x1, y1), (x2, y2) x1, y1 = x2, y2 def get_octagon_vertices(w): b = w / (2.0 + sqrt(2.0)) s = sqrt(2.0) * b return [(0.5 * s, 0), (0.5 * w, b), (0.5 * w, b + s), (0.5 * s, w), (-0.5 * s, w), (-0.5 * w, b + s), (-0.5 * w, b), (-0.5 * s, 0.0), ] # for more information, see raycast.py class RayCastCallback(b2RayCastCallback): def __init__(self, **kwargs): super(RayCastCallback, self).__init__() self.fixture = None def ReportFixture(self, fixture, point, normal, fraction): self.fixture = fixture self.point = b2Vec2(point) self.normal = b2Vec2(normal) return fraction class EdgeShapes (Framework): name = "Edge Shapes" description = "Press 1-5 to drop stuff, and d to delete" p1_color = b2Color(0.4, 0.9, 0.4) s1_color = b2Color(0.8, 0.8, 0.8) s2_color = b2Color(0.9, 0.9, 0.4) def __init__(self): super(EdgeShapes, self).__init__() self.ground = self.world.CreateStaticBody( shapes=[b2EdgeShape(vertices=v) for v in get_sinusoid_vertices(-20.0, VERTEX_COUNT)]) self.shapes = [ b2PolygonShape(vertices=[(-0.5, 0), (0.5, 0), (0, 1.5)]), b2PolygonShape(vertices=[(-0.1, 0), (0.1, 0), (0, 1.5)]), b2PolygonShape(vertices=get_octagon_vertices(1.0)), b2PolygonShape(box=(0.5, 0.5)), b2CircleShape(radius=0.5), ] self.angle = 0 self.callback = RayCastCallback() @property def bodies(self): return [body for body in self.world.bodies if body != self.ground] def CreateShape(self, shapeindex): try: shape = self.shapes[shapeindex] except IndexError: return pos = (10.0 * (2.0 * random() - 1.0), 10.0 * (2.0 * random() + 1.0)) defn = b2BodyDef( type=b2_dynamicBody, fixtures=b2FixtureDef(shape=shape, friction=0.3), position=pos, angle=(b2_pi * (2.0 * random() - 1.0)), ) if isinstance(shape, b2CircleShape): defn.angularDamping = 0.02 self.world.CreateBody(defn) def DestroyBody(self): if not self.world.locked: for body in self.bodies: self.world.DestroyBody(body) break def Keyboard(self, key): if key in (Keys.K_1, Keys.K_2, Keys.K_3, Keys.K_4, Keys.K_5): self.CreateShape(key - Keys.K_1) elif key == Keys.K_d: self.DestroyBody() def Step(self, settings): super(EdgeShapes, self).Step(settings) # Set up the raycast line length = 25.0 point1 = b2Vec2(0, 10) d = (length * cos(self.angle), length * sin(self.angle)) point2 = point1 + d callback = self.callback callback.fixture = None self.world.RayCast(callback, point1, point2) # The callback has been called by this point, and if a fixture was hit it will have been # set to callback.fixture. point1 = self.renderer.to_screen(point1) point2 = self.renderer.to_screen(point2) if callback.fixture: cb_point = self.renderer.to_screen(callback.point) self.renderer.DrawPoint(cb_point, 5.0, self.p1_color) self.renderer.DrawSegment(point1, cb_point, self.s1_color) head = b2Vec2(cb_point) + 0.5 * callback.normal self.renderer.DrawSegment(cb_point, head, self.s2_color) else: self.renderer.DrawSegment(point1, point2, self.s1_color) if not settings.pause or settings.singleStep: self.angle += 0.25 * b2_pi / 180 if __name__ == "__main__": main(EdgeShapes) pybox2d-2.3.2/examples/edge_test.py000066400000000000000000000040421276457661000172560ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2EdgeShape, b2PolygonShape) class EdgeTest (Framework): name = "EdgeTest" description = "Utilizes b2EdgeShape" def __init__(self): super(EdgeTest, self).__init__() v1 = (-10.0, 0.0) v2 = (-7.0, -1.0) v3 = (-4.0, 0.0) v4 = (0.0, 0.0) v5 = (4.0, 0.0) v6 = (7.0, 1.0) v7 = (10.0, 0.0) shapes = [b2EdgeShape(vertices=[None, v1, v2, v3]), b2EdgeShape(vertices=[v1, v2, v3, v4]), b2EdgeShape(vertices=[v2, v3, v4, v5]), b2EdgeShape(vertices=[v3, v4, v5, v6]), b2EdgeShape(vertices=[v4, v5, v6, v7]), b2EdgeShape(vertices=[v5, v6, v7]) ] ground = self.world.CreateStaticBody(shapes=shapes) box = self.world.CreateDynamicBody( position=(0.5, 0.6), allowSleep=False, shapes=b2PolygonShape(box=(0.5, 0.5)) ) if __name__ == "__main__": main(EdgeTest) pybox2d-2.3.2/examples/empty.py000066400000000000000000000052571276457661000164620ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) class Empty(Framework): """You can use this class as an outline for your tests.""" name = "Empty" # Name of the class to display description = "The description text goes here" def __init__(self): """ Initialize all of your objects here. Be sure to call the Framework's initializer first. """ super(Empty, self).__init__() # Initialize all of the objects def Keyboard(self, key): """ The key is from Keys.K_* (e.g., if key == Keys.K_z: ... ) """ pass def Step(self, settings): """Called upon every step. You should always call -> super(Your_Test_Class, self).Step(settings) at the beginning or end of your function. If placed at the beginning, it will cause the actual physics step to happen first. If placed at the end, it will cause the physics step to happen after your code. """ super(Empty, self).Step(settings) # do stuff # Placed after the physics step, it will draw on top of physics objects self.Print("*** Base your own testbeds on me! ***") def ShapeDestroyed(self, shape): """ Callback indicating 'shape' has been destroyed. """ pass def JointDestroyed(self, joint): """ The joint passed in was removed. """ pass # More functions can be changed to allow for contact monitoring and such. # See the other testbed examples for more information. if __name__ == "__main__": main(Empty) pybox2d-2.3.2/examples/framework.py000066400000000000000000000437261276457661000173240ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. """ The framework's base is FrameworkBase. See its help for more information. """ from time import time from Box2D import (b2World, b2AABB, b2CircleShape, b2Color, b2Vec2) from Box2D import (b2ContactListener, b2DestructionListener, b2DrawExtended) from Box2D import (b2Fixture, b2FixtureDef, b2Joint) from Box2D import (b2GetPointStates, b2QueryCallback, b2Random) from Box2D import (b2_addState, b2_dynamicBody, b2_epsilon, b2_persistState) from .settings import fwSettings class fwDestructionListener(b2DestructionListener): """ The destruction listener callback: "SayGoodbye" is called when a joint or shape is deleted. """ def __init__(self, test, **kwargs): super(fwDestructionListener, self).__init__(**kwargs) self.test = test def SayGoodbye(self, obj): if isinstance(obj, b2Joint): if self.test.mouseJoint == obj: self.test.mouseJoint = None else: self.test.JointDestroyed(obj) elif isinstance(obj, b2Fixture): self.test.FixtureDestroyed(obj) class fwQueryCallback(b2QueryCallback): def __init__(self, p): super(fwQueryCallback, self).__init__() self.point = p self.fixture = None def ReportFixture(self, fixture): body = fixture.body if body.type == b2_dynamicBody: inside = fixture.TestPoint(self.point) if inside: self.fixture = fixture # We found the object, so stop the query return False # Continue the query return True class Keys(object): pass class FrameworkBase(b2ContactListener): """ The base of the main testbed framework. If you are planning on using the testbed framework and: * Want to implement your own renderer (other than Pygame, etc.): You should derive your class from this one to implement your own tests. See empty.py or any of the other tests for more information. * Do NOT want to implement your own renderer: You should derive your class from Framework. The renderer chosen in fwSettings (see settings.py) or on the command line will automatically be used for your test. """ name = "None" description = None TEXTLINE_START = 30 colors = { 'mouse_point': b2Color(0, 1, 0), 'bomb_center': b2Color(0, 0, 1.0), 'bomb_line': b2Color(0, 1.0, 1.0), 'joint_line': b2Color(0.8, 0.8, 0.8), 'contact_add': b2Color(0.3, 0.95, 0.3), 'contact_persist': b2Color(0.3, 0.3, 0.95), 'contact_normal': b2Color(0.4, 0.9, 0.4), } def __reset(self): """ Reset all of the variables to their starting values. Not to be called except at initialization.""" # Box2D-related self.points = [] self.world = None self.bomb = None self.mouseJoint = None self.settings = fwSettings self.bombSpawning = False self.bombSpawnPoint = None self.mouseWorld = None self.using_contacts = False self.stepCount = 0 # Box2D-callbacks self.destructionListener = None self.renderer = None def __init__(self): super(FrameworkBase, self).__init__() self.__reset() # Box2D Initialization self.world = b2World(gravity=(0, -10), doSleep=True) self.destructionListener = fwDestructionListener(test=self) self.world.destructionListener = self.destructionListener self.world.contactListener = self self.t_steps, self.t_draws = [], [] def __del__(self): pass def Step(self, settings): """ The main physics step. Takes care of physics drawing (callbacks are executed after the world.Step() ) and drawing additional information. """ self.stepCount += 1 # Don't do anything if the setting's Hz are <= 0 if settings.hz > 0.0: timeStep = 1.0 / settings.hz else: timeStep = 0.0 renderer = self.renderer # If paused, display so if settings.pause: if settings.singleStep: settings.singleStep = False else: timeStep = 0.0 self.Print("****PAUSED****", (200, 0, 0)) # Set the flags based on what the settings show if renderer: # convertVertices is only applicable when using b2DrawExtended. It # indicates that the C code should transform box2d coords to screen # coordinates. is_extended = isinstance(renderer, b2DrawExtended) renderer.flags = dict(drawShapes=settings.drawShapes, drawJoints=settings.drawJoints, drawAABBs=settings.drawAABBs, drawPairs=settings.drawPairs, drawCOMs=settings.drawCOMs, convertVertices=is_extended, ) # Set the other settings that aren't contained in the flags self.world.warmStarting = settings.enableWarmStarting self.world.continuousPhysics = settings.enableContinuous self.world.subStepping = settings.enableSubStepping # Reset the collision points self.points = [] # Tell Box2D to step t_step = time() self.world.Step(timeStep, settings.velocityIterations, settings.positionIterations) self.world.ClearForces() t_step = time() - t_step # Update the debug draw settings so that the vertices will be properly # converted to screen coordinates t_draw = time() if renderer is not None: renderer.StartDraw() self.world.DrawDebugData() # If the bomb is frozen, get rid of it. if self.bomb and not self.bomb.awake: self.world.DestroyBody(self.bomb) self.bomb = None # Take care of additional drawing (fps, mouse joint, slingshot bomb, # contact points) if renderer: # If there's a mouse joint, draw the connection between the object # and the current pointer position. if self.mouseJoint: p1 = renderer.to_screen(self.mouseJoint.anchorB) p2 = renderer.to_screen(self.mouseJoint.target) renderer.DrawPoint(p1, settings.pointSize, self.colors['mouse_point']) renderer.DrawPoint(p2, settings.pointSize, self.colors['mouse_point']) renderer.DrawSegment(p1, p2, self.colors['joint_line']) # Draw the slingshot bomb if self.bombSpawning: renderer.DrawPoint(renderer.to_screen(self.bombSpawnPoint), settings.pointSize, self.colors['bomb_center']) renderer.DrawSegment(renderer.to_screen(self.bombSpawnPoint), renderer.to_screen(self.mouseWorld), self.colors['bomb_line']) # Draw each of the contact points in different colors. if self.settings.drawContactPoints: for point in self.points: if point['state'] == b2_addState: renderer.DrawPoint(renderer.to_screen(point['position']), settings.pointSize, self.colors['contact_add']) elif point['state'] == b2_persistState: renderer.DrawPoint(renderer.to_screen(point['position']), settings.pointSize, self.colors['contact_persist']) if settings.drawContactNormals: for point in self.points: p1 = renderer.to_screen(point['position']) p2 = renderer.axisScale * point['normal'] + p1 renderer.DrawSegment(p1, p2, self.colors['contact_normal']) renderer.EndDraw() t_draw = time() - t_draw t_draw = max(b2_epsilon, t_draw) t_step = max(b2_epsilon, t_step) try: self.t_draws.append(1.0 / t_draw) except: pass else: if len(self.t_draws) > 2: self.t_draws.pop(0) try: self.t_steps.append(1.0 / t_step) except: pass else: if len(self.t_steps) > 2: self.t_steps.pop(0) if settings.drawFPS: self.Print("Combined FPS %d" % self.fps) if settings.drawStats: self.Print("bodies=%d contacts=%d joints=%d proxies=%d" % (self.world.bodyCount, self.world.contactCount, self.world.jointCount, self.world.proxyCount)) self.Print("hz %d vel/pos iterations %d/%d" % (settings.hz, settings.velocityIterations, settings.positionIterations)) if self.t_draws and self.t_steps: self.Print("Potential draw rate: %.2f fps Step rate: %.2f Hz" "" % (sum(self.t_draws) / len(self.t_draws), sum(self.t_steps) / len(self.t_steps)) ) def ShiftMouseDown(self, p): """ Indicates that there was a left click at point p (world coordinates) with the left shift key being held down. """ self.mouseWorld = p if not self.mouseJoint: self.SpawnBomb(p) def MouseDown(self, p): """ Indicates that there was a left click at point p (world coordinates) """ if self.mouseJoint is not None: return # Create a mouse joint on the selected body (assuming it's dynamic) # Make a small box. aabb = b2AABB(lowerBound=p - (0.001, 0.001), upperBound=p + (0.001, 0.001)) # Query the world for overlapping shapes. query = fwQueryCallback(p) self.world.QueryAABB(query, aabb) if query.fixture: body = query.fixture.body # A body was selected, create the mouse joint self.mouseJoint = self.world.CreateMouseJoint( bodyA=self.groundbody, bodyB=body, target=p, maxForce=1000.0 * body.mass) body.awake = True def MouseUp(self, p): """ Left mouse button up. """ if self.mouseJoint: self.world.DestroyJoint(self.mouseJoint) self.mouseJoint = None if self.bombSpawning: self.CompleteBombSpawn(p) def MouseMove(self, p): """ Mouse moved to point p, in world coordinates. """ self.mouseWorld = p if self.mouseJoint: self.mouseJoint.target = p def SpawnBomb(self, worldPt): """ Begins the slingshot bomb by recording the initial position. Once the user drags the mouse and releases it, then CompleteBombSpawn will be called and the actual bomb will be released. """ self.bombSpawnPoint = worldPt.copy() self.bombSpawning = True def CompleteBombSpawn(self, p): """ Create the slingshot bomb based on the two points (from the worldPt passed to SpawnBomb to p passed in here) """ if not self.bombSpawning: return multiplier = 30.0 vel = self.bombSpawnPoint - p vel *= multiplier self.LaunchBomb(self.bombSpawnPoint, vel) self.bombSpawning = False def LaunchBomb(self, position, velocity): """ A bomb is a simple circle which has the specified position and velocity. position and velocity must be b2Vec2's. """ if self.bomb: self.world.DestroyBody(self.bomb) self.bomb = None self.bomb = self.world.CreateDynamicBody( allowSleep=True, position=position, linearVelocity=velocity, fixtures=b2FixtureDef( shape=b2CircleShape(radius=0.3), density=20, restitution=0.1) ) def LaunchRandomBomb(self): """ Create a new bomb and launch it at the testbed. """ p = b2Vec2(b2Random(-15.0, 15.0), 30.0) v = -5.0 * p self.LaunchBomb(p, v) def SimulationLoop(self): """ The main simulation loop. Don't override this, override Step instead. """ # Reset the text line to start the text from the top self.textLine = self.TEXTLINE_START # Draw the name of the test running self.Print(self.name, (127, 127, 255)) if self.description: # Draw the name of the test running for s in self.description.split('\n'): self.Print(s, (127, 255, 127)) # Do the main physics step self.Step(self.settings) def ConvertScreenToWorld(self, x, y): """ Return a b2Vec2 in world coordinates of the passed in screen coordinates x, y NOTE: Renderer subclasses must implement this """ raise NotImplementedError() def DrawStringAt(self, x, y, str, color=(229, 153, 153, 255)): """ Draw some text, str, at screen coordinates (x, y). NOTE: Renderer subclasses must implement this """ raise NotImplementedError() def Print(self, str, color=(229, 153, 153, 255)): """ Draw some text at the top status lines and advance to the next line. NOTE: Renderer subclasses must implement this """ raise NotImplementedError() def PreSolve(self, contact, old_manifold): """ This is a critical function when there are many contacts in the world. It should be optimized as much as possible. """ if not (self.settings.drawContactPoints or self.settings.drawContactNormals or self.using_contacts): return elif len(self.points) > self.settings.maxContactPoints: return manifold = contact.manifold if manifold.pointCount == 0: return state1, state2 = b2GetPointStates(old_manifold, manifold) if not state2: return worldManifold = contact.worldManifold # TODO: find some way to speed all of this up. self.points.extend([dict(fixtureA=contact.fixtureA, fixtureB=contact.fixtureB, position=worldManifold.points[i], normal=worldManifold.normal.copy(), state=state2[i], ) for i, point in enumerate(state2)]) # These can/should be implemented in the test subclass: (Step() also if necessary) # See empty.py for a simple example. def BeginContact(self, contact): pass def EndContact(self, contact): pass def PostSolve(self, contact, impulse): pass def FixtureDestroyed(self, fixture): """ Callback indicating 'fixture' has been destroyed. """ pass def JointDestroyed(self, joint): """ Callback indicating 'joint' has been destroyed. """ pass def Keyboard(self, key): """ Callback indicating 'key' has been pressed down. """ pass def KeyboardUp(self, key): """ Callback indicating 'key' has been released. """ pass def main(test_class): """ Loads the test class and executes it. """ print("Loading %s..." % test_class.name) test = test_class() if fwSettings.onlyInit: return test.run() if __name__ == '__main__': print('Please run one of the examples directly. This is just the base for ' 'all of the frameworks.') exit(1) # Your framework classes should follow this format. If it is the 'foobar' # framework, then your file should be 'backends/foobar_framework.py' and you # should have a class 'FoobarFramework' that subclasses FrameworkBase. Ensure # proper capitalization for portability. from . import backends try: framework_name = '%s_framework' % (fwSettings.backend.lower()) __import__('backends', globals(), fromlist=[framework_name], level=1) framework_module = getattr(backends, framework_name) Framework = getattr(framework_module, '%sFramework' % fwSettings.backend.capitalize()) except Exception as ex: print('Unable to import the back-end %s: %s' % (fwSettings.backend, ex)) print('Attempting to fall back on the pygame back-end.') from .backends.pygame_framework import PygameFramework as Framework pybox2d-2.3.2/examples/gish_tribute.py000066400000000000000000000116471276457661000200140ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # Contributed by Giorgos Giagas (giorgosg) # - updated for 2.1 by Ken from math import sin, cos, pi from .framework import (Framework, Keys, main) from Box2D import (b2CircleShape, b2FixtureDef) def create_blob(world, center, radius, circle_radius=0.5, shape_num=24, angularDamping=0.5, linearDamping=0.5, friction=0.5, density=5.0, **kwargs): def get_pos(angle): return (cos(angle * pi / 180.0) * radius + center[0], sin(angle * pi / 180.0) * radius + center[1]) circle = b2CircleShape(radius=circle_radius) fixture = b2FixtureDef(shape=circle, friction=friction, density=density, restitution=0.0) bodies = [world.CreateDynamicBody(position=get_pos( i), fixtures=fixture) for i in range(0, 360, int(360 / shape_num))] joints = [] prev_body = bodies[-1] for body in bodies: joint = world.CreateDistanceJoint( bodyA=prev_body, bodyB=body, anchorA=prev_body.position, anchorB=body.position, dampingRatio=10.0) joints.append(joint) prev_body = body return bodies, joints def add_spring_force(bodyA, localA, bodyB, localB, force_k, friction, desiredDist): worldA = bodyA.GetWorldPoint(localA) worldB = bodyB.GetWorldPoint(localB) diff = worldB - worldA # Find velocities of attach points velA = bodyA.linearVelocity - \ bodyA.GetWorldVector(localA).cross(bodyA.angularVelocity) velB = bodyB.linearVelocity - \ bodyB.GetWorldVector(localB).cross(bodyB.angularVelocity) vdiff = velB - velA dx = diff.Normalize() # Normalizes diff and puts length into dx vrel = vdiff.x * diff.x + vdiff.y * diff.y forceMag = -force_k * (dx - desiredDist) - friction * vrel bodyB.ApplyForce(diff * forceMag, bodyA.GetWorldPoint(localA), True) bodyA.ApplyForce(diff * -forceMag, bodyB.GetWorldPoint(localB), True) def blob_step(world, blob_bodies, radius, upward_force, move=0, spring_friction=5.0): body_count = len(blob_bodies) bodies1, bodies2 = (blob_bodies[:body_count // 2], blob_bodies[body_count // 2:]) for body1, body2 in zip(bodies1, bodies2): add_spring_force(body1, (0, 0), body2, (0, 0), upward_force, spring_friction, radius * 2) if move: top_body = [(body.position.y, body) for body in blob_bodies] top_body.sort(key=lambda val: val[0]) top_body = top_body[-1][1] top_body.ApplyForce((move, 0), top_body.position, True) class GishTribute (Framework): name = "Tribute to Gish" description = 'Keys: Left (a), Right (d), Jump (w), Stop (s)' move = 0 jump = 100 def __init__(self): super(GishTribute, self).__init__() # The ground ground = self.world.CreateStaticBody() ground.CreateEdgeFixture(vertices=[(-50, 0), (50, 0)], friction=0.2) ground.CreateEdgeFixture(vertices=[(-50, 0), (-50, 10)], friction=0.2) ground.CreateEdgeFixture(vertices=[(50, 0), (50, 10)], friction=0.2) for i in range(2, 18, 2): body = self.world.CreateDynamicBody(position=(-10.1, i)) body.CreatePolygonFixture(box=(3.0, 1.0), density=3.0) self.blob_radius = 2 self.bodies, self.joints = create_blob( self.world, (-10, 50), self.blob_radius, circle_radius=0.5) def Keyboard(self, key): if key == Keys.K_w: self.jump = 10000 elif key == Keys.K_a: self.move = -500 elif key == Keys.K_d: self.move = 500 elif key == Keys.K_s: self.move = 0 self.jump = 100 def Step(self, settings): Framework.Step(self, settings) blob_step(self.world, self.bodies, self.blob_radius, self.jump, self.move) self.jump = 100 if __name__ == "__main__": main(GishTribute) pybox2d-2.3.2/examples/hello.py000066400000000000000000000044341276457661000164230ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ This is a simple example of building and running a simulation using Box2D. Here we create a large ground box and a small dynamic box. ** NOTE ** There is no graphical output for this simple example, only text. """ from Box2D import (b2PolygonShape, b2World) world = b2World() # default gravity is (0,-10) and doSleep is True groundBody = world.CreateStaticBody(position=(0, -10), shapes=b2PolygonShape(box=(50, 10)), ) # Create a dynamic body at (0, 4) body = world.CreateDynamicBody(position=(0, 4)) # And add a box fixture onto it (with a nonzero density, so it will move) box = body.CreatePolygonFixture(box=(1, 1), density=1, friction=0.3) # Prepare for simulation. Typically we use a time step of 1/60 of a second # (60Hz) and 6 velocity/2 position iterations. This provides a high quality # simulation in most game scenarios. timeStep = 1.0 / 60 vel_iters, pos_iters = 6, 2 # This is our little game loop. for i in range(60): # Instruct the world to perform a single step of simulation. It is # generally best to keep the time step and iterations fixed. world.Step(timeStep, vel_iters, pos_iters) # Clear applied body forces. We didn't apply any forces, but you should # know about this function. world.ClearForces() # Now print the position and angle of the body. print(body.position, body.angle) # You can also work closer to the C++ Box2D library, not using the niceties # supplied by pybox2d. Creating a world and a few bodies becomes much more # verbose: ''' from Box2D import (b2BodyDef, b2FixtureDef) # Construct a world object, which will hold and simulate the rigid bodies. world = b2World(gravity=(0, -10), doSleep=True) # Define the ground body. groundBodyDef = b2BodyDef() groundBodyDef.position = (0, -10) # Make a body fitting this definition in the world. groundBody = world.CreateBody(groundBodyDef) # Create a big static box to represent the ground groundBox = b2PolygonShape(box=(50, 10)) # And create a fixture definition to hold the shape groundBoxFixture = b2FixtureDef(shape=groundBox) # Add the ground shape to the ground body. groundBody.CreateFixture(groundBoxFixture) ''' pybox2d-2.3.2/examples/liquid.py000066400000000000000000000227331276457661000166110ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from math import sqrt from .framework import (Framework, Keys, main) from Box2D import (b2CircleShape, b2FixtureDef, b2PolygonShape, b2Random, b2Vec2, b2_epsilon) # ***** NOTE ***** # ***** NOTE ***** # This example does not appear to be working currently... # It was ported from the JBox2D (Java) version # ***** NOTE ***** # ***** NOTE ***** class Liquid (Framework): name = "Liquid Test" description = '' bullet = None num_particles = 1000 total_mass = 10.0 fluid_minx = -11.0 fluid_maxx = 5.0 fluid_miny = -10.0 fluid_maxy = 10.0 hash_width = 40 hash_height = 40 rad = 0.6 visc = 0.004 def __init__(self): super(Liquid, self).__init__() self.per_particle_mass = self.total_mass / self.num_particles ground = self.world.CreateStaticBody( shapes=[ b2PolygonShape(box=[5.0, 0.5]), b2PolygonShape(box=[1.0, 0.2, (0, 4), -0.2]), b2PolygonShape(box=[1.5, 0.2, (-1.2, 5.2), -1.5]), b2PolygonShape(box=[0.5, 50.0, (5, 0), 0.0]), b2PolygonShape(box=[0.5, 3.0, (-8, 0), 0.0]), b2PolygonShape(box=[2.0, 0.1, (-6, -2.8), 0.1]), b2CircleShape(radius=0.5, pos=(-.5, -4)), ] ) cx = 0 cy = 25 box_width = 2.0 box_height = 20.0 self.liquid = [] for i in range(self.num_particles): self.createDroplet((b2Random(cx - box_width * 0.5, cx + box_width * 0.5), b2Random(cy - box_height * 0.5, cy + box_height * 0.5))) self.createBoxSurfer() if hasattr(self, 'settings'): self.settings.enableSubStepping = False def createBoxSurfer(self): self.surfer = self.world.CreateDynamicBody(position=(0, 25)) self.surfer.CreatePolygonFixture( density=1, box=(b2Random(0.3, 0.7), b2Random(0.3, 0.7)), ) def createDroplet(self, position): body = self.world.CreateDynamicBody( position=position, fixedRotation=True, allowSleep=False, ) body.CreateCircleFixture( groupIndex=-10, radius=0.05, restitution=0.4, friction=0, ) body.mass = self.per_particle_mass self.liquid.append(body) def applyLiquidConstraint(self, dt): # (original comments left untouched) # Unfortunately, this simulation method is not actually scale # invariant, and it breaks down for rad < ~3 or so. So we need # to scale everything to an ideal rad and then scale it back after. idealRad = 50 idealRad2 = idealRad ** 2 multiplier = idealRad / self.rad info = dict([(drop, (drop.position, multiplier * drop.position, multiplier * drop.linearVelocity)) for drop in self.liquid]) change = dict([(drop, b2Vec2(0, 0)) for drop in self.liquid]) dx = self.fluid_maxx - self.fluid_minx dy = self.fluid_maxy - self.fluid_miny range_ = (-1, 0, 1) hash_width = self.hash_width hash_height = self.hash_height max_len = 9.9e9 visc = self.visc hash = self.hash neighbors = set() # Populate the neighbor list from the 9 nearest cells for drop, ((worldx, worldy), (mx, my), (mvx, mvy)) in list(info.items()): hx = int((worldx / dx) * hash_width) hy = int((worldy / dy) * hash_height) neighbors.clear() for nx in range_: xc = hx + nx if not (0 <= xc < hash_width): continue for ny in range_: yc = hy + ny if yc in hash[xc]: for neighbor in hash[xc][yc]: neighbors.add(neighbor) if drop in neighbors: neighbors.remove(drop) # Particle pressure calculated by particle proximity # Pressures = 0 iff all particles within range are idealRad # distance away lengths = [] p = 0 pnear = 0 for neighbor in neighbors: nx, ny = info[neighbor][1] vx, vy = nx - mx, ny - my if -idealRad < vx < idealRad and -idealRad < vy < idealRad: len_sqr = vx ** 2 + vy ** 2 if len_sqr < idealRad2: len_ = sqrt(len_sqr) if len_ < b2_epsilon: len_ = idealRad - 0.01 lengths.append(len_) oneminusq = 1.0 - (len_ / idealRad) sq = oneminusq ** 2 p += sq pnear += sq * oneminusq else: lengths.append(max_len) # Now actually apply the forces pressure = (p - 5) / 2.0 # normal pressure term presnear = pnear / 2.0 # near particles term changex, changey = 0, 0 for len_, neighbor in zip(lengths, neighbors): (nx, ny), (nvx, nvy) = info[neighbor][1:3] vx, vy = nx - mx, ny - my if -idealRad < vx < idealRad and -idealRad < vy < idealRad: if len_ < idealRad: oneminusq = 1.0 - (len_ / idealRad) factor = oneminusq * \ (pressure + presnear * oneminusq) / (2.0 * len_) dx_, dy_ = vx * factor, vy * factor relvx, relvy = nvx - mvx, nvy - mvy factor = visc * oneminusq * dt dx_ -= relvx * factor dy_ -= relvy * factor change[neighbor] += (dx_, dy_) changex -= dx_ changey -= dy_ change[drop] += (changex, changey) for drop, (dx_, dy_) in list(change.items()): if dx_ != 0 or dy_ != 0: drop.position += (dx_ / multiplier, dy_ / multiplier) drop.linearVelocity += (dx_ / (multiplier * dt), dy_ / (multiplier * dt)) def hashLocations(self): hash_width = self.hash_width hash_height = self.hash_height self.hash = hash = dict([(i, {}) for i in range(hash_width)]) info = [(drop, drop.position) for drop in self.liquid] dx = self.fluid_maxx - self.fluid_minx dy = self.fluid_maxy - self.fluid_miny xs, ys = set(), set() for drop, (worldx, worldy) in info: hx = int((worldx / dx) * hash_width) hy = int((worldy / dy) * hash_height) xs.add(hx) ys.add(hy) if 0 <= hx < hash_width and 0 <= hy < hash_height: x = hash[hx] if hy not in x: x[hy] = [drop] else: x[hy].append(drop) def dampenLiquid(self): for drop in self.liquid: drop.linearVelocity *= 0.995 def checkBounds(self): self.hash = None to_remove = [ drop for drop in self.liquid if drop.position.y < self.fluid_miny] for drop in to_remove: self.liquid.remove(drop) self.world.DestroyBody(drop) self.createDroplet( (0.0 + b2Random(-0.6, 0.6), 15.0 + b2Random(-2.3, 2.0))) if self.surfer.position.y < -15: self.world.DestroyBody(self.surfer) self.createBoxSurfer() def Step(self, settings): super(Liquid, self).Step(settings) dt = 1.0 / settings.hz self.hashLocations() self.applyLiquidConstraint(dt) self.dampenLiquid() self.checkBounds() def Keyboard(self, key): if key == Keys.K_b: if self.bullet: self.world.DestroyBody(self.bullet) self.bullet = None circle = b2FixtureDef( shape=b2CircleShape(radius=0.25), density=20, restitution=0.05) self.bullet = self.world.CreateDynamicBody( position=(-31, 5), bullet=True, fixtures=circle, linearVelocity=(400, 0), ) if __name__ == "__main__": main(Liquid) pybox2d-2.3.2/examples/mobile.py000066400000000000000000000050221276457661000165610ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2EdgeShape, b2FixtureDef, b2PolygonShape) class Mobile (Framework): name = "Mobile" max_depth = 4 def __init__(self): Framework.__init__(self) ground = self.world.CreateStaticBody( position=(0, 20), shapes=[b2EdgeShape(vertices=[(-20, 0), (20, 0)])], ) a = 0.5 depth = 0 self.root = self.add_node(ground, (0, 0), depth, 3.0, a) self.world.CreateRevoluteJoint(bodyA=ground, bodyB=self.root, localAnchorA=(0, 0), localAnchorB=(0, a)) def add_node(self, parent, local_anchor, depth, offset, a): density = 20.0 h = (0, a) p = parent.position + local_anchor - h fixture = b2FixtureDef(shape=b2PolygonShape(box=(0.25 * a, a)), density=density) body = self.world.CreateDynamicBody(position=p, fixtures=fixture) if depth == self.max_depth: return body a1 = (offset, -a) a2 = (-offset, -a) body1 = self.add_node(body, a1, depth + 1, 0.5 * offset, a) body2 = self.add_node(body, a2, depth + 1, 0.5 * offset, a) self.world.CreateRevoluteJoint(bodyA=body, bodyB=body1, localAnchorA=a1, localAnchorB=h) self.world.CreateRevoluteJoint(bodyA=body, bodyB=body2, localAnchorA=a2, localAnchorB=h) return body if __name__ == "__main__": main(Mobile) pybox2d-2.3.2/examples/motor_joint.py000066400000000000000000000050531276457661000176610ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from math import sin from .framework import (Framework, Keys, main) from Box2D import (b2Color, b2EdgeShape, b2FixtureDef, b2PolygonShape) class MotorJoint (Framework): name = "MotorJoint" description = 'g to stop/go' count = 800 def __init__(self): Framework.__init__(self) ground = self.world.CreateStaticBody( shapes=[b2EdgeShape(vertices=[(-20, 0), (20, 0)])], ) # Define motorized body body = self.world.CreateDynamicBody( position=(0, 8), allowSleep=False, fixtures=b2FixtureDef(density=2.0, friction=0.6, shape=b2PolygonShape(box=(2.0, 0.5)),), ) self.joint = self.world.CreateMotorJoint(bodyA=ground, bodyB=body, maxForce=1000, maxTorque=1000) self.go = False self.time = 0.0 def Keyboard(self, key): if key == Keys.K_g: self.go = not self.go def Step(self, settings): Framework.Step(self, settings) if self.go and settings.hz > 0.0: self.time += 1.0 / settings.hz linear_offset = (6 * sin(2.0 * self.time), 8.0 + 4.0 * sin(1.0 * self.time)) angular_offset = 4.0 * self.time self.joint.linearOffset = linear_offset self.joint.angularOffset = angular_offset renderer = self.renderer renderer.DrawPoint(renderer.to_screen( linear_offset), 4, b2Color(0.9, 0.9, 0.9)) if __name__ == "__main__": main(MotorJoint) pybox2d-2.3.2/examples/one_sided_platform.py000066400000000000000000000057651276457661000211650ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2_linearSlop) class OneSidedPlatform (Framework): name = "One-sided Platform" description = ("Try to move the shape with the mouse through the platform " "from all directions") def __init__(self): super(OneSidedPlatform, self).__init__() # The ground ground = self.world.CreateBody( shapes=b2EdgeShape(vertices=[(-20, 0), (20, 0)]) ) # The platform half_height = 0.5 ypos = 10 body = self.world.CreateBody( position=(0, ypos), shapes=b2PolygonShape(box=(3, half_height)) ) self.platform = body.fixtures[0] # The circular character self.character_radius = 0.5 body = self.world.CreateDynamicBody( position=(0, 12), fixtures=b2FixtureDef(shape=b2CircleShape( radius=self.character_radius), density=1.0), ) self.character = body.fixtures[0] body.linearVelocity = (0, -50) self.bottom = ypos - half_height # The bottom of the platform self.top = ypos + half_height # The top of the platform self.state = 'unknown' def PreSolve(self, contact, oldManifold): super(OneSidedPlatform, self).PreSolve(contact, oldManifold) # Make sure we're dealing with the platform and the character if (contact.fixtureA != self.platform and contact.fixtureA != self.character): return if (contact.fixtureB != self.platform and contact.fixtureB != self.character): return # If below the top of the platform, disable the collision response pos = (self.character.body.position.y - self.character_radius + 3.0 * b2_linearSlop) if pos < self.top: contact.enabled = False if __name__ == "__main__": main(OneSidedPlatform) pybox2d-2.3.2/examples/opencv/000077500000000000000000000000001276457661000162335ustar00rootroot00000000000000pybox2d-2.3.2/examples/opencv/journal_image.png000066400000000000000000017746461276457661000216060ustar00rootroot00000000000000‰PNG  IHDR=¢sM%sRGB®ÎégAMA± üa pHYsÃÃÇo¨dÿ¥IDATx^ìýi›$9–¥‰¹-ª¶º{Ddf-SUÝC~áÿÿcœîªŒp·ï{U3Œ¬éé!ùô11ÈÅÅݰ Dt;ûtöià­'òƒ Γ–sàŸ½mÅ"x‘ôüìâòÓÙŧý~wyµ¿ºÙß¾¹ûr÷ËŸ¿Þýòå§/÷Ÿïnn¯Áù¹Æ/ÀååÙÅùåå%ºooÓlè××WHYg ôÜï •ܹYK-ôÅyDÑ]§"~K€Q0±˜ï‹–­A@a*Yâ §v>á©íK†ŠTIR* ó% {•x;£ZÛðµã1¼lj3JÔÞ`qÚM‹÷ò)O3¾Ž"}¼SINK`ŠyžuçE@…¨´‹•KzN³]$7À ’t؀؊Ù.é}Ê#Y‰¨¤ r6È꣦Ëh LR䟃ejkó)-‚:>Gî ±¥Wº@6írÔbÇ`LDñáÁsFÝùÛ'´Ìž9Q‡ËbTbY^E”¶e@™`É”rcþíÕ.®Ž@–c´dU†bàRpq±õR:uá¬â,¥ž)âÏÍ4 h+ Jã`±è6ÒfGé&€“¶Š0F/€fºë(å5`@‹`.Å`Ф--$#Á òåÍ…äÍÃØ¶ûˆ"‚Cñå‰e„`^_^H^?=kŠ•˜b»sNá´äëÛËëóËóóãÓŠ/OOÏϪ½Äÿû÷¿~ÿöðâ`» èÇÇGÔ¿x|x¢Ÿž±ƒL<==}øþòüò׿þ"ÿ¯ÏOO8z}~Æâ¾°m{(‚–ÑÌšZ+ ©­ÞËkÖCö\æ¶[Ô©É` ŸŠó +Rèz„W,åv_ ÷ô!æc(ëIy”q,’p…¤ËÔzRz^>®Ä\ˆŠ5@q,Kï0ª3KÍ ÿ‡b´U3 õwܬ*b ¥ŠRÌ"Ð)“AXšìƒm”w%¥½¯o¯ÑÚ_ïwW» ö×;ËYôœaÑÙ.çdjF: ÝEñr4æu„€¨-p[`›ªÅ5¥µ˜œšø²†»7æSñÕé-y)²æAé°qnŒ‰fkPÑÓ}Ûŧ³l׸è^îÙ…__ï÷×W×·7÷_î8~vßöùóWömìÚ®öû}õ¸J³e£J$˜ízp¥!Ì6´.“$žöi³³4h™ø §á5_´À’YÌ•ždI·Yø5FÉ[7aÝ®e¿‘èY¾2hØõªI§ºQÈb騉í:ÊÒ<ìÄ%«6´Šõê^ ÆIu>ßTf 7-Þ«´ë'û6‡Í¾HçJúéYYÎ8–n¯†„°W‚€#ßY¥‰¨´w𣀿¢ÐÒ!c;uÓK;§9ºÖã*—ó³·\Ûh`„ÑôâA©¶¸n Ò#+už;‡l£É"´¼H¤t7 XE(–ù­JÈÚ"½pâjvÕe+- k;mméð[„<€®âÅÎfE]6þ¨B¸*R‘*’ZdœMi¨Z³h=pD#nÁ‡v_}t˜§ öLÔWdžcmã¨ö±68H‹–bJ¢Fù‡í†‘$ˆ5Ä&™9*†3ÇJ­€Ô²Q“WÁ„ì|çÄhI$5p´9+Êð[ÔVI@TËgš •Æ¡1ñ”q†ësn‡a²¾ÃÅÂå厒‡ïßa^^2ð/´•}[‚5^z›¶ðœõÖÜH±þ`gö»ñüúÛÃ{5…/ÏÞÎ`~ÿþýñáÑíÞºˆ¾ºoûöíéüû_Ùÿ="ñÈVp0QyzdwÈþPè+5±;™bmOþðL«P·Œ1$küí9!¥‰…•ñÚAȬu ´|ä­ß1Ç\¶âê´©V,…ƒUPÅSî„¥ùW¹ã'ãÒѦ3VþM ©÷+œ ŽA¾CÅâ$8$÷æ^%™¡PüÖÀ©Ý8Ú¸ù=³Õ™DU#™+iW§´çC‡ösTŠÖÜŧ«ëýÅåÅû ˆýaßÖKçbôŠKDMlŒ„lǹ*ôUä$Î/dÈ!R™…Üà·©s|³opæÄw"£×ƒú ¨û¶-f0#†89Ñ´ÇJ"S(8ÈŸìÛ.©¡[7&û~Ïž÷üêæŠv¼qßvÏñË_~ºû¾íóÝ=lÛöõÈêåÖíxßÖ’âü[î‡÷CkÌ…Õæ´ NÅB¤ºÁb‚M Ž©²•¡¢ieJ–¨$XLD÷m½¼­ <µµx”Bdgã¾ •,e+1„ƒé®è[Sr0êâ…Î}±HŠ@"9Ee–pÓâ½|Åô:K’óœ"i–S¨9¬©¹ŸŸ±¸«jÏÙV­™ÂE#%¹œSW…©âÉ\…H¥ (Rò"ˆ \¬Ã'WgçpUç?³ƒ±©¥ªªh@Nκ‹Ýt ]…_šÔgùr?ç2–âJ†š¦V››P9ä—JiÐ,ØfWHbIÎjŽÅŽÉ¸ÛyuŠåàO]¬Nš§©Ø:ŠžùÙ'Á¤3ì  ÏÛAeO³öŽZ4ù‰‘dÎÆQ±á cFÃ¥cŠapŠ˜õLv’ƒF^‡Q] Œ¨åœþ-ß`ø lâz ¬Ï'¤N¬¢¿k߆ vhQØ.¬®È<~pß¶»Ü±¾¾}ÿí7˜,ª\½È¾fßftÖ3u ‚iÖŸ9ï¬û¶*¸o;`ÏõHœg¬ÈlöŸQ|xxz|:Ô ÊÙýüðýáéùù¯ÿÁ¾íömß¾ýÆåçû·od0ö žtÅέ"é³×ašÐðpõì†ÖÁ&²„p¤{ãÔCèùÐ)XèÂ$ ›šMÚmTÙÎó¿>§´IIÒ6ƒ¼œµNX}4JÇPÌèH#[Æ(r’Sjx¸×ë Ž¬‰×1jzÚ8…fÞ+è$ȶò?²û!Þ)®€Ó ™DŦ¥·áÌL‡ÞÒµ¯D§ FŽCÚÔ¡Z)F•Î?ù˜íò|ýÒ}ÛÝçÛÛۛݞ ŸW>¢É¶Ô] 퇞‰9 ikø»û6ãëRsѲmŒ¯P%ÌbÓ‚^ª)Zb¬¤Ux«È–³ .R×Ù©0÷ÉW>j Îz9î ºXÇÏùfßVS(àÝMC²éÞ’ƒâ˜kØë›uÔÇÔè•YÂM‹÷òCÌ—gŠC`†¡Ê¦»FfP¶Æk.e•r¹JóûèCÃÕj{F]¯ªNÑ""‡ð(>«8È0²y9›&Jhš ÖlÇj:lvƒÈðÖ¾m´R˜¢Þ/sÆ…Ó磤"# %w‹7íɺä¢Óp”–µ!Z¯÷hTѳšYì>½í\Ê.[¤XT|M =ojCšºXÙŒ®—)uÁ‹^äãÎ’«”þ”ŠÎ(Ê ½^<3¨ÓæNŽU#2S)&V6v¨ÝiÉÍ„1  âÀB¢õ?t£u#U¾±Œæh„“³›Õ1 ÚÂË¢sœ´Ê-Bw¨Rårz  Cõ–¦=·Ø·µjñí•n†‘úþÛ÷ç—×Ýî’kßþê¾íêꊎv©É¾-Ž»<,£¥ÝìÛðŽI Æ+ÅÌ¢ô‰m•÷ÓîÛ²B¾=?=<[-]f–=?¿<²m{yùë_ÿê ¤lÏòÊé¯ýëÃ÷§_ýÕGnlYž˜)xöYNžh~w£léSÅg‡ …ÖóõQ]<=QD Nµ9®Lm—¹o#“f:ô?U•¶­Sm¯ÛT.äÕŽ+ÍKoŠ‚[ä4×¸ä ƒ(‚e} sdKD³Ä™|a[:Ïi˜qGAኑº¾³W[~ǹøZP¶W˜©5ÏÇš[ £7ÁNð.ðå2–;}gá‰4hÛzˆŽf §®mJû«ã_E˜¾Úrù¯ZÒ‹+†ëùîÊ}ÛånìÛ.v¾¦‹ÄùÙ«¯ÇÇà4’˜í®æøg(˜NÎÖÒbÒGÌdgX‚,®;ÑrÅÅ´qb€¬í7Ü­×IÍì­`@½’Ú7€Ã±†íAA´°(±²Ÿ.¯Î/Ü·ûÐrΎ톿»[ßÖöõó/ùåîËÝíÝÍõÍ5ËM·/díR¥Tf…h…H³Ûm4 LUB K…†œàÂÚ‹rÔ ô5ÑÒ%ö7÷m •ñ:.¥Ób•¯b ù:)½AéÜ·é¨/T%PœlR@œå&·i}¼cÑ e* Àè´Â;Ae±²ÊkQ – –®æXËÀêT,W™(¤y»o{zưƇ}ŠÜ §ß8òšNömh MA”eZN™êæg„‘D™«ˆVmón;1ª6wgE"òdL¬4Ê{G> h'36(§Ý‡©ª€šjZ¬Ej6Ú„‹ùÚ•$hÑb¢^ÎûÞ„Ù”2O^iªì¾íüæškÒÙ·ß¾±Uºä:užíõ׿þŠÞþjyaGS±kôsè}<Ç»Äã™ï-ÓcÝÏ»Œ¼KìÛªÇvŠ× ’nû(cH±#yô2ó „ÈžìûÃÃ_ÿã?a>pbãöôôšmOìžݻ=ååTH[ê+Ùù¸íív°Œ~ûXIvzȲݳv¶„'¨£"VxFlÏs© oß±1_/Ï>]_í)P½­šAKc¢C@›ÙàpÓpÍž KÄ\;,õ„¯Lr\¼äuRKL§ˆ¹o+³€‡ìäl¡ÕAŠØ-9êM‘wš'Pdz!ÿ–ŽÈ˜ *´…£È‚®Ã…ýØÔæãœX £EŽ;”G º©»é|4ÇÙΗL˜ Ù·]ÜÜ^“;͇^ ù‹Ë nKÚé̃SBo¶A.LŒQ*kHÉTp¢q@"pî••iŠÖ¨Uöm`|3€EÕ¢qÜ'Ëq$z@ IJ„L…­ã±Û_\î/¯ýðÁ»´›{woŸ?ßû¶6vÄÙ´zB°Ù±ÕZƒ6ô´¢‘Ó3Ò)\¹b tk7è¬VXh`-p*¼EšôBžl×’ÉÜÂø:–Y…P«BmóFÔ41ö”\P0λÛÉBܘS¾ŒDP‰A‘hé†ÇF Z³ó‚œlÆY¨W ¢`dDÔÒz‘M¨i]—ж*SÑíaêe€\7±Ã±Ô‹s(RHz’">£(‘È«$£AAò&’h@-mꂱ FÁûL“-‘Y£ ;‘›çÀÌ$ý«t¥·)厷!ŸŠH+L„²FíìÃ3‘4ÆXyRDx¸+Ø„=Ü¡‘tDDl*…À‹Žæ ªS@H¥Ñ’¯ðTÏN£Gkj¢:ňò8RëfWz’%ÝFY+Ê¢­±T¶Dé•n›î„Ø1z‘ï%½ý~Gúöṵ́º¼¼Ø]²ÉÇüÈ‚Ã*›pöî/Ô¦­zÌ9‹¬„ÃÑfJŸ³'òŽCÚ‚`ˆ»QbiS0;Ÿ%ø.‘ù-d¸Xîö;–ýq÷~ÁUs½¿¾ñ­2¬ÿw~íææþöæî憋Â-W·ÝZxwwÿùÞãþ–”üõýõý—»«+ß!½»Þ]^ívû+Œ_rù¸ôýÓ禗ç;?ÓvÆ.ý$Õ'õšFÙ´ÉIåaºÚØòÄF]­¾`\ Èùœ-¡­É¶Ml›Ëf ÕFù–Ù Rþµa›‰ÎFAÒX]ØÒü¾Û…#!2?RúCÆñ}ˆ™§¥²°{NZPb3L‘a{µç]Y€Hu7R]¿g +eXêTÜ ­Ãñ—±;,-sªGèê·Õœž~Œ haEÓl½NË Ì²AE`Ô}ÃUóÆú# ÊJq âq”>›CüâÓîú|·ç8cf2Çî¿ÜßÞÝÜÝß~þéË篟þÓ/ìá8öW¹Œ\\`Ý-Åó‡ÔÙÅÝ^kÕ¤KøI…Ó¨£"¼‚y½r–nè©´ N ¬tñ#ɽ2—ï¦-%òì"œ8í]NȺÀ}z¥¨O2¸”"àÛ‚ûæfAŠ7š2 ‡pö4Ï+Œ]´TÛ²—½¬ò†RÇžœî3"?¼d5ÎyÄ¿œw®~±ƒÝjÒ1.Q¬é AQKI§_.çÊl:çÈB›’íN8;y_™óuÈ#Vó͆‘¹i…UwŒfÔGïæ}YH›(®á‚Aa¦W+å2ZC¡B ª‘A’›óÃù’)¶Ù“"‚ºL„ EK€†Zô{âD²ˆEƒmöË|.¡FäF¦ý4sª”(*¿­]¥ÊÔfáUocÛðÒAfËÚ‹Yb›Ðtgè£ ¼Ã‰.õÛ ÆÔ‘Ì"6èvG´‰!*F‹A”CZËÍ‚íX[G¤%N QÉeÎ×âóÆÅ9û䉞õj¿÷yÛüÇXê펟ŸŸñ¸ß_1´3ƒ –eâ NÂcœ»ÉNŒL„‹§çç'' ¹òí¿<à"ìYöPÃÊ ¯ì™Aç~øñéñÛ·oÏOÏ/~j§ ¥'_&õÅÔÇï>oCòíéÕ× œ”^Îz͵ç—ÔQùõßCãÛ÷o¿Å毿þFÃ>úqŸó‘ ãK´ÄÁîëKZ¯”dkÛ’x>ãºpuµ¿ }–ÌöåZ4žò²,F²Ër÷ªè2éŠG³)÷_NˆÀÕf¤‰­ãSS”p`gÓÆî‚æÒKG8,–£(†&ÕŒ žô`¯ò|4QF4kxû:›S¢5g¨Ÿ±o/싆°…ŠÃ¶ö ÿ(~x$ciÁÖ}ç#®­Ü-°›¿Ê{Ý|íÀËú9·8¢ê`VÆð ˜C3N}aÕ ùpc~z<ÄYœMN­>o “ÜP”4g>9†Y2G+,#1¦hoC~„“Ht£ê+«¥Ýž[®Kn¤öWû»û››Ûë›ûk¶n¹åº£ˆ[%ZÐÙŸ—®†ÀF»¶}ÇKã¨U’A›Fcr''±…”:”&Ýf‹Õ"Å’Y0¤`eKL4ࣙ€~0–<ÂY3¾]d/f•Ÿ›F'BÍŽÓ:O q&‡„ö6| A²µ "™º+=•ÆiÅtè„pMT ¬¥ðQXÙ:]ôL¥ß¡E…yôl¡mó®J)<¨”öÜ›ºL%YvRИª ©SUFÉ1Êi#–yû¢[,æ¶}ÜÑ#Œíü ¦Ä¢Á‰ßñðòÑø@e‹÷ÌjÒeù%ðwáC•Å,±M‹Å!Ô*ð»Pe£„‘emqJ¡Cë¸qN$O,ƒ­#Ò'ÏG]iÕ1tÑŸÂêB³ ª%ÙÅXÊ„ãe–Ã÷iÀÔNÖY$q¿Ä >‡ójê£8.¨}w¾;¿ÚïwûÝõíÕÝýÝ—/~9ÇgÎ_îÉAßÞß~ùúùöö4Çç/Ÿoîîòœî¸Ê`êúöúê†ÃÏÀí¯¯v{®@ûóýî|ywzÌó9 ù»± ¾­Â³o¬£¶^jf6Müy÷-MëÛ¶Ô(OõdA PVÑQ8r`öù8ý¦äÂ!õ‘™Å>”ÿ ,L|‹T|R§íúÆTÐìh"pTøï*_7=/Ï¥ãÔ#žßºÓàpÏ2;Z.—ÃÔ!˜wXCfæ·*™5X=Ô„Ò‡!¦L¥—YçhìlÓ…¥ÂÿïlÁØ’ð¼Å–¡íÕØœNeÙ¦U4Cû’±æw_ž]ß\sÃÀf}ç®ÃK»áõlã Å9žc¦D½çË,í…,χg¡C~ÍåŒ'þQÊ€~*¼jê§2×2nø¼ÄO•ƒw­Hv¨4Nßœ~³—Ÿ.vŸnî¯n|CÂîþë= ÷ÓÏ_¹+ºÿüùËO_ö7W·w·>®dÓv™ËH`VÆmM¿à±á"y·ßºtÌæè©4Ž÷‘ ±RÂŽuªL¾X ¶|º–p:À(ÙH‰%9 Š—‘ÏIoh¢lq;¢ëûÚ·µ¾ ’Û´D±²%4•+NKAØËhQe`–¿²ÐM·¨ÀŒ$ ‚›0fZ9;5µ&]|ˆÒEBZ”v+Fgå>Éo@°q|ɉêø#SulÏ]A½Ã÷šÔ„zP®^ŽÃȵk Œ0±âÚl. ¦XÝTf«ðìk>Oµ°M·¨»CšO»„ÄNù-N²`ËYN!Êï(ÈmÃ.*ÁÂæk^ WÅФUD 2U·xUoéÖæcE³¹*¿°ÍžËrÓ²[ùãRŠ<õè¡wØÚÜên§ x/Pº2MaØ…ªN12Ív^W…"±ìÓVµÅ¶Nü…rÐtËýú’}›Wjé{Éd?wŸ¯7Ã(7=_¸#ãT‹)ƒ5¿È#¬qCÔù†<áöÍíšû6vƒ”µ}fÖXçx×x”¢ŒR†Pâð£Wº&eV UûÃxà^ÍíœÛ7íÑgoo¾/îrÏXTX“Žì<çuÌÇü¿²Q{ÄæËëÓÓE~âñ·_ûÿþÖQ§b?õ€d>õ ÍnWÂ*´ÙWœŸTͳÁ쀟²=Í›Â3! ØpV%ŒË÷ÁQ¤)þ1K-<"&™ýeþ.ré´PeûÓÀdnÙ)}o N™éW1g§ ´EVW‚5ÕUÙ¶W9ˆ7DbK¡="´Á` Û³Ô‰™¥,[ÐÜòû†•¯–ú ×æÓ"P{}SãrÎec[ÛîÛ–ëÎRσî‰zàPwcûkÓCž}‰“NwgÙ¶e¤f¦1>IW0š*×¾m-ÔÝ·a!Aží?q«v÷åæÖïþØùéóõõîë/_?a×öåó×/—ûýÕ͵«‹‹Ö€Æê3ë¶Qr ÕpIÙ ßÞÞâóá¢ÌzJlêPb„i–ÑjEùØ¥‹UÄ⺃x\bCÉ™–YƒN¨i®Á×µTÐzAt}¯£(Ç–c"D±²¤C+ ÓR _†pM91ÁmËO®’Žãc•´[a­¢ge 1ø`iEѺ¯RMo$+’t Ђ¢¦è{¥š#Øç#¸36ãÆ|jBÖÁDˆyƒj¥¢U厬Ә’ö²W/'qa‚ˆÛ}%Êi˜T RPª~]0°µV³1ò6öm¤e­‚D…ƒ-}‚•#ˆ‚ìhðL›ÉÆa5“i”jqÑ#eÕ*‘µˆì4’¼DNZ"¦ý‹dÔÏeòï²Ùt‹Fõ!Ò¨`ìÛ–æRXfÁhvÙ‡æÊ.ÇeA”×ZÔ²o€Û!œ+Û4îXJé »]й_fÓzQq³\àÑtÌ;É÷ÞãEà”¦– òÂòÍÉU=LÆÖÔòuW1ó*ʡ˻osY>ó½k½Wržºá©à­jDL­ÑÉ×â(•=Í󋯣zžÝ­uh&x}Rm9²¹¡Ê”ÌRãE4»Æör³ìǾ?|ÿí¯ßdæ<|òá7 õ»æý>¹¼£ŽÒ'2®¥¿ÿæ'¥Ÿ±ªÄÓ#ßð÷üè·Ûd`ºqÍ›"_UMEžý>ØqPlª´´H?Í•óaÊ:ÌÍüß²‘ {æ`¬LÆQ‹Ñ¡3PÔÁ¨¹Ô¨Ž£¤Dqoºã4E{2™ñ6­,;sDžÜÊhyJ×ÒÒ%߯´x‰(ɺœû6wl» ºÉ—åwرIÆmø#û¶Û’ì‰É¸E*߉Oº`–‰‰Ù.ËÇphÑ0YÆ5)Á4ä'~o߆憉‹åeíé3Hv×Lù·û/··÷7W×W_Ù·Ýìúû67m÷_¾ø‡«=Îú⌗W¦¼ñû¶?Â!¬µoÃ<[ã›ß~{²o3^R–±´BØÁhß$ɦYDK^ÊLDê€ÁM{ *ØÚ d’Æ}ÛjÉmx­(síÛÊ\¨ÑaúY bf…dq/\Û°M¢{ÄÛËVÅF¸\`ÙžŠÃpÐpnäÛø«HÚ .;ª+[4 VË€¥Ë¨pj9†ÞÈ, H0WklíkaŠmåu’Y™‰Ò©¢„Ks¤™+ÈZ®£q+fùGiZK´­f¡b—RÔчÆW” ¶n颖Ë'}/°- -1×ÐOùøö®ï:çÈ[×_ò²”W­Xp]ÁN.=˜³M!Ðê&S±£ëxßV2¤?Be èm¶Š[NQ~Ô?Šé§îº‘樦ù`éa]”Ö"¥G8bTÐFhA·APàH#Œf m+Ù ºËãÜß,(“}›FâtÔnõTaŠì8¿zƒ‹Ã…>J,­.”’ªã7Í`nXUàÎXÉ(Y¶4ÇæÈ& 7¥”Ya3+ÜáD=±ÙÈøÔiß4Æùââ2K…&ã­C…T¦ 7}Þ¯è.ã‡CMnijÔnñ5IÇ E<³.ð±øüüüðÝÔÊ35r/캞ܥù4Î ™Û¸nÛžò.6?‚@æ·ß~{{ycwG`lÚØ·½~ûõøutÏ>áËk¸Ý56v}º‘¾,k¥üM”Œ‘v¶Mê „'ÊÙf]˜j)5©Í¿´ŸéÓüÁhºæ53?ÍÆÀ)ª1¦ÈñÛÙâà,Áç<í,a„ #L‡]œƒÓ©^È5îÅCpJ.P{? py±÷›ÿݱA²iãð ±o#LMŒ9Ä~ÆØ]å4h»ÀÌu¡ÁŒ¢™-¤p€ ~0²›}¨|Ñ}`|‘e¼b%ŒƒµŸØ„Ê ”_¤C¥^!Iiì‹O·÷Wg—owŸonïØ·í¿~ý|}{ýËŸö—|鿳k—gáUOë;c ÝCnµ0ðÞ4½4@ÞÔÝÞ¨ó*åè\•êL~‰…­E,lZ´ˆêmlw¦fmú:iï¹Û…ÛÈžjUexÚ ¾2ÞÆH ‡©Õ€¶­TuÛ1˜ö=O L[Z©2ÒÖµ¿vHŤ½ð!–z‰ÆWÐVCÚ0+¹¥¹5 Y¡R8°,”¯ÝM¯”žè‚ã†Æ±»z¸OñÊC) ÑŠËÀ4¬‡ÈŽYžÄt¹ædËÃ'Ùšå¢Ï#Çå·‚â}¨ µ´Mº¶þÓµüq=,PÀ•ÉìÛ¼aêȇL"á‚åiíû€©§¦ZUQGu¨ 4<üT-åµ$JX6Q £làD²D¼Ìpj7C=ÎCÕûH¿-–Ór´µœCØÌ'…éa^PÚ¸¡HXR2øµ!Zád=Ul9pVÖØ§@èatxÃÅ*ËŒHgj…Í¥¯W¶lâÕ÷Û¹¯#ÏFíùÙçmoŸØ®Qøøøøýá;ê~ ÷õíû÷Çg…_üÝ0%ø¡]¼p´“B³û#õg]}î—×b™9k·—¦Kø¨Dë,þ{9iŸºL?[O9)}¯"ÖhÏÕt¢UË*㊾}СѤ½’^X#hœ~Ñ«³Ó¦ç”žXŠPEŠöü16ùe¶Ђ!`ˤÓ`°ìÎÎöçûkŸ±]^úYI éjÏ¢Ù,fÈ3Àš F[×#¤wí qh]‰n]D-¬ÂL]R‡jN½èÑi2˜SÇé‘êYèš[˜çþïÐ Á¦ø€aÖ°ðÎĺütu³÷i$Ítåqs{µ»ºô {üâvr×.¬Fx¬ž~jŒ–Ñœ¨IWÕ„«Ôð-JÏêvìÞ@{h Ý#?ð"Šfÿ†Áh Ëí÷¸ »,û6;°‚rA^™qùÖtJ3™c …\É$°KIZ)m#b>v1̳¤FŠ%AKFþˆb¥ ÂB[“ûKÝÑ;ëú!–…˜ü6ÁI©™µpœXÙà¬ÚV¦_N0<:LGu“ª¾ŽH É#uðÌä•ýtÇÖÔÈ'¦‘ÁÒ <ÆL4«¢üQ”œƒ l íÖÈ,âÄдӳ“ýÇXÅÊÕàûª-aŠ:ÚAÚ’~p¼µ…0ÙÉÙξa$вÖ9äd 4ÓÆ:*:;¢¨³G8Ž?H;°!°¯“wÐ:©õkŇýTÐÝØ¡É37¥cx‘˜íq¬nd\‘Ù…ôRŽõ"i·!ÓŸþ•wmH;:ÙÑx¼vlgíQ3v —qpC9·d®÷Yc¨Õ|ñ’ç{ÑÞud±‹LWn_¬áÒãÏîøéÔ‹\wöWW{?ZÊE§ßÇõçîæöþæúöêúöú–ãîæ ÆG½½¿íWÜÜÞ\î.ÑòÕ´+.ð;¢òñ N./}ø||Ö?î}%Ù~hJ·eÍ%P?å1b›š‹fs[t‚öÆ„9Õì’s‚dzÀ#ý1$ l“=$Hõü÷âDod&ï¨& á|$¸0 }µ€M ­ MRvZ{žcÏG?öÒö”ýÖò!ݰ‡‘Ú³ç,8‰qó FB% Ô å‘uœ„’ÓÉžT}³Û´c cÀÉG‡4>H±²Ô½8Ô†÷Ag—ùm«Ë³»/·»³ûû›;&Éõõ×_¾2Iþôò[ïnoîïÑÌä‹óZh@®§é‹òK€–º2T5EöG÷vï$A÷ãΨ£ºPñ‘E¦D±²ÑÍ‚¥¶4˜‚#*·HN¨ç6mÚÈW6iûÂ4EŠ*“²ÊeDRè®ÆF•A%‹ûP„¿½/YEð·Ù%Ï¿ýK–×·^´ä¸hÌÊ®ô=¶fÁ[Z‹{àD ¸K»b[t‚e ‚zm9?Ę3ügDzIÊèöæÇa¼ó{bœ,2Ù¦E%IKزóRÔбӭ:X'b@³G¾8¼»–5…—Ì{uð!èò]QÇÖZ´d2=qqÄ<©&hM·ÄRi ¿(]>Ö@¹–ûùØcã¢á•„(³i-Xl]ï9y¸CƒŽ0HWéÖXü”žX;‘/s£õé-ïq!_æXß‚e¢Šya²9wIÈAD2~5§%‡†´é’œ±’‡26Näk W@· ð´‘ÇÑí~ ç•¦ÍSM.¯>ï§HG4œ^ë7 4’ñ¦D˜1Ó—&¡Ò{îÖL|5‚}“6S-¦ËKË›vý-1†•ÏÔ^Ÿßó°Íìóã³?¢ÿèëªy/ÝãËó³¦^^¿ûÅu¯Ï>ÛóÝ,¶ggÏoë=*ýÌ¢´À ³2RP}³–Û­C4ÅÌR:.’³ü l³öHç ?‘>ý1hk;´fª= ML÷ÄÊ$C` ù"Z™Œ×›U‡¯yŤrã…}À™ß;æOÅøyÒÝ•_Oæ%-` °Ñø3rþÒ°¨g(Y‘aÇ ÆM¤Êm·ð4X×À°6¡Lœj*ë‰AVæù¹s(ˆÒ0RXt/ícát@ÀH)V‚Ôi”ß—¸ºÞ_îήoöW×~Û58~çµ?˜àoÈ·]´;+VÒCSŽ2™AKñ dÖHóÂm”4*Í>j¦äÒýdÚϺŠRM¤÷*°ŽéyÑ4Þ\föhÇV†v‘p³ìtª kÒCes–ºj¨œ“¾KgUÓé„å r*]¿o)%™FTŽ~m¸Ã¢ ª÷¯~¥œq/«cŒ¤¹2 ²rbÊö·BƒY´" d—VÿG2¢2Õ=±°œÊ•>ÁrC¦ÍL4Ž¡Þ£.•öO6;Žy!©VQ=°ÃvÎŽÖK—§@‡Y -JFºˆó)ô0Nô ׄåøô"2ùó×-£5‚I'~½ }$ó$™K `Ñ¡3&É ½1ðîUÌF¹ÖKÒÿ®qïšzÒ+ýjs 8EéØ- Rk–ño¾%3¼bÉÏz¥hÐA;…d¶Iº4œ å5I’c&.‡F°bízÜ,#²lÃj J$Qäì‹(ꃛ)Ò•õpðŠµ ’&38#(B+9,rr ;ÂE êõÒ×SaëFVU„•„ÎCÒ²ÓC̯8äíê>Z»äÂÅ5ýÚßGºög®óX.ëîù÷Kãò+÷www\ÔüɇüÒƒ×5/y—{L`Î's{¹á,¿ªäÀì&›”€ŒÉ€g¤Ó-ã(çƒ,µ^Yë¶ICØæ°eJ×Õh¢`©¤M"¡vZ¡ºÅy˜Æ¸W[7R1*jšHßCÇ[ZÌܰsŒÁJ§F‘ÃùPT‰>—5ZªéRÁ4¹Û9R—è,È‹4rÏ-óqfÄ[ã÷bÅâk=ôJ7YŒÔÌÄqnQ'Ä;]°8Ì!›÷?Ðlfýæ‹O÷_n/÷ç¾›í³¿Zò§?ÿrusýËŸ~†¾b7ws…9.AÑÓ‡ÔÂa:=è¿n·¬qÉÿTÁ Yé$=åÑÚY¾7:GM.ÌÖÐ’îÒ 0xP°] õg´ˆ(î“»È)9þ $Þ iîÓ¨7 ±ãy,ŠQ‡V¹°;Òœ“ô…ŸÞêÚ¹Cg¬#’9cï<×!oe)2æLg_Ú­CÙƒøÜ¶-Gž€ûR©?tïU³{Ì·‰<=}ÿÎfÍ}›;¹‡ÇÇìÛ~û÷__¸¥xâµ—ï¿}Ã2Ðlã0‚iÓ˜ÍRੌmšæéÒ7êžê¤.23$,"¾ñiÖ9>“KÍR§`-^YÐÕº­hCNØž d¾æ“ÅÁð„ðr1ÔšÝô|éœ*3EøJ-îŠÅĪ—Qô–C-Îü1É‹KGÄõõ>û6Ÿ‰2ý¹´ùL¡\Ýr k߯"A ~Û‹rÃÕÂh™L‡F^#æÄ g¥J‚Ž[# =²ýï@¶íã³%Ò„½ ˜G1iécಅ¤éWömliÏwçl׸²÷s þª•oo»þüåóŽVê·ÓR>ˆ ™µå\› ýº²T¾±‚2©gùã@f¾ ²[ù?Ž¥¾@¦ù>Ȫ5ºÛAÛ”æžF¬¼Ø¤â­mc#ä4h„+i†Bó^íAþÕH¶êõ¨2 .D(ëQRW 8"6M}\-8eÊÆ³Îsµ~„¡2-ÔûÊþq(T~bãy–'øŠõ½)6…Ó Séу8Ô"™Ü4°`¢ÙÁÁô’´K¤GV"!Ê bS"š‘7±²¸È¡F»/Ì…!€FJH3hâ)%Ã`yÇîâJs`ö¡ðvöéƒX§…÷(ÿ¤TÇ1YâC]˜ ådÞÛ, 6\nø Y ֨㠶2K€s… vÀhû¢GMɱ²\-  hªdÎÅ´‘24Ô6¶jl½¬‚Éi^8Ÿf¶ç®'•óŸY}ã‹ù)^Ìâ>EÊÅŽ»XÚݸ¥YÌ»gôP2Z]κ¨¸qrÚLjÇÅA[ ½5$ÍFQ›ÃF%«^Ò?K‰ÀñÚˆŒÉÂèTÙKJîrç.í6…uq~¹¿Ü_õã‰~ÂÔuÜí|Äþꊻb¿£‡ä•…«+®‡è^]û™‰«¼‰=d.PÁÚõþ ×W;²;˜ýa.E•·xÏ>ƒ`²™éŹ¯Ææ­k]HGuQ´h ïh[h‚lÚ?¡sLl5É(Ñc =½ÅÈå´k²±|Š¥8kKUÛƒ åÄóõ¬=ÙžµÀ§<”Y)Cdbv^D'ge )“4vŽ "ˆÎ ûTìDgbè&5–fšZH¼e#=êT,NVÇ dÙ¤îoÈŸ.}¯ß޶¸ÿzË€þéç¯÷_?ß}¾ÿË?ü…¡|{ÇhfÌ1òHŠèfˆÝ¥Óû•iê®ðÝ뤴¿ížgBè‡gÇŒîɬÍÝÀÇ0”M{²'ÏÛA:sî„BàB‚R´@dÛ¨’ó,º‚ÄF„оä 7CÐNÉ)Ë»{×FÙùr£˜Ô †òtÁü„: JTοÕz}`“B14WÍŽJe|ƒÉ7"µ äÌš'Ež»Ïj•¿E™¤ïÑrê­«¨{îßtÜì 4Ú5i&ƒ±C&ªHZ™þ«F2.-­å¡­€ZÃü(6®"TUhÌðpg9âK;Ã5Á´Y‘)\>ƒ N²ÀúÔEÒZXÆ—h§ä rïÎ0 ൚¥·@kP§¯§°5N·x+6Ÿ¼CDü_Þ‹—4æßÈÜ¢Ff)á²Ä¨5l¶[³8, T¤¥…Í?«PÍM""‡6Üb¶_L•3G~%”Ø4oTXϹ“¥¨œÊl%—‰84Ÿ¾#^‡Q–n`4tôÁtG’f¯K¾p·†¼¤¥ž´_Ë`ɨPàâù§—ÍÛÎZ¶]N.uÃDÝ£M=bžVݺó4/7‘O&t,[h-^ó ´Š£Ž<Ùe\]½h‰pˆÉú -wR]Õûìåíü,_’5-gOB”Ä|zù‚kÜÙkÑ¥ïŒ1R+û’_­xxxxOÏOöÀüûø•$OÒ¯//¾NÊÂèƒ:»Áçm¨yxøÎÿñÑ7¹>ût~HâÕOEøQŠ|Læˆ8t^ò9 /¤i»Ä”£DSGÙ°•,¤i¹E[Gš–æÛ\6ô ¶–DIjꜸò”$8P žú‡EfTyê”Iê.݃žß]]²“¾dCâ¶Û]÷ùÎO 3$4¥-ßž©žk³ñ²a&ûòÔOͱUãžC%‰Ú![„YR´HAWŒ éC–2òŽ£Ô$JÙøI1Vœ@ÖßÎ=I¶V€tÐC8Ä2dþNóþ¯³ü·AM{,dA1¤U´xÏùÛ˜ÒŸV:Ù~þ¿³yþ(þx½N$OÚDºƒ;hi†úv´+)";3¢Òÿyl›û„ÞÿSñ?ße[ñýñaÑ'E'ÇÂ{ÎÿDüÏjËCõŽ*:zóúA›´¥,˜¨ƒ¦‹ÄÈ~ ù7pÐÐ@rû=˜w%Ž0®|'˜Á bìg¶Ç–ÙX×_î/¿öy[>—à¯LÜÞ°«e›Šu_a2êõ‹ÂíEhj@)í&””ì’i‘¯¼j*ÙLÆ($ïSd󽇣FJléE½/ÒÐHÊAøÒ7<²g=ªi¡”@hy,"‚R‹F.Ù©Û›KŸWZC3ܘt*aai +4ˆ­8^< AÁió–òß{Ç(ߦ𦕡d|+™ù¼ñ¬JJ=¦žó¿~âèYáÇÇ'RzÙ÷ªÀηº¼ú±Ñ/ y~x|Η³`ú>¸ï~5‰ïó1Ûs¾s¤Ÿ}ðmtrp‘÷Æ=?¡å»ë^_ \lýðDÞ3G:zÒílÌrÆòy8ŠtÂ[j{€ ÄXl™¼è4ŠÒAÀ|H錵z? ó´7 fö•lG q{fIÒ1ƒJMòâÓ~¾»Ú]î/.w—;_ؾ{ÛßÑáù¦B„sM$¡ÐfìûÛÓe$„±õ ÈN!›¢Í¼Ú¤DÓ®Ñÿ‡„bµU‰mZ‚AéP#XD\ì®.Ø¥ìö»««+ömw÷÷4ÊíýÝÍííÕõ[7š#íâŒeà$6jš¹ç_fõG@@™+K Â'˜ôõŽ9í n9Ò ’C± ¡ê$œ]s}Çã ñ#à±—œäjƒë9 HÛSiŠƒ^LË\EAùTª*Ð9Æyè7ýµ2V]ÂÓ¢/#ТÉÖñ¤Lµ™Ž’¡4˜Y¯IåŒúºA‚ c¶ÌµøFr„ñzΜ!ìèœ"#ß3Ùþuœàá`iÔ{ 9ÊBkÖæPKLí¤üG>ܰ“NIÑ¡’’)ºVÉYºÒÚ™P(œ-,áb+ :h+s‹€ñ “À~Œ–* ïPaРɱdù{×ŃˆÈ {f<ø´¾%a¢›œ(EŠ£mUiÅ h¼7 N*R¥b°&7üA6¶¦£)¶ÍRîcI[´M¶¦NŸ¤^T‡ºl(3)_Rš¥lr(UÎ-3Í•)s˜•6ê5bù ï»¶£Ñ–é–R{ MãœÙ1–på^nuΪ™ZÅâÁ̸‡b y÷±ÚÃ÷¸aÁ²Û–ìáºÙÔ k‚:åç ?]pXÒ¯¤.UYMhMÍ¢œfíåÙ馯Zóß,:¬oŒh7 WìüÖ~‰ý.ß²¿¾¹º¾õkG8 nK绂!î¿pQ½¿û|ÇÅôöNåo®®nöù¿8o°»¼p/âÛïÎ.Ï/¯vnÓèE¿PŸwþzö ñvñöÉ#ÅJzÚÎÞÍ6µ23õh«ƒŠ±ÄrÕ°]l§!SŒU}MÐÁ¦þ´±Å©Ö@=昶§«Ø„i?"j§û¥W=YvíP~¥5©¼ÝžëTbÂìð—üÄÈÅ]« Vˆò¡gº‘ z´Òl«-ãª8¶?ÄÆÈ 9²9¹ù¼ßíÎL÷_îÏwgúóŸ1_ö‡ä¯o¯¾þôåìâlí~Ö‰Äà¶­h£~RƒVÀŒ ÕKŽF'R5Lé>KË>CÂTó O£”’þÁçmMÁMLeë}I. S4‹0›Tü6ÎÅ‹Æ@-Ñœ2&²¶ôMÉQǺ….QÅpLfpʼnõƒÇ”Àå–€³Z²pìæ1‡ËÍPÊGâ§MD©][# Š\ø`‡´25[É>°iÖS{ ›ã,sŽM-kÕÈãKÚÓ—Mú° Ô;"1*ä&îçuËOuIT!†_û)†hßl‡–}“œ¿ñéÕ¯f~õ\¬Ïn_ŸIg'µÏ_ìÍQ×1¤ck[Cƒ¦Õ”à<š«¥6ƒÐФmçA‰¡vÌüÑïú©âð^ã n©-ä÷-n „ öÍþXúµ"a

á®êÌ‘8­âÙ™û¶s6©ê:7¦Ä’ÔPjï:0È.–iîlòîO‰œPÚ8Â,mžMžQhÀ5‚Róñ° D¬È€sɈ_as™©ÁõÀѾÍúGFõø@'£¡D«´é"H5ÑÈViÒL‹¶g#ÞLY£èô›.æ¾M§ ±YUB®`«–m³aQ¿‘l44ñX¼yî¡%+?-ÒƒX¥ö¢  t¿Èo•Ž0Ú!ê´mk'1aÐÁ2AÈ™‰3š •!Ã0«ÿ)U%ç³ËâÎ@RG¾àø( ˆ…¥{È®}XÂ%HO8QံmÚWx¬Œì²6ÙšIVS›,ôj‡‚,Ü1S—å¬/´-;yØ?Ôœ×iÓfÕ æ8Ch[MI'Iò&ž75Bºˆ•e–m_'-¶Â È,Ì2O¸I6Z†`‘k'õüG%ƒzÄ)`÷z…>ìÁ } A#NKh0[,£¡èT ½#YEFHßf•™†Ó’©ICp½Õƒ.æÒ yÿX™|pì»8ÍEG·ÆÐc€)RZÞÏgæeTóUm £‘Š˜I…Ó; wºÀ™1±¸t‡3´ceR¡ÖÏOvÔdÿåe:½»Uöa]ó­` žO"ͧ¡èï.w/~8ÁÍÙK¾j$yÌM˜4 ¯¥æËºŸ½ß>ûë_ýþðàg½ùí·oxõX6p/¯ªøZê½g¿©Ä—Viªf“ûá lfã—âgšojkÀ­vߟær}ñ&+™fˆ çÑR(˜ª. r”ïÔ*âEtS˜%¦ížŽàdYd¨8d=]²!9óƒÀûËËü*Z>¼swæ%ãÜ=¶‚ÑMÐ^O½:ä6 û¶õ¡Rb¨‰b ÍÅ1š’“H‘i½¬gZŠ8ÒË;ÄbÀ@ÆBZ·{kn!e‰)t& Ä:ÒÍQj‰—ÊC+É?RþÊZ›÷€£’Ñ8à$ÿ7³£›s"E­çâ03èGyJ=6t¡˜‡°]—Í乩›8¦âïâœÚÇÊŠ9ÌßEÛŸtXÉIÌ¢-ˆj»ÇN;§°ç»ŸàFÍjg¨°ÇGüµ W&–$»bÙ ›E23ÕãHbbIþ‘¤ø°%Ô€q½“Ù @öØÂì:Žñ^þDw`躣5OWТ- XPÒ²b°‚ã,­ /=€­ëº—[ŒiwÛä§ÙéúD,PK[TÅ%3ÊDÙ«äUnóýgíf8ÆIóN¤Y- f†Ývý±o$={y=y={~ƒ`Gçñâqþúvñš4ßÎýØÁÛ§Ë×O»O9Î.ÞÎ.áâ¸`¿Á.dîïÍìÙ}ÓóóýÅÙ8Îgz~v•tþiçñfzövyÎqvyq¶»€x½<£&oŸ^sØr­‰:• ‘š–GOGhs‘evil³á| 8b™‹ (ÓctŸ…aÙbK ó[dÊŒÛû“¢w˜Á ÝÆöœ"³Ë‘G3ÙÊt –Âä˜Å¿Ã®Æ™:—çû«KØwŸo/¯Î?ÿtÿÓŸ~ÙíwÿÛ¿ýËnùåë—›»ÛËÝùþšQf5ÎZî±Ü+s°>HÙݧ}Þ+6$dJt½ÌýSÁëʉ"hÑzކ”H¥<­lËq9²Ñ9Wò8»5›ïØ9É·{äç^Òˆ T9„Øßù ¯“2UÎθQrx-gF˨IÐÑÐ6°B#Ë[–KIǦe¢m«€M£q»Ôl~+ܰ|Ò–FEŽ¡¸X§,>’±1)2Œ9Gû¢„ˆÖÐÚ2Wv¦=ˆsš˜EH* e¿¥‚ýéÆÎþ«Y˜Y¦ýë,!›ÎË*4ÿdIZµi‡Y™A; *Z „ðH5#?dÃSq‹Uw+0¶hbÙ)Ù<ý€E«]^ޝMnðÑRb F²“¶• ”œ5€n,Lƒè&ù„MÚ‰–ÑIÅüUÌsÍvýà¹]%×lpÌÆ ª¬rÍ®%·™!õP/Î$'’¶rs•DÈØ™<8ŒˆF¥­BÓ…÷ÙÅ)¡þ8SE-#S"®aq@éŽûûLù[™…é—f¤V©—MH"ù %¸d(œD®£lX6kö v9\|ä aÿ’OŒf—N:ùΰv:VºÉVÒ¼ú² níaC({®[CÑo²í#¨,ø,£ä dfà(’Uõåé-_ÏÈF¯/¿`%m’¶©GW.'3D;3V¥`të0Õœ¤±àÅ!mli8Æ·ª*\|j<¦QóÙ”+¹ŠÊ¤ÌŠø¾wÀ~hÃjcþé%ïBÉk2Œ°u¦;Yо„§uTkßN(±eÔ©n¬Dÿœ_æ‘þí)/¶þúÛ¯hùJê£_ìŽø ª´äóãów‰Þ=¾øb,Yðüì=<>ÂyúžWf¿?øpÎÏN<¿=ã>Wó‘ È^JˆmÊ4c‘–øD«fœkÑž³Qa0”Æ”¡"1X?jqWÞ86íS>—àáï’å‘[¾‰÷Ò—‰ ñqq‰bT/ÓÎB]èc ËQ0Šu–øÆe¨°ÊÉV¾+'i:>É‘ÖåQ¡á{|Ù&“>¼V"¡‘æº2bM)è öøŒÅ·«k*|q}suwwé7·ý´Û]^ßúõ‚y&Íj±œseS+£á¢œ±!PÚ mÁVø 7PI° ãUŒóÖÑ·dÃ.ß—n1³ã\E¼fËhó’£ Æ”Ï¤œõJ²$͘o²&6au`FÓ£ÞºšT9í•N0C‘!F®‹€J'pÖ¢Z. Ñ›~âúíqàŸB+,Φ7¤3k8¥u>³h€ñœ’¥.¦Xxf«Q›³©HFÖÿjÃUxžÅ†=N£I8DLS²"¥ƒÙ‘LŽ_#Õ±£ÔJ‘ù@©…YhÅ YòÅF8 ,i3³|Ha¡Ìºp鉌qé¨*%þ{š6 F”§ˆxíV:j°ÊD¡–2Ö(E㤀—ä‰ð(«`ÕáGdD9ع˜iEÞ,•È£¬E 'RDH{'Ù¥‹Öiyc2ˆ‰ò;¶KƒÍ,*[â#hʉ\õH„9—SÞ°©§© WSIGðUŒä“S9uE©É÷“*DÆSŠz)%ïòÑ–ÒqØÎ Äý2B²ÊêÇN¨lŲÓKgæ&Kj½¥‡),Œb9Ü *–É*G:‡2q“1¤@^ãˆãüÏÑEX‰l)‚$?ûß|û‰kѶ—vva/áÖ5| Å¥ºÓ"'í¯ÈbŸ –“öîwó^ä€}—=É~wNÖ_JÝ_øÅ$~—/ýå;ºÀî2ÛßàÅ-ßa¶óµã~™0VÚü¾Ðoúµñˆ#a‘útÑ7ž¤nOl‹Ö³u ¬Ã¦Ie”’´âÖ9í˜Z–Xœè|ˆUTµPk¡‰æ7€empíøe‹ÒóiK^'MðHX‘¡0-ø¶üöC[ž"Jðž&†€ ¨ÊÇ@˜tÈipÈĦÿExé°<èàÛhQìÁ·Õ9÷Ioﯼÿ|{±¿øòõËŸÿáÏŒƒù¯ÿÊ­äý—{¶nÝÞ{—šÊH·®6Žÿ¶Ñ;t7é L1%©^f w ÞjÌÐlîX@ ‰ÊWNOPù•.¤ðÀ¯f‰æÓ“„÷VŽ‚Ûšl}¢0-¥óQ0•­Ô¡Ù‡ÆÐ±Å˜Ó)ÏÁT'–×OÜú(<Þ¢ˆ=æ¦1™G‚{@ß==Ö¸Š(Ϊ›æ¿Y„‹µVXîÑA_*‹ÕZi œVf¥"g²ÖçX‘“ë›ã%¥,a§dPCwâw²3Àh¦:HnÔ  @”z­jofÛ$›þH²q£”çÜ{ÍÑY€ÆªMC&b®™×ÃØV?4€hhº•Â)³5Z*€,ت€òu"Ÿb´!Cs¥N:È„”Z%xMEÌQš|%ÂL¢Ã8åÔ²ÆÂu¨˜³Ip”¢ š¦mšÄl•ÉäiG§¹Ö#­â°Ã¼š‘9Ù@m'@5ªîꜷâ¯yF£År†¢Â3¬©˜¸Êcr@ª7:ha„8镞-oOÝe¶bÏoù¼EqJIêŽÿ<%HûXÍÕ[À–¬QEŽÍ†2ÃlÄå1VÞÄa•k3é¯i{è*IU)*^î‹ö䂟Žh•5ëå\ÄNÕa€Ë,ðsyÒ£PU- :8z-:Ý"7„®Šî¢í8‘˜J` É_¿y(á¯^r½w€¡­gßõŸUÃY5AäO(®'1iŸ9%Î8Å—ayÖ=sl}þQ¬´!v4sÙ½„M»°É"?sðéÓ㣿Žê»¨cÅ‹ÂëÛó“ï‰ãx|xb;æwðçƒ7ƒ}z~òQÛÃÓÃ÷‡ïßÄoߟü¯çÇ<Ÿ{~öM†1åÄr^öû2|°ç·û6>-.RI†ZÛ´e(9©fá£&ÙV6Y08tVµb°Í2g³±²ÅÈåãyA™¬?hÁ6·oqËÇqó8εȟËC%CÍa¶gkÄÓh›åÈ^s³PrÔÈþI ÒŒRy2ƒª ý=ÒiÅš^­v0ŸBÆÕfßæÇßÀ¼ÿ|w±¿üúû¶¿Pùý¯ÿÂfþþþ¶?!ïÔôC*óSWÄçz•iÔÝgà¡\BFsg2=Øœá¾ã52;ö8y›à…!á%\Hy±Ž.)%‘hf²8/„QSöQC9Ââ-ù¥–`ÇŠFºÂ$Ôf–Füb¼Ä“ìf°r+æaf—"]”1?º*ÿLB× ¹ˆ% jÎ2QI'ó ¤mi ºÖPF:0k¡p /*iK›Õö—+ ô™f¢È”-\?~ѰãÅL²ùºm¨häRïȶ'ên ÆqLE»vW¯©%Á˜)U¶D´$3 ÏüìE*«P¾ËM}*hë>ôózÊ–‹Íüô4>T2˜ù¤ª¯“²oû–ßpøõ;Ùïß¿³ŸóõýFºèú‡ç§ï~¸á™ âÛ'6zn _^ÐÂâÓÃ#2%9 ¡Ñ3©¸Eô×(¥ªÕlÕÝ·ô«E{¡G=ßÁʾíÒïL¹ÚìÛ²u»dÁíÜ=fÅè¼Ú±|&~ G\màd†Hú±™¶|ORô'GhXŽ4G,¬)¢?úr‚lv¡Cl™Í‘z«4ûÑ «½¿¦êŸ®o¯Ù´ÞÞÝÜ}¹£¾üü…ALQï0ì&>5Þqå0ÍîÏ™€c=oŠŠãÒðùón²™`éTаœòù<3åžJ¥4œÑÎAë" +fˆb †d(/B­bfR¥œ:™áÖº OþLR{«.• ƒL…åà/“æÒt9êaЖxr²'Â.@¸}hÆñ; —½"ÚQ(g š ÇrˆLc¼L0ÄGGiТ0;¤é ¸¡š¶£ôE¢„BºR#Zdb3uoŒú%i“UÊ•¡SP‘¥ºI ±n©í#[z”V?‘,µòâ®?5ö .ÏúÊ]NPùäû‹Kv;ù)ˆ›û««»ýõÝõîz¿»Ú_Ý]]Pt{u¾¿<ßï.®wŸ.Ï.®vŸ0¾c‡ë6÷ì2ÖóËæŽ4ßYƒ GCvPçªa|\çM#³êŸîMU[¬-Ò¨£ ¬56/Ø©åÀA_¾KûÛÍv“ Rª4Â1œêW ˆ–Žvž§ hÔ±–·K"NdPr53¼EmÒ.2Q­D¤¹mÄ…dw×g—Wg»ý54~þåçýÕîëO?ýùÿÌvõŸÿåŸh„ýµ_/ÈXó lM*®G·}Ÿ~:£?–ÇS¸8E¶Û帣)w~„FšÃG¾ØÕæØ¬8IJºé¦ŠØ¡ßéM¸aszÌ·É„8¶ØdÊ|.EïVw.<Õ‚2¶ŸÆH©«{t»cô´]Žl2NB ³ ÎÜ(ê1 ƒ ¡¤°M1èÀ­¢iÂô°O~ùÓ.ßM„ðó«ŸÙÎÃëi‹ã‰æ°‰QC?%–F²¹³¶4Ͻ*áËy €3úùÙûÉðkúO¹Ž˜ð>„Ú¨xó—ÿ0·jü‘˜f3Ráó¨¦lUg10õ­ùOoÜ9aDyܤ6è¤;8ûß1¢_`³–åŸCc¼a™Ã5£'MÉ% ¸•„ßÔv¿¼„™ˆtG ŒižL’å_ÉÆ“'-O$· ø ¦Ð.ÃEV3Y%TSwd%8"¢¶ç&tT©¥~N¹¼x˜®’#Ž±Ì¹öÑKÎlŠs6•ó”Rš3†jú@¬ì3BC'*?ÀhU9ú»ÝBS®É ã+E‰T->L§öÍOf[lyÑR¡L)Vf;…ÔE9LóÖæ{þrÁ(#5bš”,ƒ}ºsi©—¾`䢗>´rìoP$䮸 åÜ9Ë„´{lJµÅ”ÌÓ«s_ùâø€í©ÍöÛo¿}ÿîÇCâû·§o¿~§_ýõW¢ýÿë÷oߟžžþýßÿõßþúëóÓÓ#6üª¹—§ïùâ’×W»Ñƒ°µËÒâ•×H°ùüôŒj~É|/#½-ip©ú¦£ˆEû±9F›¿Kæú³¹ºâÄU4[Tú1sdŒ¼´™£ÒˆbÆ10|Ο®«’¢¢Ï¥Ï)‡„ÐM´ÞžZ-JU38ógñ4ÆÖð8€7åÛU§0°YRºÙ_%Öìü@[m0SÒ®4߈t@—m€,6+[ÓÚšÂI¤7¥«H#2Ë1q³ÂÑÐP›/‡ìIü>p@Rg,ðÈÞbsð?0lEwnG‰œBô  «•>¦äˆE ZS`ÓÂ[ö»ìï ëå¶QNµÞÛYÙ}˜tÖkqê¢b`J.Ie7BEËBoÙµdžŸ–®î[ü¢ô:FßÅõ`¦›ÆqšEìwŽŠ2O ÓE[œÐ3ëà‘<0ëK T~káÕVßYœ096@± ¾Pï‹óaöBɱp/â]TPÙÿ³f¦£vÛñ1Dø'ÛFäšÍWää¨ì˜´õü߯»U\Ì:âü-(Eõ²”Aà`¼Øº°ì‡.´„’>îûql`@Ωå\²ÖáÈz=ø™ð鬌÷ó'ª~„tÕ(vCÍðâÆ€6 %6M‰Í´ œŒ`#îdTéX¬¥©©¥‚Â]$³Ùê˜Lo%Òd¯n/v×çû«‹»ûÆâ_þñ/û›ýO?ÿôÿôç»ÝŸÿü'÷ð——l”YÓ½÷âx¬n$/½•åÍ¤ëŠ Ø‰“f×é“u¶üˆvKŠk†T¦4X6E—59w¹`+ *¹P>X.Øð“~XºÜ¼[¦19÷{@2?c¿¥–ø ¯vŽã›E#«¸¯UséˆiÚ¬´gwƽ­å–ȇi 𜟥㶦–¿Úоw-E˜ Â‹ÐPŠP¢8K•,*v@s16,~úÄ @ ÝöààN]ì—nÖ4³nrëßQQ4žÒ}â¢Ïd„¹*‹X¨0͍LêÙ|ùÛô=±²[4T,5[™•]ÐϦ–AˆÒ?R$­L±ÍFD”FtLè9BÌ,_Mj¿Î—!“™Cb;Ï#Iøêc™<¹UÁK¤ú!dbaE5ÍìŠjáDæ*>ä³ÀygE!Ÿ;$Êf ñqøÀ~[S°„›LÎüs kž¶±M;´†¥QE¦Æ;± ~ѕًÅÒW¢»Š7Ê©¨¶tkÇ4bÄ•¡=ØæX€ÒíŒÛ––V5(Q•f×Ô‹Já)…?‘‰ÀK®—»,„yËo»À‹Džv{Í[û4Ú*:Ë„à$;޲^€’°Èöж* Œ”œ™Yµ ¼õ«ÓÀGCÕ]Â%0F t¿ÁÄ@F… eã3j%ZJm@¶}³øïRHé>osæúBP;%þi &/¥†¤dfx†Éè¸O¾éër‡ÒããÓëë SŽö=oOˆR„Tzèìáûó÷oOÔðѯù=ó Dòªß¿}£Ç¾}û8|gqþþíÁÇz _%¬qìg? AG¿ÒR^¼&t!—*)ùþýû§ç·„Ÿž}äÖwã1I%zÊ1Ú`œ’f$´ˆƒj³`1à¨áååÕ~Ïj·ß­ÏØ":†´æ_Ùóæþ<6bÖዹtM™ÂHÛê¢bÙÙ¢6êFdN>d0ä;ÚÃÕ–—rÎyúˆÛvŸQÇ`ÓBïŸØEë…^] A&Ñ:Î.Ýd\Ý^îo.öû‹»Ï·øþ‡þ‡ë›ë¯¿|eßFuúåg"ò!„fÁv²T ŠxN”’®PF…¿ŠÀ…/@å­¬AW„‘IË"Ñ”¢( …΂2=¡‘k'‚¶ãäO7}Ç«åížp[Øl‹\u•ˆ™îÛÔKb˜5mfÆi@N¢†H÷L©ÁL¿4(hˆ1nHjkÕ Ë(‡¿64m¥¦Å*͘5C®Ñ5©@ƒñPŽFZc+K3"@¶\„nVDˆm¹ÎàhU1j#åmTAømZ *…üOËžÒÉAycðH5?<ÒÁÒeeü{êyéÖø áŒ2¤Kx`É¿GÅVZ¤D°T I¾ú®ç[s•?¤Ñ§©Ø¦´I]JÃFÇ}7öméDÅ"Œ}ÁÐU¾†6Ä€ÍÊœH¾WD’næ!YÇ ü±ossë5ü2•–°^™MäSoµÌtJþj'c•ã!êæM’µ³‰®ŠQñŒ±§#ËΠð6ЃdpjÇ¥)XŠ=m ©Ñ1ÓX„ìÛÊYhÑšApšn‰m$]D”¼ô“D¦üLseb™#›‰¤Ð—g#v+[3P4೦P{ЋÔðÔA™9"•dæ2H”È‹…åœÅ&9´aëqrË{ëkîÐ1B›¹òª 'ë•8œ Vüí…-I‚B—µxp:K7œmLB'=¾nÛ“Óz’—À&s×=Voh#aЉl”lÝ”¬†Í‹‡;Tüa†×Wßvqþä/×?"½Û]aYF÷ããË÷G_ÇÏûÌhpÉoäcΠæS«ùÞ¸oßÞüЂ_&÷øà‡Výô"¤O~¾•=_´}³¿ ‘ßïúöíÛÛóë3Ù¾½¼<DÕAŶZGœ¹oó-ÚÇÃÜ€-PLÝ’%Š”Œ^(`¦cì‘m'‚!À¢_äË\¥%N€©AM™É÷ŠUk!Ƙwœô~Ê2 ÏXç¾íÄÔvt!s’ž`+9\=³öÎ"|¸R°2ÌØpÐf'ÛUˆ"º>š.Íòâã€\vUçD þ'°º¯ÙCüAùe¶Å)´´‹³P#U\Ydã--Àg8´#5X¤”¡Â½~hX?/ˆ*g±¢fß6‚fq i¸ŽÓªÑ-*Yb€ø|K‘Ëÿ]rƬc%;…â.ç³¼ÿëæ;±­Ý&#Bm\9 25Xt·ÁÈ)ꤴ̘ƒ!1³`¡¡ÖdÀ2;ƒeÛƒ‡Ø¬ˆTº£ôÊÇQ›}[~X²)Œ®}^Ÿ_>=>Ó­Ö]wéyöо)íí»2ûþ6²¶ž ?”JÖKóȱÛËÃ:t^ü1®ü®×“?Õõüúä¾ÍŸçúöë¯g¯g/´ªÏä¼¢Q¼³ÐˆàZ¥Ô£ƒiørp½¦ß¨”ß]Ƕíjue}Ù¿e 9‡„]Ì: ‘Ä7¦'ÃÙV—È„æŒú‹Ï…¦,¬ä!–§JOmxégŽè?;ħZV³LÖ+‡à•O¿f]9¤Ÿvט<»¹»¾ºÙ]Ýîúå &þí¿üëÍÝÍO¿üüçø Mps{Kä¸t^nÃ1’,\3úŽÑQÉ lù«P‰."e®1WyJ ²(³ŠœÑsTÖk.<9Ûæ–‘ɼ²Sôf³Ãƒ¶ Zkßf#Xñ³ömí¤¹oÃÞ|Þ&ŒÆƒU…bU‰÷é–X 6ð¬e,lí0ÜIÇA‹ºs*V)©­­ÈŠ˜T”Cd¦~:#-X[lM-ºÞÉe‚8‹n'X¥ãÞk•~?$H[¯¥²Õ-* ßÉ1Kcuð›.¤| 2udÖ›ªñÉÿL[ŠôYzƒ m^Å!Þ½NºÍþËû{±f²`­¢6ìÂønW܃µE±g/´.ƒ›êÔ&´–WëE„Ìÿ¨}Û‡ZÃ]üœ;ýþ‡íÛŠ2‹%S‚RGu8mº )ÉH§)‚¹o«ã>Ù·½‡“© •Ÿ©”žX’ C%ØÒvÞ»îÔ´‡~l‹m')ºM–…¤‹žÏ Ž-è†Q~¡뙯y f•lÙ`|,)ˆz‚IŠêXmžèØ2–‹Ct€qê´á J#ÐÍ‹Ð8¥ ÐT³v‚Y.cß&Ó^¬åaG™ðœ—iOâå¿!f°"TiÑAåbI³h€œBýZ(“¶9­›>m·FòÌÍf¦ å¤ð‘§÷Ï/ÎÝ ùþÿàûÄëå…-¥}ÉÝ~ã¸dX² ÒD¸t©×ħ¼æ–>z~ôIZ±“Ÿ=e 呜OÙÈfWǦ=Z~’áaÓìáÐüõ×ß^Ÿ_¡ÙÇ=<þ÷ÿã¿}zþ„<>*lœÏ~x‚ú:ÎHÉfK—*n@ÔÄN ]^\±_Ûﯮ÷×Â}íá¿U˜òóòD:Z}MP÷œêMçK €!×}›ïÚÃ;ù!–ô”«ÊX©Tˆ„É0ÜS@ll8®œ yYU¥Öj—ŸöÙ·ÝÞ_³i»¾ÙÿüçŸ1Á¾íöþöëÏ?¹o;?Ûß\ƒ­¥ÉQI–ÆN Mlö¿£[¼5àw)3•K TŒleÊ]TÛqô2±… Ÿ`ÉÔòEƒšXÕܷ鼕aòR³†’¢rÔŠ;°8'é–X ³àa¹Ý\„Ø“Ep¸X14mK¶£€r•ƒ5Ða$È4=Á‰©•mq%Ê1& QŒ˜¸¨Î;­r¶|ТÖ.J™¦ãò‰£¹P6-Z÷m³,∙z¸osZÎjBTkØqÎz=f¶I-ìèò¤%JoÓ÷¨—ïe41ÕK~úiŸŽ‘°äÃXÙHŽmÄ0x2E˽ÖQé’G¦Þã œˆ5È™“l—CÔXÄ'2]@ @í,ãpH[©-'²¢ÌbÉÔH+NG–OZœ¸XXÖV‘‘‘@ZN#YñT.8L´ 3f–‘9Ú¦f—åB»›ø›…n‹U¸¥ ë Ìf‹Ê—(½2ÐÞ SÚÊBcó½6m^|ÖE,Ëûú8yT…YKå_\ŒoPCªÒÌRºX`œøúMÑJ7@{Ø7“í ð¾Ç2š"×”–gB§zYX“•Z·=Y’ZˆPmwá¡`s¾[Dá(¶a%³Ad³o#,fE&E[ŒN£YØaù”áÐÈ(íùy÷[Ð]÷[‡çmîÛ(½¾¾&M4 »]^¾àÏÈøÉQ¶ky,FWæã1Îeÿ>‘Ëom=½² ƒaꮎ=™ûí7é6sÏ/Oÿíÿýßi§Çï¾ÓŽRövXkªeþµùÈæœ-!^`3Œf‚`m„O绫ý¥?#Áþ-û¶}>U*TBp4€élåRO*?íדpXàl–QuP;C¦û6O±EÀu@Û‘Æ5Œ8ÞX.qÈZú;û6Œ3ê.?]]Ÿ3;nïo®o÷7w7ùÇ¿Àÿ·ÿò_ ?ÿôåOús¾mÅj‹=èU2ÑŒA_dhb"]Ñ g5&8Œ&ÚÓZΨ*Ñt-8§û6@ÊÙÜÁ{Qˆ¦Cþå•5²¨/ŽCÞþ ͇¦ÙsÁ"]UXêŽæ×ù}’ïÒ-±@gÁC¹DÊ,¿Ø,QÎ6†Åܦ ±4°8%l˯÷X¦NlÖ;Ìbpcj¥¤™Vƒ>6Xùr¶|P#EmÚ–´’ÃæôHº,T ,Ë[Tfú æôhúÖÀk_³ô jîÛ:n•gÄÄÞ2{BlÓa¸Ó#(üªr‘ÂO»ÜU”^Ø6Î’,VVAëÊxuI 䦜uÓiz©lu·ŠáªÐÌvD{Q)ébdkßV™-"5€LÅJPêe,2dWË|èb´ReÈv€FXþB”FLÈ@>åªÓ+ý²¿ˆ…:zŸÖþV~ñWZΊ§iÑMT¥B3{ PÅU…Ñm2^Ì ¸œ{ñ9ðÕ@°¬‘6Œã`œSsßVw=†|ø‡ GyÌí¢ÅÁŠmmʇˆû’Gû¶ ti´ZP-¢Ë»i •ÉY„‚Íq´oúG0¤Éey$;&Ø"m}ºo# ýu(jÀ„¾ömdá?æyY°ömìp§3ˆÅµ,½€|ŒøÝï6DZéÕK9p탼s_¹QJ·´dö5~.á™”eÃ}Ѱrr]„f߆¥oß¾aÇrlðžþÛÿñßÑýþÛw6|Oß¿}gýþý»Ÿx€åÓ»§Ç‡ïûàw?†•ë2ó(ÁZèìÌøºØgãæ¶-Ï%ÖÎÈÇVœÈeÚb´ )õDF3é0ߎ§Ãæd7Ú 6ïŽ÷m¶¾-€UCÒ>¢˜I¶¿ØC®±4ÄÊ6~TvŽÍÏAÃä…ð;>ܺ]ßú]*·÷·ìÛHÿñŸÿæ¿ü«¯“Þ}ùüóŸ~!*÷JìBlyêJÙ…³T¥ ßòÕÄj&ÐJ P±Å Ò–®1‡é¦ b6ê€9ø(šQp¸³‚ž§U #1^ÿC‡³!E‰‘;ÔŽp$¦(Å ²túã€Á\ü%y’n À@'‡úöm,½mÏ”ˆ%¼enñQT‚¤ùmÑ –÷E­&Ì¢ÌÚ)Vv”’faZXZþÊnÝÀ¬¡Ž²cß–”,ÂÃ&ÅM8¶–ƒ‘ÉÔ‹Vyó´²5ìÿêG'û5WÏ¢#¹^ÇUÖÔØ‹±z’â;fˆ‘s´4ÿ©‹UHØ£Ô¹!‡“Ö¥™ÊÙ*´#$:ð†Ð”œ§)ÓBN©ÇxHJ%LÖ©qˆÜ ÙiªØfU™é‡8Ñ]8Qé¾ ‚…Þl´¡SJâ‡^€CÚÎ)=äê#'ÀÖ#R.òÃ$å×XíIª~Œð$ÿؤˆv°3‚®TÕµÉ0Åk†ƒ tR ö¥*i"…ŒcfDÓ¬BVÜv_òdcŒº±Ö+ÿ\šœÃð¡´œ`Yjá°CPÐVß«ÈömÕLþØ>†éý~­Fiü"Pqkj¸Ã³Í™×Û}Ú§éÄíX…L™vïömC­¡h$CÀJTVÛ²JÃl°œ‚ò4»YsY;½ƒN9ê#¡M­äH–‘1ÍŠ11UôݶˆC+}YA®±•qФÈù²hž·ußÖ×I}·Ùó‚¾,/´ |i"þÎ}Šƒ‘ÑÏi+¸ÒÃ.킌*ã ì@¼ô•M=nžÄQúàÇNß^òÛ\ÏO/ýßq»ö⋤߾}G˜}ÒÀÍ哟f…þí·ß|dçÇ °†¼»G›BxK0¾ì˦í²û6«ãÓtÛ•íZÞoå^¦ §Bª%Ëx"ÍvÍÑ™v¶®6Kdàh* ‰¦¢Z6QŠà“ÆmçŽYû®oœÛd–DÅmâ4a†OšM[÷m7wÜ®ŸÝ¹½¾»fßöÏÿò¿±¥þçþ§«›ëÛÏ÷_~úJ䄃a_XÆ#ÝèzäGˆä +.~ß–ˆ“ê)?K)ª"ü¦%(¿4é¡h4ìÂ…¨úhа8 ›#-a‘HÃæ*΀G ƒV%I[»Ò¤-Bañœ–6ÝI kÜÑ>r7òMk0Áè-–ä¶FÛ Ã?’ɬôL·Xº'µ2ûh• j¿Jð°ªp¿2§yUÙL?lÒÝ·‘¶Ô €˜ÙU:xYkÔ13¦–—pg6Qά_^ekà¾Íô)nUHËîÛ%ÉfÂ/Ô]æ}òx‰u²ºJÃÐfñ–¹M r¦{ Iõb-ˆmnͦÅã†'u“•MëÖ¦ ÓäC`ù„ë~¦‚«âœ° 'Y ÊL?DUšVlÑ[­4…‰•š´õB€¦.N¼·è(ÈÈW˜Sy”R«á¡afS”*?¬Lõ-޵½¡ÏF&U¨Â°Yk…É¶é „›@­HJ¿¯DTÀiiÓ-@#¬Ô‰TÖ” ²‰Ä¿L ˜ •GT¥¤°Ù)£q¼‹Ý6%ÍÚbyyïNõébËXO^¥"ûàž’aDÝÿ ^‚÷¶)_óÍÔ%KªÍ ‚ú²R¦IZJÚxêï Ø’aâÉìèèœß=k´"¹Æ|bˆ–vR:›4x¿o35M´‚®‰ ‹=cFL˜k@£‰vÏÉdßæ ÕãbŽî†ái(N™åŸtšÎÅ95j¥n‚>£RÓçmU_˜~T™i±b+šmZ±EiAg˜¶Ómól}hj²‘]ÜìJ+¶¬C×L㔊M¦d-7S#…̤ècN¢c™""„ðš™îèF‡ö¢tOUcŸ¡ËãóæCãm¦ k‰ôþAÉêtò¸xì³.˳«V”Wµ!ÉKѰŒÏ“+¿¤Vöì]SùÖ“:so“Œ@%÷m~—|nû $~FÐæs JQSšæ±} h¨ä`ßmLÄ{-ôE¡ê(”S:aŠÞccº] A6ǰ¯HÃ{~ñój¤ÞªÃÍ ù( ZÔÚ‘: y¥Ã€È•««1ÙV7ëA{[xwãFæú\­½»ô<}˜ÅþtÖ×IóØ’vN¿¤Ï6gµ“ÞHT–õg ú †%£ ik¡iˉ îXTh/]=| Ox6oÞDzÏÞŒÑôüíÛ7Š~ûíÛãã{;?ßðøÄÎO6È£è3>VT@L¾„E½è5ªAYYvŸ. X ¨AØî Ò×¥Ótqø¤`íÛìP¸Šñc4«Öh¥GØ ûš±3;öáE°9ù+qK6ݱeßv±÷·bî¾Ü\’þtw{sÿùó¿ý×;¿¼øùO¿ø«d·×7w·u‰‡N&bû67ùÔtömŒ‚I¬ŒHÑD†•qN¶O¯5`Ý—@”CcU±u&”¡¿ó°¨®”‰2›–µ¶% o+úËEÁ"†Íƒ)þ)´””løƒSÀ1È!¯ôâ“¶H…c•–6ÝdðÍGIô2P‹Ù³9Ü‹J•l¤-%\áõà¦d×Òf­)± ³XXEå,h¤‹Ìcm6ˆˆ=;;pØÙ–ž¾þ}c²½RãeÓÜxe\òï:4 ‹ÚG¦DÓeA[›8)%åêUb €Ñ Î€c•ߦ d'ÆD³gX”ÎKcåñÅ\j¥–…U£¦‹°ì-ÍVÑÑ'nF,Ö‹\†^Œ·4ñ`EjBÙc,'ÄÊVXG[-èïÛ*½¼KÏ4aúô:%cJB,N±”S'ZQw)>ª^$‰°tù•©*¦‚­› M§trÚ=œ# 5(çóæ‘ÙZð1[Ë•©;€çW$EúŠá©pò˜ä)‰à¾-¹øˆÐ)]¾—Nä³²DêÃ}«‘ Y’9P³€ê¬,Dý¶-iÍ.\sß¶©L9¥Q  ¡ÅØ]×)ÀE—´;Ðö„yfNÌŒØsC˜•XF@é蘭ãCq8YGˆñ±D»ÿÐt]·—S âÜ· iY% h/›}Û~¿‡)ƾmª/;æ^’?/þ™ü&ÞxŽ(j˜|YšZgCi¤9Ät¡)[‰}šÝ[V7.Jì.Î}5#/•ú8¤|©Ôwk½úóö~]û6ß߆L7kV x‚ãG!¼µÁº¾óg0yÚ¥ólHvoç\ý\ÌÆ L«ÿFÜ ¥™í…7yÔҸ咓á>ßêÛ2Ô©ô‘ÑBcŽ"ËœªHÔ“V°ÙëG€—1t¹÷=o—lÚöl²Ïï¿Þ±ûòóçÛûÛû¯ŸÿëÿãçÒøùëçóýŽ­Ûõ͵aú(1ÓͰÆÇò飷×3›ûí-?)»yÛ¬Õa;7VÑùPt6¶”SZ#«âé¾­2]W¤“7ÉFc8ŽóŸ>]]]ußÖsÄšAÈ: Nƒ <“LÀ¦7?Á@T¦B)%ís ³Ô/]–ÂÊrÂ: ÈYÝx,oꥋÇÕž}›ãÕö—Ç¿§˜ŠÇa Få| o`Œ“1dqÄ:=ªu¨Â´ciì,›6ðl&ù¥à¬,îHcbµXùÞ™öÊTöÀx’–øF=iF/oÚÕ:Ú·ñO{Yb”éʧ“û\1ÖÈ4atòF•ußiËYØü¡Ë)" Åùy~G³4tFHÌ(›)Ë]lFdºoíÛ¼G#[ù-¡ÿ5§S£ÌÔ.%0cI#¥÷M 2@r +Iû(=Vû·Ô²-—(gz–±P±aSÂD#XY¦VMÑdY³é1ª™À:9¦itÙÚÉò©aoéRÃX8É[À(ùt6®1d—Š#<’'òÀawsv ™ÉµL)S£ýG f€}d]4†Ž+Ä¥XX‰ÙªК™Ÿ0Æé, TÄ´º±p‚ÚCk)FÞT£‰ LƒßˇªmJƒCÉ cöÈ)¨ÇêÂo`Vu.\.›IšQTGµ*•eN‹¼Š‡˜ ˜*¯´E ~¼*AÁÏuÕ‡€<ÖEÜòï^/Ù—·ñâo¤„õe¡j×r†“2‘j;s­63,/¨¢‹¹ÂkÁ4QÅËû}8Ø8²ý(§m뽌£I0‚;­Ì¬ô¯,º røîu6û6$¹íGÑï pßæa|éB—›ÞÍŠz·4”ý±º/Z…!aE1Ãâï|íÛ,Ži‚e_EÖz¥к¯îÛžŸŸ!žÝñƒ×ñÇp£#a«1f¬,þú¥qþ„Ãã“3üù…ˆÙ·õÛæ~ûí;¾l–|F]]{ƒd„1…Mx`0q‘¬•êpB„ Òás ©WÉÃv‘©…ÔÝBÆk…SâÀfßvv¹?ß__\ݰ/»üé—Ÿv×»ŸþôÓý×»û¯÷ÿö_ÿ ý«ÛëóK‹ju´o‹7mÔï];Á¶Ê5]Ððƒš’« ”ÏÀ꾡•i k:öm([¤åX JlƳñŒpZŠº™Œ -Dƒx,¥µöcߦ͵3‹|…kʳ%öƒÉ¾4#8ÅAƒo¶á•nJéb0[Z®=œ*PbK=ÍB¨Qc§PÂ`M£6þ„74°„0f>‹‘›Á1å;0‰È‘%¦6EÞ¤MÈ’fßf“w£æíÛÐÝîÛº3³æ@ºðv¨Òa߯¿Ü%.£6³ Êùn·£#ÈÎYMÔ–êfB¿©­tì¥uBÿmÆÀÊsÅOfcj”B¡IèwІd]‹Ñ„#«’%ìPå…“lñ!ÄšhŽZǘ"ž“Tsdƒ–Z‘ex™ix!z®â•[SŽ´¯?Ú·ÍÀDì,ÛÈ'–O²àÄ‚>óè:cÀž‚†ß±½ͶÉìÅߦ?¥Ù·)“®ÅÀi„`y¯5RÄ6£è¨^‹^ d¹HlËüËN‰z$Õr¹o¶¥*e‚-”Oºø%NÄjæI´åCïÇ#Å®³G¦F )]”Jcs ˵ÿÞ‹²sß–^“ÇðÔ®Œp]r¥z¡å}Û²Ù4j“á±@éå¦Á«fµžŒAVœR“îò-Ý,ݵÓô€2CV×õNS4¥E([EËŽöÃï‹0cßFSå‹ô»o˺zÅ6¨’ª{ŸŸ}[vB1¾®ª¸öÃ.RäNÊ[rL2Âiâ*LŽ3:“‹5Rƒhæó£/£R…«Œ× ØD‹*ͽ†zýRŸpq¶s-µï^ž ¿}ÿæ¾Z¾Ú÷åÁìzñåVëÿÛo¿áè!ߌ´°úÊMïçMxpeºÝ1l)ÁÅ­× kDÆþ•nü $šÊa!/݉˜Û y6fÓX—ç¹Òʧ-5¼»>Û±o»Ý]ß^í¯w¿üåOIþüõóÝçÛþ·¡w/¯÷> 9Ú·ù´Úõú5c?Àæ2ê&+á[#ßh(Ä…^F˜ý08Èv/Ò" ©03¯ÔµÉSó¦§(ã¦M WF`¥ã³~LAçÆÂGPVÁáN:Ì‚•îNêõ^ Â÷må/¬¢-Ô)³Z)L£ŽF#ít*2|R’sª¾¸4J6Áúo¯™#л^…Ÿ–VBÖÏ@SËÖHÐ#z›çìòB-XTäüÓ>ÏÛ®ïö×þ¶ÕþÏÿøû›ÝŸÿá—/_?ß~¾ýË?ý#•¾Ø_’^úã^îÛØžQ÷¾vLƒrÂ…{6ɱ¿¢Òš[¤‡„á¦+Ê!í0ê ³nAG[ˆr(jiSUæ÷î¶Zp« M}3ˆÌ!©ð\SšÅ)¦Q²ÙæòÔ¢ ò¶­Ú6cßf¦¼ïÛ^iÒmQØbÑ«vÛÒ-ÂÇä¸Ã«X[¬ ˆà•XÍ›¤0CøWyH[ÇR³3Zõý™[ ºLÓbqȪ;íKr¡|°.A©1Ϧpd¥FÍFÛ¢0»o[ÏÛE[á-HçÂbÆìr¯ÙñI“RQw¥›¾–WQdE³r8HæHA"Lˆq5H-DÉpäoŒˆfIꛬeÔB‰…åúD‹Ú5»ø‹°8æ€,]lņ4M;Fçp–…Êol®š-~äh'û¶Î°D[yÒᮄ¥U5”9ðh5Ó¾ïƒ<ñØtùE¾P‚ÒqÉöNÅìȬ}YÒm½J,;µ\TR7ÇÌ¥ZTNšñ¤YZJºìT †Y̺ÒïÛPË#]ÓìÃÙdñ€ç‘Ÿ¨…¢,Œ#–›–e =u¹$ŽÇkÝ·Åב$i-C7 ¶ÆIAùK¦E‹‰…iå#e²¸TÀABÅd-ÞDUJ¢™Ý ¬¢”BÔ»ÎIùÐm)À2pVï;ƒX}öæ7k°û¹ÜûûëˆÁAfŸï§Í¾ Ó¤/¾9l5NmC^4óm]e]=¢³¶Z›PfUíìlîÛØ¨y‚‡(d¡- \º9嘎RÓ¨m–¢N·F‚3M’CØ=ƒYº¤û€ïß~}ó½nîÛÀ÷oãýmm¨ÌMöv~ÌÁO¨æ9ÜK¿-.û\Ÿ½9À§ŒÊ<Ë˲m-ëbÕ9PHžÎJÔ¥0Á¦qhVË4Û(ð »óÝÕåþÊŸ\ýòÓçýõþó—û»Ï·~gÛÝÝÓóÂ!ôGoÑ ±Àærµ]üؾ­ -=ã8Dc¨ & «Ry£$ÌÒŸ«Ìá¤Æ\Ê„’)2¢ÓºìÑ™Iu<0‹j¡[~)£û £n¨)®<#½j—¢f¥·œ¦Å–ù•!¼Ö.¹µÖx€Mш?DÏK¬‰]ŸÚYÖtª›Le‹¦Ô€œœ›“Gf,SC?åö|ŒÁ=FšqŸþp¿è/ß³Z*ë×»° }pqOµŸƒU…Ýžûõ8ŠzÒi‡§À^ªPúÐàÓMja†L˜óè¸C8´B€Š-Tš³¥²‰köAlA#’È‚”Åt:H. âT#J¬…•¬œ™ ”.û·˜R`D²dBGuJ¨ŠD`‹÷œC/“6b›£W&<éL9rí ùÁRÁe¯aVh{yµnEò·1Z¶ŠJy(Eа-Ï#Èè÷ÛQ¦‰Y¯Y<ÒàTlÕà(u` Å*ùcDÐ7£C'®\¦n¦x†ìªr¯m!! (ue!¬˜ F2 F#uWkÎ߂ޣƒYâ$ še"&‘°FqN­ÙÈ-,å?°'Z$`V4h¥EsVñ¤ªps‘ËaãMãÓ 'sGv"Vá¹ã$WP—•¡=z–|]wK³²ª†ð ò ýKvèC%)S?‰Ýœéì{Œ›–C!vÝ´„K,f¢.K#ÙZÉQH&G¿^-–yE%º$êU^‚ˆRwë˜0Fä±JÐZƒ{n½¨ènw¹÷ǯvW×W»«Ýåî|sÅFˆíœkŸg]ß\ùe·7p®o®#¼GmG¢ä~wí§6QGkÇ®·?ÔÏîw¯“3þv¾È6§ar…°–n žZ¤5G#¤šKmÃ(¢s¹ÿ„­ë;¢¾¸f“v³¿Ùÿó¿üû¶¿ü㟿þüõúööç?ýÌõ½üÑ€s߆EÒtY< #˜Ñœ­5¨¢¥ªM‚„¶%ÈË˸›E[,&©ÎØ$w ˜m\ÇŠ¥;ÈkÓÍZä™>`ã6Ò÷¿88ƒJV DéÈÅ6›ÆL’«t•Y’”©…ÿ•\î` 8†r²9ìñî³—´Q@oì˜îîAÆRl 4€Ä3¾»Ùô»wÞOOþlœr±(FE &8oîË+Ié’„ÙVJ)qb‡¢ µÚ‰Ó •ÀšÙ2²ÀÒ¬¡7 N0¤«k¶@lëî¤û¶D1%áºÌUkÃ?‰nC"èÕ)”ŠV¬]Eÿç>1§B;…æêÈQ\#=FÃ1\ïö&4óÜ“=›³-Ðà¸qà蚬Û0õ»ˆmö}b¤vŽA©­1a œÚ8ÉkªBä;‰jOÑYÍáh BÒº¶) H?Yë·Ì•¾Ïž­¢Þ!ÊG¾* ø=–À‹³-Âr]4ÛÚm9ÅïX•/g)®˜WÓ­ôÊnù ±ªúHáx8>LÓÑ"ÞQ?¥!ÁjÀJ>ºà„?¨Oå¼ÚE×¢ ¢"§–·t§Uhh©î7b‹.±²K«¨õÅÌÓ…šõÿÑÀ>#Ù#§ÙF¿o!2¤.¸|zzBxŒÚ!–qÞÕaÊÖ@,…‹Œ¯éáÓùýQ0!oŽ@Äê1Z#xŸ^½øæl–ÐÈàÃWiÓIÄ–aþÐJÓp¸‡4:×áù›ÀTLûQh - \]¨ed(ÂwR+Îp; ÚO!íÛ™ŸwŒ‡?Ø/þúÖ³?«õôø0µ¯06ϯ~­œoÂöÅÖ§>¥ó·¹h¿‘$YRÍÚþ¨’¥F”FÅ"l+•*Ï ÏüζO»+v…ìÕ²U¼¸ÿé3ûÇû/ŸoïnÙTÞÜÞ²/õã VÇþŒºˆ½ÍkqL;ñc µ)“q3º³-jiGRéÅlJ“¯S…YesÚ( åÌZ²ƒªÞh€<±lS«+[É v¶i±$Ñ…ÖÄ!êC`M‘ïÌ ŠfƒÊ Ì‹,Ç•øé ÎŒ<%[ËKLˈT¬Ãà9¿‹R™¦[ÔÜp¶Áj‡Š•H‰øQáŽ% ,+Y,³Í‚ÒúË ¦[fQ•¦'Ø4ˆX2eò1Ò`¥ðcœ8šò¼Fë )‹Rç@„;,*($øÆ  ¿–¾"«Hé™§¥K@æX–¿²ÉÛìª× ¬Ùw€¿-J 'ÊZê5UizqŠˆhéÖ)é2U”jœÁnú‘:›¸™‰%y"¿­ËŠma}ˆmÑ{±¨á„ù^†`ʉ¥ÕÈÅ–.†æÔ 12ˆžJï,lí,Ú8¦Ê–Ö™9·aqÈ;jöÀta k0¦Çbɯ>ÚvÖVæclŠ1'­ºPæ=‰ÇÉVõÁ*s^ÔÔÊg&°E ë-oîB¡µx$+Ì1†WWD[@êEqh¸-òI]7¶Yíç‚i­F)ö4£ûT*ÂCkÀ§Fžr€¾Ô=¦ÕhŠ”˜Ä‘g‚J`²k¿N’ÔÛ§6B;ŸÃym¹<÷ˆwìŽv>r»ÚSzusµÛï v>Û]ÝÈ ?©û(8.ÐÝ_’ž_ú¼Ðýrcß_çxó¶6bxó^aGÌåŠ$L*L&b><ûtyu~yuv}ç·aø[¾0ºÿ§ýçë»›¿üß¿üôåêúêîó]¾1íV·Ûß¹ãÇ‘5·LF‹d5汘%¶2™ š]ÏÛ »yk™Áû1Ž 5WGM#q˜‡‹Ã)£ hîó} â¨ze>DKÚ mJ“V¦o8h¶ü`¤cÞ,FÞyQÎ,"}Ã&ÔÆÚ^FV ,»IiɃ:@nG0e#öø8¿+y“3?ÆèÕªãH… ôâ@œX®YuŽÃXh¶ü¢üQ»ƒéçI$3âÃZÚª©Ê®Eù¹y ’Í>l0æ`†ia5½>xzz‚³ãâ:¿s~¤ücw¸Ú5i.ƒ]I¿nlô]%Vé9Já€hòšŠo‹d;aÊÔpbÎ9íÓ´¸sr©B%´Ó(ˆ%'SÙ7ß–§VVÔÚbáPwϸIÀÝ¢‰ÆÁ sLC‰O—{ç3SÑ¿V$¯Õ"DÎè|»›ŸQxñ'¹„¿M^>ßðæ,eáQ†Zß¿SôøàßëËËã÷G¢y|xðò‡Ò“+•õ"ƒ{«¡»V+÷±ñå§½û¶‹îÛü–Ý/w×·Wÿü¯ÿû¶?ÿß>ÿôÅ—xo¯­½[Â7ëëG«ÒùÜ žb:D1™•ÍæoöCT}+  G{ͱ¸•!Ý€¬ÃÅŠF²@®Ž•˜€^ñDW/u½˜E¤6êÖ]û’ªžù³¡¾ÉT~aq¶–‹z']a•é¾  ¸P˜®¤Š-ŽòÀ¾½;Pº—±¨ mm\kkZ#µ{¡¬Ÿ×¹!ô9`eQé³ßŠ€–ãb»²$QÚÇå™íˆA4­À6øZƒî¾­×ã–‚E«¶¡If¤HÀI[A÷‹d-𣾠AZh XÌm)¨‘9‚+ÑÚ*ž[G ƒj–³P_`ä§Y€/¹i«¢-Vzåž;z‚ì ä ZJHêåÛ»q±Å*=ÁÖ`iÒ¥¾Ì.õ%'¯êÊë˸½v¬áQ#Ü%£‘Eöƒ}›E4)ÙúZõ‚.ÓÒ™óA-W-Ô*ŠÛ5¿›¿ÅÂ)EE ˜ïÛ„ùRy Ó`µteHÛ«)þ.,GË ¨©eyaÛ€ ÌKwK‹‰=Räÿ½ýe¶2 YýÍ¢±$ –”ÎójÑŸ^àVÏ‘ ¨p\}ÆÂ u+ šõB+z&aTl nLW1$Ö,#ÐËÌÚÜÄS±50À²*3ex‡CT¤îÛ"Ï*Z+†i&éø—µb 0á]öèµ*HÉ% }µñÚ·ÂèÖ·ž¹eBxÞ° Ä©¥ê5þîçÒXRÌ㓯cZ`Q< 0÷mL>8õ­˜Æ+ÓLYüw"É&Ç×Iu"æÆçØ?J>?ù*jv[ú22ÀM[: ñ͉‹l×|´áÓ—Wvl¨~ûõ·'¿Äoýå~6UKXv_˜µºoŽómmù®Ýó‹Ý¹_Û¶ßÝÜÝÜ~¾#ýùO?_ß^ß¹¿¹»¾Ü]ž_ÚåV5©#Àu³CVFR ­gk+«iNbl° §p2ÁRÌy«Ûa/iüOšÄ+d¤R:%ùoiK2¼jÄD¡ˆD&~Ó)™þŽˆœhb’‰®*9 õt7阩½‘.NtDS‰ž‚!¤ÊØ·µô ³q·=Ó|ëqjT¿[×=°á‹†+úÜm(5$WI±Í¹‚Fº±4Pš –ÿ³ 8ˆ&•ѣ͑P¦MEWl«”éY+ÁÐ: ‚•tÑ*€Ê¬´€®À[Ä•\2$‡Õ¥®õž«’sø…±Y¹ª·û$‹¡[R´g#3ìË?Ȩ«- áÈä¿òQI#s4¦I!¦JdÞIýATñDÝð&¶EœAÒ]»‹(¥ùc…CÊôªüêA¦q× 1aq„T:˜ŽÃƒD0tµ%+4…Xë5Ÿ5\÷â"7°8S*5X§ÿ,–ePS0NlV†äD6b$¢ÇÈUE:ºƒ9åA-‹dÊÐíaˆa÷#¨S XÍ€¢&Ò¸ý5Ò .¥Î˜ÇhÐ$œ&Ò693£eRÃ9ñÁJ12$’-Ääð.g°+Ÿ˜šñ•„™#j¢\ï+¼‚½hÇØ§ÊÄ`®ÚivpTá„låG8à@Œ³D— QëQ’íãêŠç­ˆF66¸KÿÖqô©)›”±˜½gTG¼ÃþP–FóÓ›‡³‹®†<ÈXZƒ(_Á®ÊÇ~b&¶•ȽYöc­«W#£~òÀ…é¼/‰úµW—;?¢°/§^_ùi†›+_K½ÚßÜrÚßÞÜ\î/¯¯¯nn®Ioç箉Ÿ“¸DØ:þ)›¶KÞj½»Ø_Ü}¾»ºÞþúù§?}½ù|óOÿòOh~ýù§»Ï·Äáw¥R=vêÎ j‘uÓ œme ¤æŒ ZØJë¦9+£øm‹E¬,Hÿyï…~tgŒÐ8T6Ù\ìüÄ€ž“K$ž‘¦"¥›nQIþ[*'›ó›­²4gä[/‹³Òè³I—ÀŠza«âÖýí¥+E`¡b#3C¢Û©nä—$¥¢[¡r´ÊŒ]r™%@Õ‹Ò+]û6°ˆã6¢ $9ˆQ:=–ï¼Mð¤%Á]ùÅVw‹Å©,Æ®¡Ë!œd“ –ßE„=H<䎂w¨ä2X-§uÜ–._Å*’Ù²Ê4­ iaq°•YXÙÝðŒ'6F§¢ëä«´hö„ Ô=ÌÚ݈QZ&~AE¿PêÕŸ'?ÈÇÒ@4,ê€l VQÅÀR_ÄB3Ô«ã¶“áTæX—ð¼LUƪ9ûZt˜6±SïeTBAy.¥Ç¨Êj+hÜA,­¥ûw¡F°ÖlQ&XMW,±E,§‰âoàE‚„ÿxh6%Ö ³µLº –³P> HÒÁ –.èeYN˜Þã¥^K—ìRo«V±ÄJ— ôB‹–Vx .M˾O§¬á¨uÐZÆ› Цý¥r(=ž8™DƒŠ#§gÚ³uyîÏæÂS%ă2 ë¦Zä-½Ÿøh…Ò¦ZV @¬ÌmV…þ稻„çÄ3®T qÎÆA˜…Ï‘‹S[;βEc[mžÇxq1Å cˆw"–ÙKÀÈú"ÚÛó'D!Ý*ö7¾ò‰ÚÄ–QúòâN.0*®l¸öÒ­aÏ@‡×x{ÎS7¿Pä陚=>>ž½|zøþ@– nŸ·=åy"ÅŸý‘V¢ÍoÉŸ_ì}ÞÆpµ»¹»¾»¿Ûß\ùéË~¿¿u?¸;»4x]ûþ6wciXÿÓPé`ØÙ§±5FzDR‹#΃†=ÅKh[ª™Ut`8‚2ÿÉ*E1ìÐ4sŠBó¿µ²Ájÿ(o«ðŠVw9¿£þ!6Ko9KBÌ-ˆêAÞÂV¶21tŽ™ƒ•}ÂȹY°dHkd Ÿ`+IZ´© D‹ÖõvÈ-„-F>ˆêHÙ™}‹7NÁ6»hКCå½}PbqJ4°²¤?OÉïùÔÔ²\¨zÌù–˜Ä±Æ )ÆDé2ÿ.|\Á^]æZ\Tl+üû~O$OÄ(Ý23Žò‚û;±AM âÙøýP¦¥‹Ø‚<LuE-”°˜ÖVÅÕyÝÝÁ(l‡åïP ‹XY]àn› )½oÁ@dWŽèÊ·ù¥$áËîÉl¸ ضIŒ&CH¢ç)U¼åûìÒƒsІQbÑÅI¶XÌ“Ò5@à36H%‚Ò[™Ãhš@€¾‡èD%[±ZÀZÓ16cêD¬’ïÓ­ôɃ Ò¢·7뮚U§óX‹ªB¶ hŠ‹šªd È›nü’.¢šË‚#5-+¹1—n‰¢¥J'’-*–ü"ŽW®tq²•Ù [`eW *¹²¿M †;ÖP5³iR± 4»˜E³Å‰AùFù ,1¡éV±–AF¡éw2eýö½Ò,±%¯æ¦¨ÞÁ*z%¼Ð,#­ (ÊT³¥˜Þ•ÅØHIøžʃ:–¤a§E væ†S”‚€låêd`É/´^È”è¢TŽÅ¿[ßæìr[ÎüÎè÷0LÒE¬t¡ò¦“í…ÂQp¤»ÀÊZ•Í⊣Ñ}EµÀNM‘¬ ¨\ðm“m[k …•ĬÿK~+ *¿MÎÏ-C‹©Oób§õ'˜ÍW‚4æÙ/(Ù¢±f­+€³„›9Upreѱq°dÞUÆÀR,§¡;ë¥6åæ)ÒʽÑ’ZÄ™¦¨TwsD•_3|qsÑ÷ˆ¡D<„œ¸Ï.²»z{{~y|ðB/|­Ïv`/Ä–£ÁŒõ‡Z»‰Úõ¬3Ç\6£©¥[~Úâõå“HßüQÐ Óçm£ã+œââ¯Sñ³ ÃÝè`Äi H¯L·g¿ŸÉ×ç× ¢e“äÕš:F|c\F«¿ÙåÇü"‘§'jM s¶sí¿qà§KÀ9[ÂKï5½¾b ãNͯ#Õ ,UÀîðu¨C¼…Á:Æ(›(§EÙãq8°.8¨pîÌPW½#C ‡îžZÃB\>S‹þ4ÑŠÿFBŽƒÔkCâø›`D¾A™-ÝÂþ€AP;ï1Šƒ“ì@åÀÈ‹:=ñÞl±å”.0âñ#,ÃñaL ʼnÁý;qeðïU&ë?…`éÉ<œeÁâ,¢h¶¬‰ÑAfÏiÔÞënQã`ä?˜–9Ñ’ûwñÇ%ÀH¿ÂŠeakÏ¢A4‹|TV?”SDBÆR§Û²GíDö[;CîïGÕ÷# ‰ÿ,Ð÷2¬°Ão1 p’MK& q$?LüMœ¨ý§‘áQ#Z#žqúK,~é‰Ê¬HÇ4ÛcI–(Zù²Ö1-BË–ëƒÁr íº0a#÷"P"ô±ìQŽ5*ËÔ™÷µ¤skáÖ,ñ,@gc5l(»FhiœzÌ.MÁ„–̾ËÀà–c8S4í#­G–­Ý¢#PâCЄ59¯ÍîŽmàå{.·…I³óñÛÎ7Ç]úÞ8ýÙÕßÙ–_¬º¼ºÝ_^ïÿôçŸï?þùÏ?ýé/¿ÜÜÝ|ýå'¤ýa«¼©ã-›c–iÛ wóy[ 5»7íîÂ@©nËZçœý±vŠ6eÓ² E ûøsyéDÈâ02Jêv£^-¶»¤0‰ŒþR–uð\•ð Ö&hYbÚÆ·ÂÙl˺Ð6¼¡ë C-D9Å6‘që°ÐìbŽJùÔ´û}]¯ªU`¥EùMäd©{^ÿ`¿ÎÊ;EòfeVFDN†wUBåi|»„VL¦ñzö&A^r0þüà §ñ…Â7+TÒ¡6jT#¾?¶! -aY‰jHf[Ž3.w8á%«DHŸ:¤÷ÄËN Çw —é éÄÂ'iQÉ¢YÒ­À{Tæ1@¥v𥠍iŠfU£4-uÈN‰ØYL‰ &–J7âÇ"¡éâ€>B«}Z,¦«¨lþ ǧWÃÈ"V‹ØÊ,zá=,f]‹ R¶­÷¨×ÆVJ9¢ÍЗ%g–×ršÔ™ÑPÃoˆèÃtî…>~Jâ]€VÛsÿa0¶» Ò¤ i;€GÇ‘CAþ"3„©M0j9DŸ$Ì·Ï’ôQò°JÍ“!1©&ž¢¼h`ôãRÂö0>ê|éNíy ¡”Êš¶dËáBDâ°V7¸8÷Í—¾ÚëåpsîÕ²Ã5}¸Z%?Ðr¡ùV $ ­ {y\:\G&6yQi©…L'^³õÂ9k½ÿ¶…eyþ¢.Raµ©½?(ÅûŸBŒ(J§1YµN ?ËézÊHu™h6«×Ûxbà=><`ˆ2[#Mw¨…Éì_í!¿.^šk¥Ì‡Y¹ŽvÛ)YÝ$RªåF%_y–'^È~s¬‘äy›M1@ûaÏÍudÓ>¢Mj’Ò1œÀëëùköNP/\YÔ>½<{I‹¡ &èÅîÆ•¾âÉÞìjwyµ»ÿr{ûùËý篟¯ý1‡Û‹Ýeö)*Z™ÿD› ˜çxÍÇ[B3ôUGÉz"o‹Qç š%JÒÙL¬DÎ,Gf·ˆÒZ]Âàz¤´b@­Ç¦‰ÈV‰ÊÐ Ñ\O¡âsóQFùÔ1}‚*Ôêe“í€{DðÍL–ôƒÊ¬Á‘Ó–oÄ,Mã¤~'”÷”žU2©YÇä:+ü¦(%ÕÕj£òE¸SD"e1=JB§”C/šŠx ÆØ¡49¯)"1•iHÜ¥,—ØÛ((伮›†PwZ%J•±$G±!Å’ªks%ßâmËŠ˜ÍRÂt™ûÊT}s”犃n \ˆCpÙé¨îš/–S±Òñy¶ª,±ÐÃÎ:,›Ã&ÙA—è¨nlÑBBj:Ñv×r´—Ù…!aŸ|€­‹baÛ@'¥ƒà¿'vfn ŽUFq\ÔG†üÄTs¼¶šho329Í¢ªÏìUP4’rGõ˱–‡fŠËE¬$MCD0-2PÚ,"Œ:0nƒ‡‘†ëøV€mÙæSn]ÒuÃØ€ã¨.¨{íH-Ì'=æ¿\÷FgçuÍÞ&ßЖ’H¸§›uu¯>žóØÁí!E¦#ŽAðo]@WeëÛ÷Éã çkå”ÅGFI»êâ"û6?¶Ê¾íæj—ŸF¸¹½¹ÿ|Ç‘¨^ùqߎQåô~Žt5±;©z¡e“h¸³Þi”(\Þè-4eù+Û¢¹oóíY!-m fÓ‹Òi³¡kxÛ»6s……´Ûkz_³$'QÎâ§bê7»Ð~„˜ÿïù?²ƒdï»V–´ÂVc"…?D¤‘ä½ÿÚd •W¡×éYÆ_ ?$ÿ9BÅ,O¿ÊP´däÇ÷ˆJñ!cêþSk‡Ü ¢+5T²œÓ¢Mx«h¥E •©p±F$öO\œ¤?RYœ:ꎜXÞºØw[ÅÁèÔîÉó;‡‹qâñõR„ŠXjè"~ ‹Þá„¿ÂþO ÊYEMO°uWb¥?¥^×¶2^aÆS+'î‘› 8QêÊ=³uijEefvÈÃá-L‰5#Î2Ñ C˜ãVpÞšI¬ ¤œ–ºô¡F.ÃL !ZåYÉú†\‹gÊ‘“_ۥʱ Za4»°ªGÁÖ™–G 1&¨ç![ùï ŸæÛE[·§¢.¸b$¯L˜é8 - ZÕ°M£n²€xâ4QIVä[Cuw@Å¢-òeìgî´^ò2¡¿v…÷ñ>©súð¤*ãÍd2çŒo‰&õëÙ¼¬YVX¿Nöô¾[¼<œEšò³ÝÏŸ|…ôz7¾¤íþö/ÿôçŸ~úòóŸ~þùÏ?ío¯¯o®Ï/Ïü^¹×g¶nç—ùvR›À¡LÎý”uH5Þ¬ a¶#Ê×­Ø dص ڠ«Y±À‚Þ5½¤o‚:¤¼í Ì`Îöòùrí·£ƒ!SÅÊ!ð铟Ü»rr=|œ€J˜æID¾Ç¥y ×v-ÕørR¨(i#/­÷)Ö¢–V8eü-ø$8õyƒM^^úeb°@Kw--Ýlqð—’Ƴý‘[Óè'¶/u!öœ×I·ò€Íuqä]1+çŠ[•šªLGs‡õZ…¾tÕ¢“ª,™eA÷A³¬¢b-ÄØ!˜4$PÅJ–( /üŒœx>Øoé6] »ÜU¥)üâ}0Ë4¥Ím5ŠæÕ]q’n±8¨”2}1;nÉ”XÙ­£ÅÆäíY^}ˆ8(³E½K 4ûBE³åÔû¤zë¢8QKf°6ËÈ~OPÊtxïHkA=–CŠ$¢L‰'_,9íÚhˆU#èW1Ä;¥? L­´DM-ËMO€XUNd>^hïæŸÜÁoëµl’Ö ý°MÕVF‰‰Š•˜)ÿÝÖè©ò[GѵL:òéÙ.qͶˆlQu0òÓi`·Ö`TZ€þ3}§‹´5Aš&âAopÈÖ0ösÑH†â©Å+L¯‘¢‹K?Ö³¯á†-˜¨úL‹E/G°8¼"¦´ÚqCvÔÝ\ˆI'¥Ô´gfßtkAϤøM¶Õkžâ¾WÁîËx²0@\¨À÷ž'È5Ì^H mS4˜6˜“õdw¹ÇÙã£ß×p®hoç—‰ŽÝ£ÎðLY<Ї;QhL)®iZçÔöéñéÅ dÖŸ±©úBrZ>XarpÒGJGøaÉÆÞÿoÀ2øq·EÕú¿¸²øÛFsÙïú¿ð¿0–Œÿ…ÿ…ÿ?ÂÿÅ+îÿwàÿd%ÿïn£µì@¬mÐï`ȳËaüëîìãÈüÔÎ8Üü噉YB†î1² yú°ªõ?}=»ùËùþf}s}{ûõ§/7_nÿü¿|ùrÿå§/÷?}¹¼Úí¯wܺo¥Î}QµÑâ§3?Úî~ѽ±ŸV@$a·7ôÛÛ…ßX*O´ÃS²¾rc¦I¸°ÅÛ”ÙÈtö ᤠ3ð‹b”Ô5­<3Hë ª ˜¯¶ª ŒB*‚êÕÔß…ÆSjÆH(ÆP˜-×¾V²µ^ÌÊ,¬¬DþCW!Š ž:™Þ‡å Zt\ª(Q™ ,¢ˆ|}­”ÿWšŽ,¢}Å‚vô”J,IÇVFHtdÒÎ>H¶ÛgSd´:u}@ؑӫ§aJÂ2Cp©ïðGwLI¼˜F&ÆÔœI úWzò#:…[ß¿v03=ƒh=okÍÔöÑQ12VµÂÝ¡h§1;‹õú–-Ëî|ÏZöâêþ­Ð\U‰ù<ߢ9¯Ô±n­ÚÃÏÙ›¯°:)˜Ùº¦JùeSâöÇL)}îï®.[ñ.®¾œ_úùR·n7÷üïýYÒ›ëü¨Âþb—wUŠªügÛ“ÎI|Ù¨Y…#k¶GTÌ(Ì}Zß´£·Æ³%ÖÅâ·­À‚ÒK‘ÜkZ}h%c œùX¨»ò>ÄÖ¶!;4Ì ¤xAW*¯€|Ý.ï+;4¦MÉL(*~¶ )ãp}•èÅ&1Oâ€Ò:Û`¹ÖÊßB?Æ ïX³-ÍÈŽd nk ¬BJ›ÖT%Áà¬v˜D…±D«™’(K¸Øº[¨0Ì~±L[€ÓNii±Š>+gñË[º@`HgAŒ ¬,ÄOZÎá óo4䪹,tœŸœ¹†dERÆj8CÀÈBµtqàÉžE³pâ(CIUKêò4»ÒZ«Å™’AÆÐiØ%¶ô "3ƒšÓ³Ùøª‹¨X//,\ XÁûv…¡0‘øä¬ð8zYè‚à:¬è߉DÑ ²Å¢CàäÈ2¼¤£vIÁ6[ݶ‹Ùf š‚vœM8vóAhׂð¹aØ9$¢É›±œœÎâde5ìßpS3A0+‚Ù‘5S†(£@«®Tm+A/%5ž lµb® ™¨n%!“Zj_÷jŒÌÔZF@iøXØrH+¬þð² fŒˆØ‚òqÿ7Š+»œ¢Hš/¯.IZ=T;+^L@–¾´~²cpÆ›Ýs‘™–é·4Œe VK©‘ÿ­Öª¸i”`p¬(+íÏ 6Uk½*\»[¬"ÄŠf—:@¬u!¾V0…9Z` Ü#H›nÄ4KƒõbQQ¢ÕŸ­6îøGbÚ«}*ïõÅwyKÓð3ÔbxñŸ˜Ôxãit˜—×A“k²sœ©oTÆÅâh_Êk»Y¤°× ѱššØª”†P¾ðEƒ©¨E!àhcƒSÎphºyY[$ÄP™Š6ã¤q‘‹Ñ˜Å"×ÔÖ±‘ÌPIF3Dn0O‚$‹8ÝWVNñ,5Õê8ä@ÖÎí_6 1sŒ'$·™Ë¦Õw»Š£SÔJok(ý^+˜I3;’•DÃo.M´·Az©û¶B^Òôolt–ÕL@¨X‘M/ä+gý éùklÎ÷·é ƒ™’#PFÓœË-6Ƹչ´ÜÁ‰A —"]Ð4o>%E#aP䔸(ÛSJ³ ŠRXl.¬Ìÿ5.ñâ7 [Òì TK}r¥ö·°Â ·êâìçÿçõíÝÍíÝÝý—Ï_þrwûõ—¯·w××·7W7×ý~?wàŽÂc·¿¬|ä°VfóøÒª:…û54žZëD7FÜwXý¢õ÷õ/²«¨x·ùP†žë¬>ñ„LÁ;‚2m‹Ò)¹)õ:˜Ã7*£ŸÑÕH¨"–´ã‘×I•!pŽ‹ öXC¸º3®ÇÀ( = œ¶F÷mд$mºI'–àŒÆl(ÙÏ03™˜×÷øì‚™'ö ?««pʇS³žfS=þYÔ^lüÀNš‚;¡:rÐ~£Õö©³zN!,$ÜOÝõʼn3IFhe]AÊÔædA\×WÂ@”“U(0†Aˆt®}%)ì­¡HA `Y±Ã¾¾p?ÚmÒbKƒ¦Y0Ž8ùZ.ʬ@% ‹d´ÊÔÔVLq{Ÿôééa–Ž*µt+ÓìBÃÁ—nRÝZظë}¢·Ù¼¢›» mh™æRªùú„K¢pF›³¾ØÔÜøi9M‹­Lc. ÔŸÀ&|Б¿VžUÍ1'QTÈF“ÿLXØÏ”çà ;¾±= ¼’ƒÞD¥©¶_Ykßfƒ†ATQ É–Œ¥ˆpmA66’ÝN°™&ŒÂƒßÛRŠR¯<öË~ËuœnqÖ¬IŠéêë25>‹bÂD/ÚÉ+]Ã5Ó‹ ¤H2!œ"›€ÛbHÝ·!V0lÀ-ñbJüIæ<¤[â=DÆ^1e@©i(ó{?C}!MØÑ¥dmÕ.0c¹£}àáu¸B,áÕZh)be2v×¾­cÛ}Û|8ÀŠuì´bĦn«j²6ŠÍ¾-_ÊdiÚJ;ËZ˘Æà˜11fî3ðgùúN‹–‚Ö#S8.S¯ÔõQÓµfœF´âºÖÃ9÷Ü%‡ìu#U(0ŽS@{Z¹ÿòõËן~úÓŸ~úüõëÝýÝõíU¾k×mX»öòjçÓ óO»lãp`t©Xß°Ü×ô8mÍŒ'HN¨åÌ«êàac?ÏÛj؈À¾‡@È[ä”ÔŸµ+'kàp˜bAÕiŠ–Fê (JZBÉc¾w„«H—ÇFFØ)9ïþ?ìýÛ¯mÙ–æíuÛ·ˆ8qNž¼83 !ó„,¨2™U,l§ì”xA‚ ɨ 2ˆR•e©\ˆ^!ü ꯫ÊÌs"Nľ¬Ûö÷û¾ÖÚèc̹Vì8yÒ•¶ë[}õÑz»÷Ëè£Ï¹æZ+5éäƒÒÈ”3?Í”²êHe©>H:~Ãq¶ñ@ýC>‰!õtPîUw§QXÛ©‹Ð7ªJ]TÌ(ÆKÿV:Q~Ð+jb~ÊÛ¼zM aL:\j ÎA&<áPRe-½p#˜|) ¼áß”h*çâSiŠ Ã\=4[¶HÓW]*3*óÉr¨\ý^2tì5Wz{{{+N^òi4®ü¯,|fŃwœ2/¨˲bÕi±SïÁÍÊù)`M1 e2á]ÛÚD*7¦Ä_~ CÛ'jVn(Gï„à£ñâãÇòi˜Âè s8êß~iW+ŽÅ«d}Wªhúüü¾Þ2GÊ_@ºÖm—é3°º»Í¢Ê¼{~ñkíO ¸ f–C^‘ÜR§×ÑÁ‘Ïjxq&¢ H`7h¶’]þ:¨á«èøoEðãÁ¬Þ1<»xˆ”œ“fÝ¼Äæ½-/L$À%ëÉÙv§(›}§ç÷wwr?}‰²)}Å3Êmà–†íO)€önséÑt©ûÕùòûÉÜ© RVÓÛ]8ºú‡é‚rZãÚ™•v⛫ÖÅÝý=ËŠn’Þƒ–Í@¾µ%òMyÆäß`ÝÜð6>ÿ+·ŽKûs§rCóNÖŧÿvDþ/ß…ÑÝê~€¸úy>“{ÃÝq{àÐ û0i§;«¼Á&x¼´îTÊ îxhœe.‡Õ:ß·Òa|Ó®ô(š–é—¯.Ö‰.Hy㇤0ÄÇÑCcœŠˆb~¶ž€fÏÁÙaÕ¦}æ¨ÎB/}w¼Llƒ%KÃ<¸âÁXiƒ,L¸;(§øùÍLñ³` ¾#Jw(zn¶EÚ‘ű¬øDɪ3[|e™y©l@†i¦Õt‹–æ63¤P™”¨Ñ>á:«) zV= ô©ŽÞ¸æ‡ØÁ“¡sÉGN^l5õ)ÎÍaG$´Î¤‹wÞ§‰›O>Al)ûPjžòÁø<¤P:' eöGÚ”ã“RËa3½m{ÉÆhsÖ¿ˆøSxèå95t¹ÀKÏf èÜÑp³¨º”>æeÁ •Ÿ!@èð)íÙ¨Ë 4wáŽ%0mÕjn U†‡ÍÊ ê̫ٹ¡@/6 Ö}ŒˆñEÕ}{„2ä&Öùù„án2„Wº¥Þ5£Ç“K—x HJ»]ëZã䡲ٖ·9;x(ÊQ\ÕàSSŸb<ˆí¿ÍÙd5ŒÔÃIÎ(Ôñ¥n35o´lúsQLŸݨ³j3×@¤þˆF§ã5—²r¤é°ŽU‹^ÐJi¦Uˆ»Òâ?¨%1 ¤©¸Rº½½u§ÑVçwAЋ`q$½bD¾j™ÐÁ¶’·`ÕÁÌD4C™ã¼#‘ÕŠ¶ÄÔMú5Þîîî,šzík":Ò`êêŸ[¨ÐÒ·€Šg‡¿-YÖU¿{`pQåå\†L[ThÈ0ŸñrŽÓÓ³@¿!:Ê„vÂAèsL”1ÊG9çºÔIƒA€Ó˜'A[dU§ik`¤Äd;š¾Rªº”À5 ä¨o±ÐÖÇ ƒnÑàr1·EAtB‡°…9ræk­4¿·«+:ÑÒu^NÁòÐÙ&ÃTè·@P"{¾Jœkâö¥®hÍÕuY§ijkBdÔ Äª;`)¥!Ø@ ³ â ¥ GvEmWºX_@PÊFgd´7• ¨=Ô7—Ú9†qD6c^ZX/+|ù¡z"¥‘ÝŠ¡k:ùÚ{Ô¸˜Êªí… ø“7üjì2ÕP"”êlbžtó®ÅiÓ°–$µ˜m’è(› Ž‚0DA½ÙC 8Ñw|5Jl:½–˜×·Ú–ýïeÑæ[6XÑ£à˜uåPPn¿¥–bv.÷wü½‘ÇO—ªÔV¯kA2þ$ å~õûÿŸñË£_~ñÅ—_¼Ñ‰íÍë›—/yãM;©†“!¥¨ÒúK"ä^¾8È…P êˆ[¥Æ@j™™~ùÂx¦ÈóF#’íÖ3û†°ˆêª¹ý(ª«8+‡p‹$ÃŒç^V(èÛz®Ž(C#j²Ý•™¥©…5V8#¬NS9¸éTö`Tûö³tK&΅ЪWóÖÿaœªiú¹LÇŒq8„„4“çÊiÌJM8Ê g¥\%δv¡»ûŠ8­˜Ç–iq».p\LçÆ&*@/ ú‚I†} 4ÜÊ¡æZ_ªmºIc•ÌED”f0:Bl…ÐaÊÀ&ôËç¶VÛ”KÁÐ5)G¿Mvšn­ÜêŒaßËfòy^÷·Ã²å1}v.¦jÔuôé[‹¶ËvÅ™1¹éRÔ Fç$ÕÔÁФØpÓ_#¥¦sÒos;‹Fоcã3®ÕwxSç±(«˜—‡Î0-štk¾ÌŸ»fB\ZkíKËà"i;¬«Zúnep O0ÌM§)%H¿6£¤„KÚ£qX+d˜ÏÈá‘á¬(A£b=‹X©jÅx²+Õ^|î¤S掖KŽoÆ£%Òtm`Ô%óñiZ YQÆU|7¬&q…éÂ>íc *á¨áPf= å±ÍÃ<Õ Ç*"Y“Ðmí}´t£ïÊÊRã$àAmJ˜Ø2FʶpUÙ–UEèÞÑÝ“1œf€ÞaÕ‰“ÀQ­µøªÒÃ¥6.‹vÑŸÇhƼ!šb¦ ï¥9NaQŽB´_\ý7ÿ•¿ñÕO¾¾ü’?·û’¿µË—þˆ<¿M*BC]9÷“XPÊd²Á<æ°W¹+D¤µ¥r<Á³µây§1MÕZ/–b¥jÒá;g`#úÌOy”I) ¸èè3Þ¡ i1Xùšc5 +<Èg cF$;„;µà~ÕÄ a†çyÔG«¦uð e§úлDÔT¡ÙýØF¬"!Ò+#Íð…øª½š}n Fyu"¬Íƒ(½Ä2Ô¡Ã?À›Ô†¨­Ê“­}ù 1ÒÑ JèCèøGGßÇsÛ,ï,‰-nNSSZ§êc‘CI+™ÇF¾ÿyé¶å,¬ú‚O݆NŸSR ZÓV!¹„js7Ü„ó,¢Í üùœÃ°`ºˆiÙÔ2÷¥zÁ¦lê.Õ-vÑ.އ{ן<íõÿ^½ T'¯”™37tîX…“”¹ì€lYÆòÄ”¶(e¦…@=Íܤ×ÕÇ«²<\åÇ;Ž8u …Ô!‚QX¥Ãí0 ¶Hg륯Ð]O’²îãš ÿh{ñNq®à‰%¿Ñª36ÜR²÷Av#´kr–Ž«‚83¶ƒð£ï"*ˆ´ˆJ# g ‡«Ï¨·[ˆ`è©c+ðNŒúè§ž¨NW6ªf‡“EËÉ  38qmY¶í¡~îƒbõ˜ Õ^p–ùù°Óßì}&Îw'ˆèâßø_þÑO~òÕ—_~ùæÍ[~BzS¦õâêêò†ßñµ“‹û‡{-g t΋ñàÐT›¨'OM]]ÔT«ôU[ª/¿l÷ܼšòèð{°K3žI¦ZQg~Uºë ŠÅ¯ô þXÙ5ê/rѱ>Äõ5ÿŸT:áµÊ«µSÚðƒäD$yo†Ï¶g!š =„˜¶«÷h>úOŸX³ú0¢T'û¨<‘ŸÁSM™Ý\óëõš…d¨Ë¡»äÓ¦õùXGäà58A'#¥¤%ó ÑrÁ›2ÕDË=’’˜|æZtú¡b~g[#à //Ð çì X?Aùµu¿´IÏbôÓ‡ª3 ©qhL¥a4Ó´¾«9úi “sšR˜ÙT­ÞI$YEâGÔ…š.Qš¹(é[\'1Š —æUÜ!Ú°×ú¶-ïíKQßµ*n®_^]ò§PGðmPcuïÿ»7nû¦+ÿc'„Þ´DVζµÇ¥:ÕQé%ÄÁÎjvï4ùk¶u<[‘NX2¯fh'†¼ÖjéŽh†1œá¯ËòTg æŠèŠ–ÙÚa¾Nmœöm¾â /·‰5uÏ”_qs\7¡|B3!íí,,,ifäŧ»ÞWѪGšX‚ l>­4ËMˆZ°£ëÚà—·@šÃqBšá¢Y=tÙd2éÔ~§ì“ÿTÇ'ÿ3Þ³MÑ¡†"«s ŠÀ‹ EÞ®‹J-qñ,:¡§ßÅ‹—/_–á’LÔ‹gE˜c¥zÔÆ*œá ¦¤ÏŸÞˆ†Ùâ-XÍUg6-£¹w¢Vš‘ò>:ýt41óÇJ¢ƒª!Ïúïý¾úê«|¸¿›œŸ¢:\ûÜ&âÅvn;ŒÚÔš9PÐ~JÕv0 šPߊržÛ| ©yÆJv5«dÊ}ãw¾èmV…Ð`®-G%¸Ò½â©“:¨áÄU| Y@‚ˆá„"’‡¬’Ù&â3š>!¦íjy¥æÜ¦½.œ ¤ :ùØGå9õÁgðLó†?³žÛ²]Ê•ŠnQ·<¦ 1ÕwÕÒYŸ[‘mk &o£;ó‘ë›6[JêBÆ ö/;™Ãtü˜oÏBúc«‹ë+½à£3^ðÃ+þ.£”s[1—s[Ñi½BµP¯d6Žtb˜z°Æ VµU:´ˆÐªì‹] ïe¸E”„ªJ}^&<º–†]hô(i²ázÄ3kõ§Çðˆn<×¹-Áìß1Êç sá¡ËÑB|2¦—îˆ2k7'µ½–ÿ³:5WHXöÒ<(Oså‡VˆÏ`܆P-Sï!¼ØGN‚¸:t!t,Ûá)F´êÈüÞ¿W[í5Õ3}MÁ;·m1zq(MGÀb%,ÙeqYz’.9‘*C¶~5.ùO<ÊZ˘”NífyQZÖ,”BoMj†9³8ŸÛÖwŽD( ËÁLŸê†9†B˜3ìa¤&Vî¾:IÓ 1"k‘I’œjû&ç¶µ9ÿšRÜèà×óê¿ýGÿòëׯ_½z¥C@§‡# (…f Dd˜ ùÚeðÔ³©R©sV+BSëŠÔÛ-–,È#¹ý$r š2dlw’ÑW Û,¥Ò;½©‚nÕ1 Dâس¥nY«Ct}IÚd›2žk³0šé»iŠ‘!#b¶õ~¿-á40Š3LÚ™QŠI6Î7åÀ9±ËSMJ9Ù£gÖ°ÂàØœ„!L/Dtò*ⲈűM‰$´fl"¾ÑÖ|pSm]‡ÖpòhݧwÌývÉMqâ,M1J¿%¦ÝHòmeŸn€ôÛjª‰j0#f·¡P4ÒŽuÍq–?Ìè°Q!‘=‚aæªåÇ…H*Ó =˜Œ¥'(‹Åo]‰`¦ÓÛ¸è/ˆè´^¡6yøN)–}8x1V§Í¤q@DÑ9@ž‹R¢©‹vvÜØ•rEâbWíÍ£“_ùšÌ&fÛF µôXÑN­TMÌìG7á΃I¨à•Ic¥A¼E¥Æq§¨(P²¬¢ÑÔ7Å+A½ ܯ] 5£z˜©íl‡L—À6S•‚ZÄßFGu¼)úꙋa»ø4Ù(±±¨±º’/Ê tr€`.­Ï·u­ï.ªö cA’Z¦‹Ù| tü)b­ƒQÆÌÛbõ»EYìS`ûvëÌÕt]b¡ ¯–i”92 -³B š©R •pxÏ"¬À:(Y^„%'t!|ö0 1ˆëÄ¡îçuDƒè«·@ÍÑY‰+G{AÆF<›Kª¸´EÀmúâþø“/¾ð_yõJ/´`bï¬ýsR]eÊŸ~ô;=×ùÿŒ¤ýGƒéfgà? %às›ÕŠßøoýâäö„¸z±rÏ_²ÐR¿¶5=gáL=bìáH¤™–еvCi¦G©  êo\¡o&Þ|ÉXtL²\(Lp¦¹=‹Nf'v|¿-:Ò‰.¦a45¡ŽX:’De4rUTC:ü‡ÄF9l<Õq­u`ÿ¢uAu¤„?ÒtGĤ'"80CŒ¡8¢ÝŠˆµ7Þ„À4#ŠTÌd˜¡ÆaÅ‚ôØœ{¿íÐâ<-åpϦÛ8¡Œ°=U×T+®ˆÑ'Ñ Ä¤£úòæUæ}˜¡‡ƒÁa®½‹óBøGT"5OãÙw½+ÔEžCÄUöbÂX¡j¤y@»^†Ý{»üaŽèÐD  !ÑSvÍqÛÌB fj©»¶…- Ži4¢Zs!?vES"½àÕäß2vžÓƒt!2_›OÔí-Ê™‹ƒ¡s+µ@´tæ&RílëÖê…p„ƒ[µeÒoë" Ò ÔŒ‡q•zELlZ„êƒM?²¸Ñ..yžùVÒU’Ãä¯ï×Ï™7šñ,HÍŠq ûñ“r×§ r(ó ÑCˆ¯<3¼+&àÐdËßøLÒ‹‚ˆ8½n«ZßÞç%z ~*ÇÞr‘½B¯,"ŽíÜ×êˆ 5^ÔîfjI·{ß'Â@aí¾– .^\_çÁW!ö:ÌHœ‹ˆÂ ‰Öz`áOô‹é¶øC †Ÿ:ZÄäbš†èò«GÞ`“¡èmͧBËóÅ¿óÿôHªs¿—ȽÎlþM"]êÜV£œŸTZe;·ÅM5¨ `0jT»¶#,¢l# :–¾3Ó~D©ÿf/7 L¨ÃY‚‚tÒ®"¥#ä¼@AÊt;¨›v‹3û˜ £öDU}f‘…PBX!GIl&x éÇDu8èEÙþ `RbšBÌåvÎm’†¹J¯Qßn{!Ä4…SŽ0÷ä$ƒ£ÆpT Õ4ª)©epÂÉ>;¥iCˆ rèÔ‚Ôi2¢’JÞ:Âè ¡£¿B[Uv+;+éj¾¦D›ÔÄzoó8izÍu”ô ¨>·ñ—is;pNH§m;]CY)6µýdÒWugƒ9#¿lø¶ÂðÒ_Ô–u2½ 1¶‰V¤ÿ®@«Û·=[…âo4•A)¹Ž­ê ]ƒcItäÊ×òÚ^Ô(o¹|zqyÏ+ ‰âGªDë»=KãòÕKþõhþôG |ÀиzãéA<€Ô¦ìP æÅOjÑ©.;ȳ{£—,׺K„–ÐRÂT¿¤ Í, •’Æ“hëlI”jdJücàãªìÁM)ÿ×…=¨Ú2=úµ’ |q0¨3¦ÑŠ1Œ“g5¡ÚO£ô΢4˜gÊ_{$ëÃЕl’eHw«ZqZ üŸB^î-š GD«á§aMÿ,=ˆöèø ±¸?Þ®-’/}Oq³¤níD ‘ïr¯­`Wˆ¢&ù3N—ô‚÷RmÖm¦~ï&ÍBé¡ ÇᜬӧL_”úBþQ}Éuz¸Ò6/Ï›ÃfîpÂÜ‹Z{Æ«õÁÓA”¬´Ð1ƒïD¯8u–ôÒlXñˆ§ø{ÌÈû¹z°pS~<Þüx‡àÄ׸•ô‡ÆB4ñ”sjâ)uötú—Àç Ë鯀Õ#fÄÎÍÏ@nŸ€f¸OFåñSJŸ"R4®Í;ëôô>jœ€3n‘ÎÙcæë+ƒ±ÝÚ|’ï‰8á^üoþ“ÿÙËWÂëë›—õ~¡¸ItÿsÎÑžø‚O$¶ƒJ" ]ßX%¬-©g2Ö´€šöví¡íG@·«ìü{ øQB’æç¤‚UàN³¨†ÌÃýB<‡}¡éÙjE‡ WÿººM„Ebœœ²ÊŒÏ¬8n1žl7PÅœ‚òJL3Hsy¿M½‡Wö+&í¿üXÕÁêYjÁ4CZ-kV+¬†¡U¯£$̘ ‡‡bøaÊ0B‡Xag Ú¼FZÔüIÔpž÷£—Œ÷÷÷ò3‰áȈ‚ƒÔv¢Ÿ³U«#;e;™fË‹sиxyí®Ò-­Îâò6–µVCɉO+9û¯¦.~ÔÙ«øÜæ¬ëÕò¥¥Ø¯;y·ðÚ_]pñ+òz¿ #~ÙÕï·ñdÆ“,Õ Ed[UX{Ê”ã Cÿo+rR¢Þ—ëÇåŒgà^âYõ½J+Zˆ²¤Ma EHÓ*¼˜So0°èpšƒì“ü¦›ž|“Œ_Êç8„ˆ7cw3&ºAbû,ÊG¯Qd’7éî ‚2ÍV^B'W‰Ì ™ d|‘³ÀŸ°×ix[.*ÖÒôqé&‚̱/àBK—?Íí·[ò§êP÷(JÍ,á)4•@¸“ýaš!iN-H çš*qdÌûá‘%(‡ü3JBh)J/Á²,E?øÝ"8žPñL“^“¥ÈÜ!œ=­›ëBªaë[Ýñ8c)þºyÂ~ˆ1Q÷!S ‚‘‘U@hëB̽ :ʱe~ÉU úð~›À†ø¡Z|JC÷`’I7QóÀÜ÷ +a1·rÙ†ãótÝæ‹N)…y@DšîˆhO…¾çî[r攚—‡ëfqhÇükª^ÉQŸ$‡†–ÝvìOwüŸ«¾‰HëÂﶻɕm[!.þýÿóÿ‚¿ÞÆÿ¶º©¸ÆƒaƒC/à$R}¾ÍA¨ˆç„BQ9 PÍ[þiøÂÝr.)?(ŠN–Ÿò 8¾tTó’åÍ3”Ü ¿+ˆÏÒÈ–j}m Š1:!VD!½0©šÛSÄYcÄØ:(Mûð‡ †™æ6\np¥Ú®ØM|mÏV²Vœ4G80—ÖB-®†èœ¥tP¦"ÐØFyêÁ0OmC¨æî2bÂLq+`õ¸LFanžâžäS°éŽîÉ -Ï_1†9Ä ÿ„çAq¯êÚ2 ¹AX¤³8j),n£?‡ŽÄÏN?÷šÜ&¡ìíÚï:+‡eûS*Ö¢¬ŸÜÂqªE { ÓdÁ?¿3šþæWÏÙz¼3FÃÐŽ"R2Ùf—ÔkÅç܆(\æ=Y1dk†íMH#µÄîZ~þ«Ã.áìò äÿ¢ÞÝÝ9œøQmýB8xî4œC_½ycÏÛlœÝ¥sÿÀNelçÜ&·ÞJ¹‡!.í/ê^ÔÒŠ †æVh7° ’ÙÐú\Bò?"lcïXRN&é²Ç…‘”€/Ãùšˆ©E‚ûeŠ¿Yàs[\y®‹öµG;nmèQlŸAKAŸÛPé¬Õ¸÷úS ú.Ââ,”µj\Ø%W(Î[摈Ci•s×<èä†Ô·ZºrL³ºO¸ °hË‚1TµÞõòpîÜ[±w['4­º™PU·Âzg­^B0›ÝdÙl=¹ÂÚÒ¼æ<ãóƒxP%B|M&æVfµØ„[ß*c+μŽ ‰.C5Å—ºÄ[Î@Ñ©IC_:¥¶êHƒø=j†t¤’;¡»U6å®=Ë_´é¾¾2¾ÝEôx%DÀø!‘j©Q?'-¥¸¶”«RWþWûò¯\ûÏUkoDZ£±‘®Jæ0]Ïé8ððV¬­Ü©ª60mØ] «Eºäá;OÖAå’z¿Vˆ­'%céøRˆ?[PJžÑÅMlOº k0±ø§x&‚áks_œˆV«dŽIqjŽfÊð\‡ ˆšûA>Ú®ˆfêÄW%' ,᫉êÁ˜ˆÖfèÂôZR?q85IbH%-õjì¡öÊ£¹K©á“'NNÏþàÛƒ£Á§$†óŽ™”˜Gm›˜ˆŒi†ãØ”g~5AÁËÄV›(|ã²éP˜×<<Ì‹aKÃÂÊ|˜vpÉ-ÄØä…ìðA¿¼Ô7dB ™¦Òo)8Ô.1šæŒ†¨ÞÞÿ¸ôÚ¯æ{ì©uƒ§Î@E-5õDy'€)à5í! ÓÚ åCžâ­>/ˆÈ…êÚ-åÍã3wdàðD›5yc_NÙ„É6ã²µÊAOÍ#gõÈÔø›k  aÖ#5Lhk=}!æ£av¤[ ¡i{ªftxž©å5¼ò)–D‰ýh„F‡ S&Ú)Ál8CÀÜ–nù°»V+\‰™B{ ž„}îvÉÇÍ*™ÕÈ2Þ”¤½SHLF!„Ð7¬úƒ’•>÷Ìðsq „Æê%n{¡¢XÅH>ÒW-å± G×(„3:ŒŽ@Ô¨Ù™Â9X‚þè¹äZØl‹èuˆZÃc³5GÑ)“î§´ŽY ­ Ó42}ÿÿ—çæZ_üOR!ÉQˆêQslú£†Ïmq@]Žöè±#ƒ"¥†•»2:‡Ô¨¶aëhËsGÇ5´ QÙ\ŠãÐ1·‡6H>®u”è5ýRrz!®]Xj[†wsd; áqSÊìÈâÔO *¤ë¨ ÓÅJF€ 6Mh3{¾£Dz~ëýÅöwn¥#už»ñ£Æã'uÐ °@÷ÜÚt*N 3Œ×kz§ÑìD (ø ­"õ‚ä#ÿu?gë¢äîp¦€õxSrÌ ÅgÌ%럭tÿãsžÇÏ bØ I_2ʬŽGͬÎ'Ý\|G³äZÜßãš5 ~ÝÂ77/Q¸º»ãš»»ÛîiOSMô…÷|8¼AŠ!éýo³éÕñý=›ÆC>gíÓ¼F‚¿2Åß½ñFÄ&£,ò)OnÐ÷ N˜è¢õʼ߆\2ÌÌs(4Ý0KÈt³¼¢Q*ªá[OMT¡55x#ä?R#RkZ-–nHWýÊX%ýj¨¹Öƒh¦!›˜¥iÒ†åB%Ž,Æ)f=‰› Œ$™Äu ”cÞ°‰\Ê¥Ö5Öœ53ýÎˈà4ÃÊ›I)ÏøÀo[éŗȃHk©í…ÈL‚ŒO­ÔZ$Z±mè}Lh™WÕ}+ÍbÛF„©UPÉ&ì‚͵'³qÅkÞjr,ZÕÌ\Ì’BîyÈâ–°Õ@س’ʶ¦DNŸMïélŸüÆ<„”Uã=þ—%‘©ŒŽjT8ùˆ¹ Ê©#ÅopD‘éØfù÷IE—âÂM•t¤©Œ ÂÿO@©tÆgÓÚ1Eºˆ©¡Ñà¤ØGÁQVº]jú˶Á2Œy ” B½ÄÛ™cÕL¹<‹»g»îƒéýÍ´±\ß“m4+s§†…MO½`7Eyô Ø ·ñc)+•3Û%?>×¢vÜ HºCç©Zj>mùÌý•÷YCuJ`z¡ÌB¡ƒÒ/"‚ôÔç¼J±ˆSb"Š&¦È³TÀ• ôHŽT¥# î²:B¯Y°jŽk’@šQNËJj@_eô<¢íD¨L“[°e¸Òã¶³MDèrlϡ̫SÀ ÿƒ'ø"¡%¨gSW¯L}kŽhƴ罚V†¶¡—VwM96‰ÔI>‡Rõüµÿ²*’Ô³F7fl +Žÿþèü8wÌ¢cø4ÖˆM™aËXÍzkYÃZ®u¹åLtg%´SšéSSIÒ¬Œb‹ù!4ó¢»i·ows•å¼–JÂMqJ biuªnL7¤$ïy_Q šžÝ iÕ¢ëSejjÛ¿ä£Níu!„<,M2Ð]ÑI˜hQÓ% ØzZ¤TÙÊäCßЖº«Õwœ»7RètÛ5àÞV‡‰¢þP‚i&º®îWL+JR#ϦA4ëj½Ò,–ÓxƒéÙÐÅ;Zè½LSZË2œ†˜©ù2ky÷鵥¼؛ú&Tª««½Ç:Óô[¶Y-¡»#é3áY[*A[RÜî‘îgôq·G”ÇjèSD*¬ôç Ýa²ŒI,nW„¿"¶BµNPܵ¿rjLSÄAÓÃæ½]üqù÷ÿ¯ÿ®Èü¨T`èPuÉ”xéH'¢:Þ.a†¦Y(®¤Üè;àÐF½öj“ÕY2-ŒüÇZ¬Sü¶;BåÜl]^|AŠ6ñ*ƒ ÉÈ•½Íð8X‰n²[q¶±ôÈeœL_ŸH„\¤®¾²7ÐÌÐÓô¦ûèÿ ‚»«E‹7o/pI\êzúáhÌ¡=}"xfðYZèvK$ôÌ*6´©üî nIïäN¬$@åìj LŽÎšSHÆÏ4Räjø7ëÉEÈÛ*J†™cÎiroxZè“–¨³£É-µf ŽÈLÆÑ­Í%*C}ûý­ê¦¤Úº >„ÄûŸ|ð‡€WCÿ §ÊÍOd«ÿrÅ ©Œ¨sô€œùýQÞ„™—{œ~æ=cž|è‹ù̯֎ž1wLgÄmnØ$IÒ¦ˆèaXu‡Òiµ½þ'Þ€ˆÊKêÑYü{¾`0ŽZNˆÜ/¾¼Hvì|Øbòv —ªŒ³½0b¬S,Xê¨0Ñv›MF{ýhȉmëÃ=Ÿ<þøñ£ò {ëH­~ùò¥æííÛ·¢å35QÜMŸ!È¶Ž’œaê4Õ!ŽbxYÕ‰M K£ßò UHµüûe¬#)é.¶ŠRš:ä%;$ xň|T#ͧmIèm„Ýe—OÍò¬¤QŽŸôKMl0£ƒbÚ-Ð(HANtW 7פ‹6W9S‘ ¿Ü¢Š7>™J;LPQ–ô²wÑI¿UŸAˆ®kÒ7*ÀlÒ-,F&¬šVâJˆ¦jÉ´ Ò¿í”ÍÔSáœGêŸ<0ìàÚk×ãˆ#-sø¢–&R1l?X,Ý=§—&Eû’ñI¥ýQo?=råÙÉæ)CV‚“¸àaÿ±•š,ÚüÏ}Zöª¡é‚òÃ)M»«[&c…;N¶™Ù©BÛIìÊIn åÙMÔÖz4:·D!œZévVM˜¨ñþJý$GHΰ­|È0 ªÅ™ÄÔ<[ãYàý¶b /÷”ÕA^áñÈøtñþoÿ+^5ø_Z‘WFŸ} =Õlh!NDw3ËJ2:$T»ín¥•lï–gS•‰5쇣’Ÿ.jÆ¿jÀ¦ç“¢§»jAÎü:·˜T­¬™ãÜæÏçòàw2·ÙxµäçÚ>Úñ¯o^½z¥&^ø«GM–ldˆ&å‘Þ}ú¤¼Å1½Pˆº‹ª[;T¤½la®á ä—¥iû!¢…†B˜Áw›å:ÍSĉ07E”Ç¿!^˜ CYO—¸¥Îü.-s'©­Î*eClX…×èºéMHÁÏFY1)/>¼¯)fú¼ôõÈ}F.š ×¯_)ò_~éEÈщD*JR™d¼5{ezA©òÅÕ÷uÎmîr<¨†àŽ”’u=é;-;ȯJdå©ÎºÃ3 9-W>} PqtD0w‡sD)Pò¡å˜‹Ÿ¬2™ûb4ÉÄ¢3´Gcš ©l‹”ô³Úñ¡oóK©2 Ê3LÌN€H!lÄŒT­S»%U’i*à _u"‘7oŽí‹cßg«i¹¦‚Úc¢TÊ•<´í”Mṳ̂‰+Ú$=IÀHSE'ÍÐà˜§ÆÃæEͱÒHÞùÇýêãÍÿO]î¬JÏ#`[Æ‘gwùÑ”:kÁ>õ훺¹‰‚sD ð˜+ݲ@9æÊah#To¢5P0LÕŠ""±.¢Áè„Vµa¾ðëíÜæbfkIJ$D¨–Tˆš8Lñ²–Rëb½tFô ë²d/ïu¢—Jöóú’—‹ÿðÿþ÷ûì¹Í/Q8)W–O¯]t¡-°œâ–@ç#U.­ÀÊÐÈØ¢úé篮Òðr÷§MrNÚÁ|Uä)ùˆŸ¶.„3:ÃQp6a‡ÒU¶êif‹fÆÊ ER˜@LƒN4… ©¦Zb¿(òoQä%ì‚x±†-þúi!š!B¯œ ‹iùt&aAœmÒ­¦:¢¨Mnª535rÞ>#]‰A°2E'ºè˜+\è¡¥MAœÔAl…˜OBˆ­ˆÜ½q"é BtÄT­Cdšª¥ hM†@Õ»¹0;‚Ô»ÙÂʼntD‹?ç6ѱUS„,ü:(ƒ£{—s›ŽÈLŸcñ«lË ³‰>gíÂ@ú:’fø«š§—æÁö4Ð >E(óô+ÊÃgef05vœZ?õŠ˜ÇD-µ¥} !ý Gµ¤ g+ŸÛî}n{ÿîÝýn½•ëöȶª zýúµ†ü˯¾âŒS¹CG”¼º¬Øòð½æP'“zÓÔj¦n¢ºm’˜Ô²`R£·× Ço,6ššÇvj`\ ÍèÎxN‰âIÝ̱ qV?SšZ¥x0‚šÑHjóÑ §:ç™UÇF@tøŠ."9¨Ú<%Usøªìñ`Oäp×Z‘f42%è™’CÕ1\›kˆÄC5ÒT]×mc5æ©RSª•˜ $yGˆ«ØÄWí`4ã%†³ñX¥ÚpËæ}ïTÛ†« ·”F§»ÚV"äYÂŒå˜ÿžœD· \üGÿ‰ºæ_ >·‰ÍYMç¶O|øFt¿VÓ¹q™QÎ /YYc³™™¤¤ÂÿÈõOÀ ¯9ÐÅÈž§ùFš6­¹Î;í¼‰eŒ¨â¹¶/£¢éó¹ÍgŽxÄÆ:¶åbu%Jš‚”¹”cóZµ`fŸD¸ IûGZç¶ FÒÜn§Ly©*c¿ÊéDÚ+S¤;K÷s‰§ýŒFÉÄN´8ù§¼ƒh†½rª–å¯{n+Á‰š që与¾Y1ˆÂ+“n3NT'úp¤MJtêàÔ0uÖ[ù‘tzH¹ÛaTÐù» ÑâGS:"âJ|~úöä¹Mn9¢ vɮʬ‹ükkùÜú£ë@Í5:À=i™7° ß4õQQ‰äf3Ktˆ³">åN&ü 2ƒ\·haÍØ…u=žþõÕ~ƒê¼w´‰ZÊ%«¢~ ây;·=|zð¹íÝ»w··wšÏ‚Cû…® |Îm_|ù…'‹TvÜK€”ÓœÛâ|èǪ”_ô›u•`h‰›~«Q£Ð7ÕRË‚I*&Â1âM&x7Yã³WãêifYRÍäZˆHsvƒŠÔ4SÔ”¦V)Œ0W©jàõŸ™Õ¬©V.°‰¬+Ê(én®&ëÊ)ë[¯€^úw\ÔtGÒ›‚”m‚!¡3¿žÜù-‰Í\D”Kg1´è™¾‡Œçwd“ëæ$Vcžz 5A&¢ä&¨~tÂÒLÎÜ.|R"<º­’Ы²à¬ §že:Ò1\ïÄð<[«§#¬V œÅA4Í•¿1)Êd9¬ï ÉP#†2f©l[M(šðúuG½M“÷¹©óά\;®YJgÎmÿñÿóí3•ÎmüÏ>‰Ê%K]Yñ”ñþ/ú‚ÿQ­‹j¢ˆ!ÿ‡÷ÛÖè!Ìa {ãW¿Œ(’&gÑq…$æH£¾0~BLSˆ‰0LqV…ÁSÌðS'n`9|e˜qKªÿ“€ˆ@´F'Vq"¢”öiK:ú …äàTj/ìD9~ÂY¥âgƒÈÆ*Q¢‹ˆgñ£‰ÓœÛün;{‚ÎpzW¦8d_€®÷þ MAš%Rò¸1Ü—8‘4&BqÔ4Z_qaТv4m J/FtQ‡ù»\ÜZÙ3¥VûV¶…UqÔÙðŸB4C„#d”ªaH'¨6é72¡>·)½Çß}÷}Îm%9ÃJA<:ºËÞ¼YÏmâw7òí8ÊŸ~ɵýÓ‹ùð«<²éª `8]Hš¸’‘‡Jû$®ìÇï)aSw6Ek4›-ø¸-3Š˜æ  RB‡9 O²‘yÒo~f欴Ɗ­@‰|æÑ¹MSD,Òá . ‘Q6­’D]L¢«››W"PÕbåÕÍÂ<¶‹ YÞ?úÿÊ«ÄÔ[€˜I†Z¡­ï´s¶Òù‹÷£c%á¯DW¸QåËeÒîÍP½žÛмhw¹§E^ðáØ$ŸãêˆÊ€eÔú]FÀ¨‘žQâIEÍÄUCšé,”kóùvé½kK·+MíaRà !ûgÎmAšÃD‰T¹žžÛ„Q‹«HG'ç AR©EG°zê S¯ügù‰¢ÑÈ–'Buâ ÓwÙFGĺ9Æ£û &@´ô…!&…µŽŽ…V-„ÂÇs¹ ŠÕ¶ÂÐ×éœÛ1U«©(9·…3šâ?êÁÆÏ†Ä˜° Ù$†IfüÜ/綂ס=ÕlŽ,6?öÇ }KÏ ¥ÁÍÊp”È?Õ½ô†Ð¨rXÍòs8·9‹zò hœ :š³ ¥ïñóy«z8q+0ž9·±û÷_|ûí··oït ¸ç óg\´}ú÷»nn®ß¾}«¼ß~ñV3@Ø©*sÜû°âúÒ¤(H–+ló¸dŸb?ï…¬K »'!\j}³UåÜfw²8 ˜Í£Mw ¸å` Ös[tÖzÅ8aÝ‚8©…Yÿ àâA Èæ;§„ˆ«¦ å6žÿ¾‰¢ ©° 7{»?W*•ˆ°aÌÒ ?# ÑD¨²œÛX<œÛÌçh„Eš¦ÐÒwŽ.Œ93Ë£…5Ã.½½ÀNò‚%w1³œ$X·¦ÀY1´:µ å/áfÆs”1[èÑ ”’êpìcKø ÏæÀoYäG ^¸*jÆpš¦/gÿYÎmŒ•y¤ªòt2ðø6êõ’I/= 0Íp†È…^¡ âñ‚wtàÒTåu¢q¡æ´ «ºàÅ\¦Ûæb늖¼ªm«ÀSÅ DÎmRí[&kÀ‹'ƒ7˼¹}’ŒÐCجpWºÐÞWø…‹¹x`è8¡[zÕtg¹ê–PÊÌfI‰[Xês¤ª×²r‚gš!ÇêátÜ …†:웣{'&Î6æT94SÎÂ|ª)'زúëåèÏÇÕ?@ÆS` Åœ38hš§©­O#|A9ÕÅ]P‹Rÿ ¢¿¢ºö›*,êÞ¢‹s…§šA’¬ÒÉêÚ¯…Ø®³#”lAÂ.‚ݾè[q§½ÉÕlûEÁ×ÚÖ6ÑÓÀÅ9…ê˜ÜÃà7¥sNaCq? yBìC‹ìÖÑ_D£°oZ¹°IkSƒìÇ“7eÜ¢{ÅL)é^ç) ß(óœeQîq–ùéoqV&´;¾›<î§ çŸNx>ŸƒhU~Æê³qñÿ?ÿAž.:^ðùW¿q…$»FZtaVyAÉ›:û©^¨¨HÁ¶2Qij^øû¬ÒŠÑØÊ½Z"b;„jéðó‰v(\]—hÅpB ×„‚äý¶øô¶ âL2B yie:°DÓ‰‰ (‚i­˜£½¬RÊ2‡è(j®(®¼ñûȼ•GK¾êUBåhó¦Zú!2V,˜4Uǽ^íc…ަÚ’ÂÙ@á¡U  Í`”+GQqôbNMÞ¶‘&Dy4 8j$ ?Æ'Ä*HS*–Yée^V¥9:è5\ ‰Þš„H…Émè R©­My' ¨)BMî°~¿-Êa’Fk:œâGtõ(õ›ˆ•`Ã"ÓÁ¶ª{ÍÍz›¢ÇôIȼ¨î—Ì'î38±Š¾q,+-H!:©5 f{Ú”£° ‡ï±± Të%´¨û;Þoûå_|óñãÇÛÛ÷÷üLàåë—²{õúåõõõÍÍõ_~¡~óöíe>œÆ=¤ÑQ±su3ÃF|ÿ=ˆ]æâkW&Eÿµ ¿pÄ6ÃŽxéW/+qÚ)&Xë ¢ÓoiD¤a憉^V­&0n &añ£ð¸YlƒÐÙfˆx-·‚h݃–ñ')5×LÌӠ׺²ª¶ÚÝvi)¸˜Ò $Zë VйnRüCf¯rRÊ)µ¹g…ÕBî‚Жƒx.ÿKH§þOÒb1# •˜¦íÔãGÍUGt :šëæ`Ž˜‘á‚äöWáøeQ?#I¬Âêž¾K²ÅŠe¤y–)È]y\K€ú•¡>‹RjL ‰î3~bœ‹>“4gºÓ ?3¨©&(óÎLñf0 Þ.²ŽüDÄÖSÞØJG]¯e8?éhž™ê''Ï“F‚?ù’¢ôh1¹L‡ÕY’ä²tûi$ßXg´“— ËBK«š'¥D§ ÃÙøJ‹ÄtªTü]Žñ`¢hõ"ø¡Ð¦ŒÛîu ÑI3 =5³¾7º3šö(zmp‚‡E:I)¹-éY¹Z@4M bè$‹¡¤îoÆ3¨n:œ”’c›¦EB°ê³Í`mnš¸< /vc[s×kbDhÎÜÙú[îòá¢&¢ÖÓ®V͈x¬ûÜ¢?Õ¨g©Ž­¿ÀÿôIDAT¸ÍZ*©è—DØû.)%‘'€j*¨hÒðýã|ôŒ(·jCÍ$6üÉóLqžGf\yxãs`‡eõ &nl§¤‘°j %hx0O”âo¢îN°Š„4s§L³À¢-ÏÅD —¡WaâíÞIÙ‡–Ô1”4Ö[©Å¹æv„—(/ÛBxÁü@i“­„ïåD¡G{“­8±,°gôMUÒ*(˜©¼¹¡º<ã0 û\¥‹(÷TšòÃy‰Ä£—&RLDdå³Xºï˜ÙÙcO…á“ã“5ñéO˫Dž·* Üc'M4­¨T^PÝ©À€ CËÓ4]ìidV.ÒˆZ-íj «f ÓgÕ‹Ü7žF»šBôW"H³D«7#–±r3,‡ž}6X„3Š.k3eŸL™7TØ=Jf«Ñçž'Qz$ô™(OgUÔÓˆycëµ—·Ït#ÐâÊã_¼ZýÜ4s. 6“u¯•aOåà‡Pé4ðѰG¢i‚L ¾õÁSª½GÙ5xIÌÛ ÀçSrç)å—Bîr†¿lU|ke –hSë²zˆ‰kW××*þT M1'ߎØÖḵpx«C‡+Ã=-D•PÁÜ3H‘pÚM~Î&Va€4*` œ8ßãF›‹ »Y#°%»4=’[¿„4±ozCYUKX¥£ìq©ýݯo”ŸSDì¨ZÛgÄF!¹ŽÃxëR²á Î6]ðX+ ßÉ'‹ZõEt?ØFD º‰q=z•q+ó$;)·*Ç8w™Aqˆ~’³×èîÔ]Ï[ѳÞ!Ê(œb˜(t†-”ÜpNDÁ!CãèÄ‹#k¸™mù¨9ËÔŠ×¿ü{+½¤ÖfÃ’R± #Æ–à=ÁÛ[L‡ÛPŒŒ3óë¦ ¢7‹øu|eÓ¸vÁ+fПuB«à3ËÆ Dz*Qón"¨Ærüjý@„ •ûSNìgG ÝŒ) {ÛPR3CûE`Bdaˆ D'Mv]ã«<ìW–eqT¡JЂøl»ñL³8Î<´™›a8;ÐÇÂ(›¶Uz—Ã~㥉M3 ´xÕ d65©1G»‰¾N “BïŽðpeðž,Ö°¢3 >/làqÞ÷ÀœÚß‚$éd ñ9(=£XçPÆî~-é…=0sçó€(<ƒÒ; „ ÊÑ$sac¿úÿÛ›,˜vÜŒ3SÙ’/׺'é Mcˆ#z²ÑÓL^¤—/Ñ5‹¡wžÍ¯k1 ¾ÁÝLg©WHݱª)´ûrÕË2=+tLà$µ¾Ieå ¹öåøñërg+Ì»¥l#ñ•؈šèf¥R© ±‡þøþA©šš@†s„“¬„VàbµhnL®M ²5]»“Fé–O¸ùÝfFž¤EôÃÀYo4ú,Žö=,² !þEÀ +×ñ‰[²¡-½Y'ÑÛÙâ…¶m@®Õ‚/dEã:…¦ühçP«´$T× ; »°#÷«R£n”tœ|ÐAÅAÌ¦ŠŸ Kκì‚ÙÔþÕ*ý!mŒyt;k¢¹À«ŽMÜ»ào¥+ˆ$oic EÇÕ`mj|¬¶i†ÈЄÄŽU×QÈÈ H3Æ­HPt´'èb˜•cŸzz=|º½»¼{üþûwwwù; ÿO¯^½Ôaë•.777/ù; ºÇ_¾ºáø•Ç}V²ÞiH­`éÖ1 ³ZQË­Ýëg@3 M5ëгï&Oút*ª‰L‚;˘`Y¼U^rê<Ô;(+cæµgX9$ðâ‰8VÛÙPG'<.¶±•‘E‘b=¾ð_6Ы5ñ”Å6ÚXÅ0À9õàE°·ÂÃ$jtª`?\ªa·B…Ê–xDjëÆÔVA«ŒH íQ_!B¾Á*v¢ö2þílÛÊ6 =ã9Ī˜}qÈÞµjJAJjF…ÜkðPL& qHmË؆ƒÀQÇ"&f¿p€Œµ5KU„d¡4 åY¬=$J¤¿ôJD.ü²wÓ£óÁ×VÃ'ÍÔÛ”¦Ì¶!@P.ú~nëmžDdöºAŽ=ˆŸ"w°ÎÑØÆ¼°+ˆâÇBÕãÉs~'¸ÁÑÜëòW©…!Ne‘SN㟮±3àK¿ó1-ήõÃ+ïöjöóL÷X3]†³Hhl8*‰¾ª•Q™‹>IoŸùægïd'%tKÛWŠö߃¨£´&J$Ÿ›òŒ³ÛHkøfØg2)È!Ýe»Ò’ΪŒ&Ê Ü ^é‰ÖºY*ЈRò3P›ð¤©µïl!Ö[ÁMüÙ§óazý`²DívRLZó‡ðyšÕ•V\WæAg§ÿ¼h+|“§~vÍ%ÛƒH8oèuP;f8ç Wåü4™lÙ° Š,î–ªzÆÙ«F þººÔÌ’@j~I]NéižržMs£É‡¦™|º‰ƒT[S(iÑÓM9©QÔ8öO^É&¢é­©zý$Ò]¾Ýi]-r”ñsp[ô*5 JÙ4™Iô3›Šu +S4­œþ®F[¹=Z9ÐÀŒþñóöÉë%~ܾkþp¼ey×*=ÒåEšÚ¥9©œØæž}åàG©V® jÁM×åÝ ½G Åm”#㬠j‘¬:J«‰¿¬öþ½½(¼â÷Øaé¼b0¦¬Â0ýÒ×Wënul}Ka &-åªoóµK©JÆ“÷XuB\Ë$–ò™Œeå§…âtÖžó¦H!'_’ª>HbJ!ÜW¦Á7Þ™O’ V1'¶nÅ©mòÁÂ}|äãL žèí'ÌÒj©šªå.ô`D½ˆòÞ“×¢ÁÁ!.Bx¢ïîîØƒN‰CÁ,¸‰(vÕ=V}ašgÈIFE£#ús¾"ûÝ©‚èxP-±)ànt¦ðiWòY,C:Â:Å"¢,"ÓMÍÇøSIRHQâ0šáÒNô'úýý}‚F'"Õº{óc:eAYjÁè‹GôJÈÏÐ+¤€˜8"èÅ£ÿO҉ѱJ=ˆ“Äì{SH¿„4# †99a Ò™:ÄA„sÂiœýóPø§Ûß÷ýÃÇÇ_ü‚ßK@ðé“&ü§?ýúâêò«¯¾|ýúÕÍË«·_ðw@x¿M»­ õì=Wg5EWÕ¤£Óéäí£íÈ`nJFšÃ¥y@¢0Hö@«mDˆ)(=Õa üé—ž>!ÉG³4za§?7B¦ VÑÔŒ&‚ ÷æjk"ló‰ ÑùÛªÔ„C3j£¨i bÝçgêm¥ÌÓAÝŸa ]têäŸæð$רfø,µV“‘†°Wp “U܆_™+!Dö·›—ü=.vl¯^Âæ{wˆT¬¢­á:ÍI©0ùŸd%(®™ü)Z©ò—ËÜñkÿ¢¤¡u&zA¢¢ŒS… jq‹†—ÇÝÝ=ê’ôj¨ÎÔ…Ç iª~43ª"X4á²Z ¦—0ž&ÆØÅxøMU®“H§R២ğ…¡<ÎɵJ B“š&Os7ƒÐ›tß ­@/)‰­º¢›Ov|E4ÿJQ‘ŒbýH”q£¸ Jp–ž ’ò™Øfâ,ʦ­zqO¬ÈÎ'‰²–ô¹oWH³¨¿|¾gýùÉø¼‚‚šŸô°ë_w``üG©¢VR¯d¡4=ˆ´qõ[}pd¸ùñ{›[Q\inÒ”`m&ØÿÆ|â8Ê“8;PÀgPz AŠ÷e–"W-„Ÿ×¤<“HÁ:šÓNÄlám5Œ¿Ná,T鋜eî3ñ˜Þ=52›‚?–£ò ¢œr~,¼Cx&éìêMeAÔ‚2ºõ1\DBèiÖ¦=ëo°|v­Jã# ‘‡zè j¿A”ßóÈšIPÕ‡2Ëiš"e°0¹S úg#ÇQ}ÜŸ=æ¿6⪲É{šÄ&»äbXάT®6'Ñ—´_G|.®þµ?ýèIÕ» NExP!Ægo¼¬Ÿü, kÑ ö­Ai1¾`·¸¬]o0álZD ã'tDP•ŒÒÑË nEIIÍVÍŽŒÐî€Ø ¢¥B˜Tƒ0M¹mŽæqØÂj®8›¸‘”ŒrÛ84…ÒÄBß¾1b^¾öC*këäݵH‡°úÆ9ňôzÅN¡‘Xª±7ÂB=)¦èZ8Zž¥pn…n¬(ÉI04‰‚o)ãs ¦ÿR†Lfg²T‹Ÿ:DÑxÑ‘=E/}äŠââ©Ã…ÊPx›ØÌ+9”+;‹GNfƒDQ•´ {7ß:é¡;bMz‡SN@0ù•ÙuS^œ½êö4NP2€§t?DJCªo^ x¨†6J¡…UAêD‰¡»R2ŽÍdÒ–É-A‘nÊ$ùÃ@SALpò™” ¢¹pTÕR„ÅN²*”´aG”lÙ8VD§{U¹†p£±I³IlÀ½.ù–[Ù˜"RJ†Öv±”' )ÒHá‰8þµþ‚š¹CR¢R0¥öÖ÷ý=D‹ <7¢&ŒŸðéTåé,]]ì¢KPÊ¥š¶tÑ–f)9LvçPÆ5B½~1š&ã2¡OšõŠß=2aøu¤‹Á=lDZ—†<âJÎ .%¡«,\Ò„#4ÓHþw‚ÒêÅ4;¶vÓp6N‡×rd¥¦nYݸü2)?öʃ6êq¶`<¦fl')_PÃäð•ƒK.µï ìÂçñUðÙ=a^ŽoW ì|NŠ‘-ÅY%»”nF×® „‡ta¿%0Ö…ñ ¥l<>äbD!D8BN@ö¤æ”Ñwß6x‚$+­¾˜1ªåf•¾œ‚H'¹->éfQ J¯ýøÁÝ‚è ¸9ŸÂ«‰¶[:kØ‹*‚í ‰¹MâÅE(©%öòYXKºÉaÜ,póÇ`ÉjA±+j;7†Á8%öŒ ·-Ø z4ªÙ(QgÁ+¹ «æŠXU£á=¢s‹>ÅN³®îÅsÃtv 憈=mç’çµî¿}L‰Õ «°ièwQÏiw‰Û0rsUs¬‡“4cß3RH³¡ª½üWBXé¤onÔSá D::Áhôë3!Î×@+Ji?DBqÃE kµj­þE+`Þ·-Bõ1ÄY”¿Sp ößõôöræù¥¢fæ%ÿ6|Æ(Òö·ªÏt»âÔ3íføiBcYš!T~¢œ¨x«ñ-C7 ‰U˜ÃZ›7•qU›€êOtÍ E{*ËZs@©ø‡žÐøª&Ó?! ¸/ô"Ã/5„zÑë?§’&R/ËÔ&ÖÕç³èœÒ'M,çÙ=ÔÕóð ¸9‘2Bqë"z†Ÿà~ø8 uQ¯øÝãWøæ5ž[!–AÒ.¸?å¨:R0ÛðMЫť̈]ç°{Xœt8]*:4wj8«Â¡”~E‚¡•‹f>uàüÊp†_ Ò·Uº:Y鳈Â3(½€4HGdK«y@¤‚(%¸¢4ŒÚ\ ùÎnò¶§ˆ‚ƒ@Ìžâ)~c[,뼜⬈¼®VˆŸ|¨€ùtÛ$À œJ†_ï!ßvO 'l¯‚ˆ¢Ã“N˜˜2(6óàè"õ75® Û8 ‰ A‰sÈy GÓüˆB^û¦éþð#Z¥P/޳bÐBGœÔ<ðrŽ­“v°Ò§P2Eg³Ú˜"Mħ{Ę©6[ K­Ý6dÝ(áåvÏMË&Ð~éëVüM9©FÛ>Àßfd˜Š\yãÀsGñI8eEb,6U,*YsªŽÈQº†x¯69®4*º ]°ºjTs¥ygɹL­d‚³ê8o'Ð)sQóèaooü±knWà4á6Ò4‡³‰Q;Ø«’Nì4YëÛÊ¥-º ­N†‚ß ¹§ôs±¿x†nfàpt£o0{EéÖL_ñçy B{XbM`& nÙ9Iñûôxñpß›ùÃãÝíÝûïßß¼ûðáãýÿ¿UFÚ'¾úê««ëË×o^ñym¼æÌœ•Ð_]qK ±ÃEcº%8® IE8³ãd…œtÚ˜wþŸðìJÁíœZÈx3û‰ŽUT:]X³0ÄDµcgBŒS+8ˆ1B|µÿhªž¸[ªe†ªÃüKÕÓX2¤üùœ|ÖÛÝýòªÜÓ7”“dàí¾ ­²Žl´›VÕÊ6gIÙ½Bì^׈Mªöu ×0œxÚæÇhƒ|®€ßú®kÝ¡ž>Šb&X3­‡¡7}ÿ­âÄËEuz¾Ç_ª6ë®'+§cXjxï‹ó!³`׺Ùþ¤a]j%Àï%ppÑsž$ˆc‰U9ÂÕüòZèÃRrR=ÉÕÒâ\¹ð=Œ˜f ßúŠÇòëpîX1ëQDeÀ3žƒ£‰Mwy¸Zu=À6Ÿ³ê«çäº=Ûrh:Ì<÷±ºÒ²yBó\É]à岜ö÷ˆn=[…… Û'î‰õŽ’¸8”kó *œöö7‚Œ×ÌBcÛ.Ï"Ê{“BñižEiž¬g¡QÈè‘a›èÈc0¶+=g 4NJFc-W*ÚU»N9X VŽêƒ¦ÓOþ¼e)Ímý—‹6˜c´UÔZy VB¥ÁCzóÄ™jSçùÝMiò?µÕ3CçvѪ ?GTJK V:Ø씲ðXQÓ²F,Ve¸‰‹Çe³>‚Qâà§§$…PXÈ«fã¡~«nsÎ\Ûo¥Õ®cTzGØgÊDw‘Ò–æÓ ƒ‘®&AüPüœÈ»×?€CV'yÚ§‹ 3Ùn O`]]B¥ÝRžš+æºJÕ¬bÄí¢tXq`ól} R‡“×èQ?J”&Ã%M©C$=I"Ê)o úöMíWÍÜ9áILÎÕ»Æ*ùjÕº%Áã'½dôßLbŸ%@L!¿ -Bjy‰ˆi?ØF„Oí¤ƒP:=ûZç !oZýó©üòAûCŸqb¤h::PNs´p센ÐQóŠ[´ÔVúv.«>îCÏû±ƒvîôh²nEAC5âçàMÍ éˆUeÖƒxÊÔPCøç÷^fBTQ²Ÿm¦0µ,g¯‘bë¢Ue÷4HƒJl¸ýÂÄ„¨YŽrãkùc?l^L4ÅÀ‡^Ï1ìÚJ¤ QPR„gˆ% oßyŽÊquïh©ø``›¤²!ù 1Í8žÐs{´`UKEµDRPFÚ˜ÔÌÐù™g/ñÏž£å¤%6ÃNƈù¿z pÿð V퀮ùï± ü_„»»û»»»>ÞÝÞ~÷«ïÿìÏþâöý-¡.^ܼ¼yóæÍ˗׿÷/ýîåõå_½}ùê¥P¸ü*î‹››ëKET%éñÎu†ˆÀdÆúáNW—”ޤwwª“?ª¨L9¥¹°YÙO¼9”². ‘¡Ó·'¼ü0ÀóN\’ ¿ªDTíèUÛ–mËžäOŒ»_tFɱRÀuæ‹tqÅšyLáLÆôXÐ.CG›ÅF Ìë+ýë¦Ìü³ü»‡;qç_VñkÎäce%`ß:·=úÓ6škÍ¥8777ò¬¬Y%sÏ?¢d =jéûVªú²¶£N¹ÃгýAQSéÑc¤Ã?¯:åËkf“”è•5EÌlš™&ƒ?ôÜ’×Ð"²À·ƒïˆ,)eûÆ mÁoD]^JI}Qóážÿ¬Kþ ÕÕ9 ‹›•´‡=RÙ+YÐ='ã‰Ä ÉšA2ükf,õdqɯgKnOãðãÑÖ©ÌÇÌ)3× d›‚šØlfÆŸu¥ž8®ëQk"&<ÙÑ¥_ŠŸ^ø™`¤b5¬R;ÏKfÝ-¿Ùfg–]éV§¿R±Ôÿ L½¼ÓaV€}£Qò‹K}©J6OïbòŒ•X]1*þ‹«ÿáŸþm&%7Ør 7¹ZS GJþ̧øijh"ÞC–K‡¦j ²HË F;²ÎØš@•>“Ò¦ã;ЪÖxhZ1JM Zs—¯§^ ÚB444á²ä ·jPôíû1BÆ ÅB¥¾½R!é¿§·,í‡k cMˆÑÅ)J7N"͘„Ÿè ”ØH³j¼[Ò&‹©ýÐŽ?ë‚ I7³X©èäWr-&”Z9׫}šöšIG[|µÊ¡·¤æG„Pä@Vå;ºÑ§m§è÷‚ÉÅzxÊTÐA¨ÑßLq4·ÉM³nzbz ¸¯YEž\¸.)EßµËUsJ9L€•iðÄñ&£OÇ`zPQœäSbÄÔÄŸ›ÂHI!µÝDä=– aŸÔ%†ŽË^¶@âÔûRIC 'à¿ÀÊ!C§s¯¬Ä„‘§¨ŽYbÌþèÎB ÃÞ=$ö8ðrò®¨+·›ø¸ÓƒG;ŸVµ<ðŸËõü»¿½»ÿx¯ÓÛ»ïßÝÞòì—¹ÎmüéÍÕW?ùROLÚ®n®qîUhþј_Óð캻u±n,x˜qÊó="Fõ½‡0ã!·¹;h œ ýÚ®–µ#i´ãÇ»A)ÉêÙWdV`´x¶Tª2Yè6Ê\ðL3[ÚΨ=´Ãoé)×ø(ôãcÖ$?W(_+£“{qɱÒ?–ÿƒ ›¼ˆí;“Ú3!²è%9…X5†$¶ægÙ4ݤ‰³¢©ÃÜ£ýìîQ|Õ"¯gš!…±Jn ê‘àäÄNÂàø]D^í¥·ØêÛÑ/nö®q\+.Ê…c‘­±KŽƒNQÁkÄm)m³­Ed_2¢â™B 5Š•ŠÓÒðÃTêpûv’Ò±D3'b€*»È&@†.Å„#ü»ä8!nõ°r¶T#í?Cñ§Ç%èDiºõh5´F „{«»²ãz.ÄàêïüéŸLJ©†uD¬…ñó*»íˆ±‡˜ä5uÀ—Ô ø‡t¸ÎÇN|'”1kËÖ=ÌFÔ¦6z“-t'4¢2L ).YŠ ¦[":DûW­^0PhõDBŽ÷ò›0³™%Zä‘,àé„h#CÁ7ïÜlmªDáÀÜ6k&O°t\VeóŠaÛܤg]#ÌB²Ú øŒÊ|»›7sËS%°zheÈ8M»d`“Vå…ߺˆË'Äâ?%˜Y(Yš!¦n‚.Lš­ÄlÕ5ÔÝD_"ËÉ'ÄB÷-Óú&»¿ššEº UÜÃèÜzåÞR†¦Zl“Ú«Ãσˆ$ÒƒZ˜u+0¡Fë;J64¿ßc^œz†H›nÐΆ'i¼`HˆÑ8­Žó€äÍÿ­]Þr»»¸»¿ýx«¢sÛûwïus"×7×/_Þ\__}ùÕ—:8è wyÍ{Ärär3:TuGß[¯œƒ™›š„·c+ü|Æ×›•) ÝMhS ‰îíP ­vžW ÈjÚžcS·IÂP×”T$|x $(½ä¾µØ]Õ¢´cV+¹I@{&C¹3UÍp2ÎÐVV}ßù½L ×Z´Ò·®Ó¨Pe^ù†¥«Uôí´Ã싸ȽÀ€a–ƒW‡EFdR³˜Ók„½ž‡EsmŸÞ’Bi‰0i^Á":uRKb¹‚Ò±ÌÇ)¿Š“†¾}qÿõ0KÂq ¦ º® ¥«–=zÎÜTéZTjËO$ qR ¨< çÂD§”>uùWÚhjÈѶç®ÕÁ€-˜‘(ƒ„#ÎλU‡Ô7fvËÉÑð[§Ÿ ÏWüoÿ÷–$ûjX¹-„4ì,Úѧ47_ŠPù<$ŠL*œ!:ÍÊ"«d¢”9÷€FP,K¬é—È‚8e4[¹´-ÅOD3¢5Um)EU¦°ªk¢šoG27²¨±PÁ'S!V¼G¿4­"²³åÚùçUJ’E§ŠÕ"eÊ‹Íhd@ÐhIUˆ$Sb¹â,Ú<»ªûj¶æÀ¾­l7›•oõ¢W¤;É-„õV]‡·«Õ¡ [Ï/cLD´uÍVeÈ%ÎhFuæýJ÷ FºÍì2†{xX‘ij1öМªŽèŒBÆÓ n"d(­(R4UÄtúîË‹¿ÀFvb¤ ߢ-•h¦nµ's!k,¶f,œæÂî‡4³¡ëü¾’¤N:Ü ¢tas(BßjâøÜÆÂ—ÛÛ[Úî>~øðñãíCgî¯K~ÜöêÕKÞ¾üò‹œÛ®¯}kº r@Ð}R‘uí×iÞH€7™Ò+LÙ‰Âζå!uì/Ê`ˆ]šeØ,¶iJ©.ùG,£m·£9”y`¤êK2Z™Ýr¥GŽØÌ?ý-H-%­ ¸%? ªŠØ5» ¨2DÙÿm¦JÍ£ "û"oª¹Ã¶øÅJÅÌŽB#¢ Ñj)¹Ý¼…}sdKúÀ…ÂIdd˜–(^Tyì2΃!!¶U-ˆ#m$ÑWåR1ì.pŽƒFë/„dÃ*®ý`váÏÑPð ‹äò,Š©±zlÄ­Aã%¨æ¡~l;¾#Ú–v¼Øy”Ä}¸ß^ž!57W»YV!)ðÍÅdF°}[æ¦9æ»ø‹ÊP‚e‡n„¥uÅ 3`ùv–NœW^íuÀb+7…J˰­‡BN½r"ZWçßúWÕÕœf Ç2<*rn¨±¶3¸å*^¬ßΟCl‡:Æ.û£¥ç¤ÕToÜAuÝ¥Àµ#I½Jf‡ òÚ%̨! q¡J+O~üúF†ÕOWhÁuÓS(Ô.ÒM¹ˆþ1P{ðO®@yy£©—‰QÀ¾–ÙV›VBÁ§un!ÿ>ßÙ1=JF e§‹ðëñÌ#ðs€{¨¦ZH§ªaiQ¯Ý€£ïÕ¢—ëÁ*˜[VÂçÑms*®á/~³ Œ´žGiºáNs°){ö›Y”Ä*gB3†è(œU³õ&íæ>ž8ÅoÓ+h;·õS0"AT‰â£m¾Âœ¨‘ ûã0bVž17ÒŒTuz³Ë"©+Ð5èµÉK$Ø~ºúã?ù[Š?®ñeƒ4I¹Ïm>0”bTß~\[4jƒelH=¨v#ƃR ã6Íšènݧ ý¹È%ŸÔˆK­²mBU)ww¶€8´ªºâ'µ{Þ¹‘˜€LJŸ°Ú!ëÀÅÞÎB©pÈjÙ‚R’§žö4K̼1qáϬ‡)Haj¹ðE®¶Â‹ŠÀyŸ·1йY±b2Y#tÌ…4W„YÛ™mOÕä§–o#:xlJß–8u:­#¶”rIH.›óS$H@¯ž…t’m :†ëê-A·û蛀j/ˆ‰#&hd]×E-$4U&ü>Ĝ۪}6ƒÆ^¹¨Æ™ìí µ’†y#в¡M-QYêÒs°DtäùÕ](?6T£7}éû/Ôñ©¶{Øî?|øpûþöûïß Ð··z®\]s‹éÐöêõ«Ý¹í:¿D•:¯´Ø!œéeäÔÔ 2 Š/½dj ‘îMŸ·¨²çMu³¾v<† ˆ‰k1÷`¢X®ƒrU kÏdsr—qN½ÂV+õMº×+…-†3ß~¤iK`=¥*Vú@³ºÍ 4üâ踠Ú;¡†Ð:Ÿzªkñ„eCd¡F Öª°£íÁ6õ[Ij›K#a(öå‘«C— lDÊCgáqÁåÙß[¹rƒ 8ˆý`Šm©íQ¼8w¯iÅÂCà Ô€™Š‰`]Z†ß€È*réÛLÓ”«ša“Z' çþ¾m\ã¢üF3¼ÖPž1 }¤jVÆŠQ©¢Ã!mã {Û é¦Ýj­ù¨…ØYN¨ iŽ9¬Ùv!'>Š9·eús&!èBlå료iò&1¤Úp.±ÌfÒØ5€Š:ÁêpèäÏ´;®êˆ@f³Ëì7Cé32ù ‚†'¾Üt ¹QÑ27d(ZN´Ø¤ÚÖãÐ:ZáÅQˆ@ßîP”Í4Â÷¤j]5Y*í_.ÝAhÏ} …¨ FAµ¤¹U€3÷Œ‹èÄp‰Tä^’7%!¡›+”ÿÁÚè Î T{V¢M?ˆ“ X'À¡«°Í¦~Ÿ©&HgVõ ]EÒÞ.ÛíL£yÀ´¸›¦Gh‡ð…Ñ ¡zþŒ¶Ctí©Mu )~¥æ—ìò€_à\œL ·IÑžÀÐ[ê'ˆZzüÛt‡(E Äq~¼(ÚJñ‚Zù¥À%Q<ÉŠ›—mAN.)ù9©Ïs‚Îm~íöý{¿áv{{ϰ<ÜÜÜènzùê%?'}yýÅ:·]ˆÉ±@¡TÁ·- R °.¥NB\É]X9G‘yŒqG*±ÜAʪ³I7³Üׯb")â¹wQµŸ7Þ[Ê‹S°[Uä„ÿ‰ëܘÅAÉŽ…O;ûŠÃÑ„ˆP“¨aYêL Í»6^zéùë„êNò ”‚ú̹ÇÅ0ʺ8D–†r 21[få¶„ð¥âyáBT´6T>‘BpøVü59b1+Çx•€2‘T%Ï  Ã èˆp¯c]ÌDtPs9Õ!¦Zø1ì¿%bUšY&Ý4H(ò ÜT´# y/>ÉuªÀYp›AeÔœ ÀçæAÍó.‚¨üöw¹„{‚X—;©X)ÉÔª•˜íÉ w°‘XÙPë¿xY Il¾Ž¤™ØMBúž¼à/Hm'3L¢Â±8;†KÂåÖü«?ú“¿É¹À7~ì ¥Ìw_Ìæœ¬:9Ê—y}aÑŒËh®&¡í:æê[D‚‚†iui+£+ Á9Ødsü[±°47~Ô4¶•§‡Ú‹K¥íy±4un”}iÄJi¹/úfV"m¼@+î:‚­@ô#5ñ­…±4Žá@QFšúA.¸¬©$Ïg1j5ÝtÈþâç!|=‡Ñ”‰žFIIˆ‚ š;”d‡ ÄŸ‡V?^¢jÑje¬Tc`„¿ƒµ×Brn+Vã D?PóþÞ¿àn·óÂjœ…i†Àf1F4Ráà_=¦vcé5-ÎÊ)Ç™íÜÜ»dånŠC‘½S Éï·éÜvÇqíÃí»wïtt˹Mf××üþâ«W¯^¿~us}õö‹·zuÅaîJ£=ç bÊQIDBJ#f9*Û’Tözgeqå;î!<^ú“s€”­˜{a½#VðˆgÊöxàÜV£±ÁÑàD óðW `µÊ$I%]¡æb–"HËð"jUÐRáÜV ‹•§6tW'î=²+%œ³Ï¸/¤#QF\ý²—YQ®¹˜j‘u‹¬|'‘ԃ蔧„Ÿ ¢vFÙ°›FñÈLbLÐDU]vbÞ%;IãxÃ,ˬ/‘hp¥Ê Zv­o'“âµJfÝ34Tç™(^ u=”<ò“no†j·ä c­$RC>‰š…5Ø Š‹gOÜëƒjòZÜIç9kµðƒð™Ú_ÆÑm.ᎌ÷Û8·ñŽo]&KÂ6Øòaı±â×—G׈’j)ƒÍÂ"Ä)žÈ?à‹Bš©u©zµ÷ ”a¬Lòrq£®3"µäŒ±HCíhY°d¡Ë¼ÀW0¸{qê4ËRKIÐ5!¾ŸX$«©2C:%fш ¶R°g¡l+ö¢«ô‰9ˆççQªÆãÔ*ÕƒHÈM­ìÒi4ƒµWAQbŠN½O7›Ïð>£Ã"2èf‘me•#sˆSÑÊŒ(HßWDAÔÒd¶J){¯L‘ÅKŽJi~8Žö£à=‚Àµ‡ c2…x! ¶¢Ds•h1/MÇ«ÌsçÊÄùøÁ×f9MW¾òª üx’•g[ά¿œÛ8ñÜósÒ;~6ê÷Û>|x{w«£l_¾¼¹¼¾ò¹íõÍõõ›·oåöZ'8^ÙVOè@ŽBe7«›½²2:O¾"Ñ·œävÚÃÐ߃1±: „ƒr7䙺NzŠ|˜ã¹¶%+¤ÈemTL¬(~‡ P2›4Ô¨|,/n ·VN弈ˆ@û¦_ÏJêTRÈPß8ôÈf¨ÓêÒ…ªI —&&w+¯"#K©ZV‹eì³—¸ü›êž:zˆég8® š¹ÈŽ}N„WIýç\`–”ôψHÒšÚvý³\a¥Â@'Ó õTóm¨ p•Oüú+‹[b«7¬©‹5»/¾*E¢%b­¡ùùE»$˰ÛZÒEdO†ÓcJËÏ>3}²È`G tTÊÌ´À~fàVpM!«@Uìøã©…t!ÍðK j¦~à{R(·Å]œi†/'!„gÎmªÑÿ|Ädl×Úð€¹»i‚pvÜTŸòƒ1?%TÇjl#šv"#u‘všÜWˆJ)¦ ú‰²¡û: ô¨Ù<¥B$”[c¥f܉Â#”¥¡å _åÖ"ìJ' .0 V~Dv/È_pòjM4bB,øn¬®4Z1!žhÛˆs›¤~³mnûøA9ôub»¾º~ýÚç¶››7oß(âµÿ”'A!•m6³óWæŽåÔÜñƼÙ<°!?­¶¿*1än/UJt¢OmBÜ`O¨!T“t´¬ÎGèÚÖyòs™|$Jø4•Òv&ê? Þñjß“:…XUòx4¬`e£¼YKp&$&Õ:°”'<¯iôØðîfxKÊÜ6ÔS3,½*šÃŒŠÎ€§³oŠMYa¦)ïˆÍôÅÙ:º–üF*t÷УC7ã˜/¨\ZÄÔqCÛ()Pìµr¨áÂè„f(êB@zC7ÖXÑ ÍS87Ö¬Ò¡n—U,©2ª1­yI‘Š[÷X « †êâ-Q~Æ!V5 IõøÂVsWm eíD•dÚ׉NZ‚Ó©|щ8¡QPþ‹â6FBb•Õ^<¸IØV9ÛƒÍÛɹ-xŠ~øú ”¶‘føÇ r[T{ØúÃÔ ñ# !¬tµè ¡£†ËS}WÊ¥žgÍ„èmØ|—¼£™oç65I!Ýr¿"âl-6OÚ|6DÛÜ3"!¶Újy+°(ÜB‹‹"$ÄÞ¥”$rÍk$˰W –êæ0`úÖ² Ó½ãï°k‰yï_Jà’~x¯s›)á½ÏmØ¿yóúúúêÍØÞÜÜ\¿yóêÊÿ¨T¯™ˆ¯D43¾÷å<‡6¢¬&1 ꬷ]’(¶¼¸MmK k7BuêW+«bšfÝV>¹’–Û<2.Ú^DYÏ-dÐì‚óoõÀ2*ŸÛ|‡®½‘8q£]ÀKK;1µõZ‰ÔT‘e­7ÅR†Î$#KQT¥7äaÆš-J Ne圩¨æÃUÓÞ¸¹äåkhœ"Uá@êšèÔfv‰a;”Hk…xxÖÕæ¿¯¶çm‘uC8 VNè17¡ÊÆ–6|r TÝ j¶ ¾ÈڌɂäQBì”ehØ™ë•AÝ¥@ rV`•ª·ì¤*f¦Y ½„ÓÂeu°p/BvTPÇœèœBNT—ÿl† ÅŽ”|"` × xøCÓ~-¢Z‘8¯å¥É ä‚|ó>? Å:N)¥.¹åò©XN&tZ6¥e„Â9E‰ÅÅ_ðÿs°.™¥¬H,aÓ±_éEƒ†ê¨ÕN®îL° 3[° »$ÑduRŒLn®ò;äìR šÅÉæGÈ„.qƒDW}HcQæÊL7CC>j¼Ä‰4°Ë'ñƒ ‚tÊïvDÙ,(Á%û!|¾æYÄÜÀϦ£*ºZz‚çV Ó§‡Ý £¯:ÊòHã-Ñ>Ïl –¢ŸÏ¼¯æk‰Â¡øcûWü÷IÖç,à sIî„ÇCS¬u5Û—‚¦´úŽÑŽ¥=T{×ÝNpŸîï9–°‘q"]`Ï$¿bŠ“#ji ªË»Ðr2dÖÂìU\ØÞR’ëÊI–¡í±ï/èÙU¼†m+3¯a©1÷lÇñh'ŒòS!N³Ó¯=ÈÆ‹Apj„ÍÉÄJ¿òNü§ay¡ÍwH ¡ÚO •ø •³"Ç5½Úl!V^χ+"Æ&ÈâÄá¾<6êE®“͹ò~Äž28pÒ§¡|Šú!$ù§PJ§¤¶‹“¬L_ýÝ?ù[~»ÿËY·ç§ u@@ÞB‡ 'Úý½åªûD5jO:ètíø©9±j¶šiz ÔA…•ŽÜ@9ÿgIXuh‘®ÀtP/CcâÈpCrÛ1qm#¢Aüù4ˆêµ?#$ú@Õñ`£o~! y×a”…٠µð³a}ÙÊÛõ Pè$U§/éB¦/i dH*@ˆ©$ ƒ6¡ÙÄ¡"®†9œ`h«oˆÿAÄÑ|j7èÞ¹6ñ¤,XD?Na‡ðåÑ7&W}¿æI¸5RèƒZtâpt.DÞ¨ݰrL¶Lz醾¿¯¿h?›¡iç–ÿ•ϋς¥†]Á̶ £0wA,Ýã’²*•F~#áîöîööŽ_Gàç¤>|øøxÿàÿYuñöíÛ››ë·~¿íúæêÕË6»ÖŽ+ï*:@)üÏ( «ÞÊ®_âããÝý‚ŠJ¶aK'tš¢(ó„dHç@lXÃ5ÌW–œ5ƹ£E5"wP]Í·¨ïò4p- ¡²‹çˆÕè¾Tƒ¦*IÕß0ʹêCJ$ÑJq"„S9k€4H¥¶DØêãq…H-ˆ)u¹J‹B–Z0±ˆ=þMš/æ(RA¢¼Ãjo D|õKÒŒžËâŽzÅ0ñjwj[wC]ò\SlÅFÁ$HSØÑ4ËÉ'&ÅquY–¨`7 #:"i®NäVÒ±¶a_Ïæ~0Ñ·ôøq1sÓ͉H:HGȇÿØ[qû³ B…v=ú+`ºœ“²‰Ó5¸Zª|ŒÂòñÓÕýëÿ­Žnµd%·ƒºBZ¡àE\YNq&œq$W\gIlé5ÐØc’KËeÃjuκ°jùûb;±z-Rþ2€ÑÝç¬JR]r£èŽ©ðî;›z©Qä*~¬Ä;—0é>0)ŽGI”AKg‘0Pq⟮8´š¹™^ïV›«*Ðö¦’‘"—˜Žóì*"\S¼&ŠnŽ÷œ%%ÉQ©arÍ2íg•ADÛ ½í¦Bô£ÊÍ ‹UµyµÍqΨµPz¨.5Q§š6¤×Ë® çüH<«zKCÙÞ4*ŽŒ"“  5¢žFôd!‚ˆL|Uä£f:ƒI[Ä:àöATS•†¬ÁŸÖ3Èo¨dem:K©E‘"àªt+ÔAVHÜ<Ö+!”Gˆ0€Ð!µ,Pæ¥%. øm’UêšÞŒ¼=§”Ïò ¼Å¨¨v Y  ?*³pVŸ‰åRmJ›“eššfˆ9’Ú™W>Ô¢0ƒZâ€öîM¤£[ÑËj×i Nhcš†ÑC×l—no243ì4»3M,³-~£oÑ#&ôXЇÆ$±ŠBèXzp~hÆ|ˆÑ ¾êQb¥/ƒ0CDÙÖá¯ú ZRÈ\bÒf0ŸÅ^G¶;fn©ª33 ¶ëUm…8’G1Í M!Ra]0AõÕÌܶ¢é Ó'²< ­Ë®EE¤Ì¬íúæ7Gç³»Ûû[~HJýáÃQüÛröêåÍõååW_}ñò%¿F*\8Åž!H‚g¶Ÿý¼ÓãÏ]8ìR«ì¤bJ÷eÝîXëô8 B<¦)"Ý Gu0œa†Ī"è^¼ž'gƒ¶‘¦4uVŒ• ©NðÍsÿÔØ•d€¡Æ$t€—K©µó éˆõÝR“çúٺ´QÛX”£¡ÙG']€ Ò;«Á‹ÔuÆSô¤änÅm€¬3!#óhM®?ŒS„ÚýÇVÒ¯l]‹JÒ.´‚2(¸Ís?Í38X‰®¡X²8EÒhX¹IB‡œ•54}Ÿe9¸*.ÑpA£zg¨´{CscOÞ«Ó$¤ ÃÎC—êTtÌÛÑ‚Ÿ—BBÖ#5ƒë´ã8‡RlÑÊC3T8ªã6µÂß“‘™MŽR]ê—oTã!‡~GŒ9x|äÜV66Ö’n8ܯ©ù{’6Žn|6N„JÝç  Oh®A žÀè„h¨9|Õ  ݤ¥Ðé¹ë$«•è R|Ú¥<¶b0^4sÝùÂÚˆL&u5†}·xäd.b¤!ÙM4î¼›AXAÊÚÎtq‹’¾Eq¥ï,‘Ž ÑR!¯ãCF­â«ú‹TzkÝ{¶Nh,ÒF3‡ä”[¶]Ü»Øjµ=@"2®¸°l«Ð8$&Ð5âÛ‰%L3DÔ¦,ÙPÜÆ:,ƒ8t„]J%nŸQfLÒôPFíYt¶¦ÝlÍ gê,NÉÐ0œÝ†h®hÕö´ÒÂϘ¨ªÁ1Ó x»×óúa«#ŒVA‰Q×ÒŹšœO2<< xîÞß?ÞÝ­ç¶œÛÞ¿¿ûȹ-h÷KŸÛÞ¾yýæÍë«›«ëkÿbݪö¾¢ðÚv5þÞŸ8·°'ÕÞŸs•qÒvŠ;ûiZbE˜ÖÚÔœy88ƒsyq%Bƒ©3³ N]pn³Pnê—LʘėCˆ™sž73P|ská gšÍ ÂWÐ:· Ùg¼Ðêþˆ@þ?ie;)UïDÍx°gî¬a `Å죬P†_µS‹‘ õ)0pJöB±7³í¿¤àäèŠÈÁ£œ:°ªWDgId‡ðƒbÕt0œ κé¢Qµ™Ç Ç­›¡Uà· ÉØm j†®b½ ]莤\fj ©™jšá$žRÊfëŽæNöBá6Ö`9(?öDѾ6XQ@t…0áa"ž"Dª@’em§¡ùâ-´³ˆj„CªÓxþ|ØÉ1ûB Î2ˆN´† qk/¤ÉhÅ2ðÕX—þŠRí (îòi©±ÚÑŠ%h¶V„cÇ~Ź0¢¨ iÿAԆΠS×2nçC‡8 :Á¡L  VyœõæÕÀyúà J©QÜ'PJ?¤Fã¬&L±]¼ÛP{÷(à™6œ¿Aü@ÜÑ ŠeœfUJVS­•vïÿ¦µ2™†¹Bšx±h†ËÔXEÁ¡¹“HÐG­äüIÏ~Ý, ×÷‚ƒ²ÔkÇÐcÉW#ís–÷þ¹[øÜi¢3Bò¶(OÂ*ı …jœ•¿ÒG.þ^¤@Å7B™Öðÿ’ˆÃäv*¡TÏa$õ)â!®Ta¥÷ë" cMilA¥b« æŽñ3D ‘ÆêÀ„Š5½R]<‡«-C¦ ºL¿Û§¬ªø¶Ráç¡Ñ1µ­iˆÔ]X aÑÉ’Ô Êšð Fš›y|‚ž0•ÂS(¬¢Ñ 1#æ3¸úã÷Ûªešú®F¦o¹É2‰še;À•ír(½Ð¼¾æ?À\ë…YÿD~¿&V´3àW¨‹Z“aF'0“*RÞýK»o:ûá7¡j=Gj² !eלa½VS3„°¤èy¿%Dy.“ÕƒW>¥Lktfø6Ødø‰ˆŸDó€ð£ ´“Ê!:Âø‰Â@¢áO=°Ên—Ä”ÿÝø˜#~¤£p€¤q•g?¾ŒQo!,ä ‡Ü>e!ÊBøD'tt¢,WSG¬ú­kÔÛ@T¢&n¤rƇ ¯ýÏ•.ëO¸dÕñ®Nùå[î.kÕ¸[¸·œ@vÇ1Íg™D%Umz‚kYL ŒHÅ!›žÄ5 )°³î§/RÕ’Ž‚ˆ(€VP-6/ˆÃî7‡ìcC8“4YÅŸcØç61ü~ÛGÿ­Ýïýÿä?¼ûp{Ë¿%½¾¾|ýæ•6³¯ò“7¯_¿å^ùÉëIBaþ40õÉaÞO¸”˜ße¸ö»ÞÙÐ(†§EçQWµã)Ϙ-7HŒÕ«W¼É¬|Š àŠÑ;¹ã…=Þ™ I$íÂæïιð¿†* il\ˆ@§«ž»¦;A¬äBL²HR‹ÙþŠH”9ˆH'ˆ;qâdhk圫~80:y¥ÁøéÅVd²ó,Œrºç«)”’Õi†/l 5£w †K¤3\²±´à”y¤p¸•¤–´«½`˜"˜a«ÉÕVì_øSÖ¥¯+÷R†ÈÎv„<”£}¬ ¸"Kd—ù#rèh3 v­¬TÃ-WÒI)˜)i1£hI‰Œä-H†²V«üFîQˆ£1Ì0†¢6Y Â'lm…¾w ‰äDµ4GYèxnxélî+±%²§Ý_¬ˆþÔAâí ?WW/_¾ô][1{³Z±²µ vjç-â*qµž‘ H\jcÍ\h+L\ƒ¹¯ qÛÍaÀ’}±ûäߥã'‚5t0"Ç'™Z~âh’±!…Ôá£iˆ3;ݪŒ•êh v$ÒÔ!,¬Ò\­Fÿ)D'Ê“¤sñDA£­m(šª'ÛBDY„Î‘ŽšjùÊ2›{FÄh&V0†‚è(‹XùÂÁDˆZü‹`qî,¤Æ4tµt_WDFtd£èD"u¥‰ä˜ÞÔ§È8tÊgB4œy:8l‡%³p&¥BtT¡D£/Œ“@ÍQ+5nµdÄj[0ÊP]ÔF--¡zñ¹ÿðáãû÷üï­>Ü}äß’*SÍÀë×|Àí§?ýÉkÿTµí삾‘Á´ù©™¦Ðà”ÁpËE\]Ô¹Q3¤ ‰4iär8ÙÛ 4Œi†è·zñº’™11ˆ3±¦ŽHÙVöN–|HaìF¦øëˆÅ¡0„·UDŒš5C C!E•4“žè¢ø6Â- #R ?:&¶úÃFMÌÖnŽÎZèXè {ÄjšÌTMÒËâ‰gÕ³•¹•…5´¦¦¤£¾FTþEˆ¯Ú«dç!@ÔÐz* ºDªAs6¨Õ:È”¹ç¶fž± 'X‚‚ÒX0Ì$=Pßêå'°PíW÷ßäÿ\ LBêÛ¿ÝÈV'ÛŒx±½!´¾‹„cBs+Çɨ<=8°c0á )DGXiE‹Tðp×;ž‹~8sèæd5!͸\!Q,?µ `t²ƒƒNbÛü©ƒLZ†Ì‡Ò<èd§³ƒ·Ö¡‡'ÛÜí&´¥»B5DM:„…›TX{Wg:ÝÑöBLVð¹¬áŠ™}N+®¼+5! "F9D¤Â(!“·üjR¤Á(:£`g`”UË4™·:©íj§¹™4Ä2¶A ò¬>$3õW±Šß8X‰3ã” Q\c0Í™^ÎoŒÊk@z;€3R^ÊMÃæq’¦ŠFH”:´}ô‰íÝ»w~¯­ÎmZj:å]ß\¾}ûúÕË+Îm¯_ò_å_½rH"ð£§G÷¿/b7›t(Az@†$¤ÍkWõ@#\[Oü¤n kj'³=±VAåRNÈ`4Kì ,t&s+·ÔŽÂY* ¼Yš¿q¶Õkdyˆße]I$fêƒ(¥f!²Æn!ö€ˆ–mV £d"°2„aî ;ª¹`ËÏÒµ ! %ƒqàdæÍݹõ¢u+ŸŒçˆr° }€ø!d¸öW_Pd5ãså b`S þdx] E•Iÿ®É#(C¬ø.ú˜R(-qR‡hÆæs ^Flão~ȬùÐ q ߘŽDa…‚u|¢9úÁ‹ðîÖM#¥ÒâểVl2ŠvÝŸýÌ®†#m褅ˆ¢#@㇬nH4fOÃnΠÄçP™ieî8*Ê?SÊÌ(Ö¬«4Æ¡yŠg*•Fq?§n+(§?å¥!'§ÄŠ0ƒrñÎêh­l§€†ÜfêþîýSÑ eÛHó,¢/Tû„#óõj*Ø‚ô4&x޳ ”ø ”R㬓0Ãbè§ qu qj"NÉ<àE;eѽ¢4^SÔ$'2‰þ FÙ(V£¸žŽ Ú{MyL9 T{W(7uE=Û—úo¤·üͶÛÛ·÷wùƒÀt_¾”I~^=î+B?uI‘A Ü‚³cã”òé_ñÒfì·‡žƒäO©$¿  šáélÎhjîx1êBg]$žbz)rˆ-£±ItÔGGjÑ¢FS5N\Æ¿ô͆S‰f²Mç8c&µ oñ7 Ü#bñìqm:AÂ~|‰«:Df:Joø£&„/¬ÌAýUÍtÐþS¥goùî4Wé)]µ¼Ýû <5e"Î Õ’®A#&œ°êGmˆI;jFýlHõJDgš‚èSœåG…¢ä†5¢—B³ÓvFÖYz‘¿¬±™˜@êz°I­ú€“uÕ&ãç œç­6¤'>‰‚R›µâVÉCÐ6ä9à×B„Uà.¤òéáÓýÃãÝí½Húýwß½ûþ{>ÞÆÑíáQwÉõÍÕ›·¯¾þéOÞ¼}ý“¯¿zýúÕË×/o^Ý(;~FªÛ‡®Pe›«7¸½{dÿw¯É ª¹Ò‹tÇWM…jß”‚Ö¶¶I|sE)NŒíj¶…TSÔÌ]OM0üË:̰Ÿu< ±O ‚ª»›j}t Å•Ož9þ3"q5ÓN©Và4j­B¹öhÇå!<‘œ¾4驤!\KF­¢=‚±€¦èxÓšLò6¤úè#Ř9püÚ~ÕÈÈĹjF©8eåöˆ(ÑIžnPâüSþÌ­51^M22}GšqáþZ&W iæÃ‘óÛO8‘ö'V£Má2SÉè‘æå ‹ëFhß4Ãǃh»T¾×"ÔÄdm <÷E/1Ã!6íµ”r—ú˜E¹® gî5RŠªAñ¸8“Œ‚€_/¼Ì/¡ë̦“—rF¤má5.1!8ÎT«ÙyÅï!ë¢~~-£¿˜‘«ö‘Eð/ð N‡è¿ÜKâ_à<¼gSrJb]ÌÂ`—ðΛ†myÐï åßü½öWâô¯ ÿâ¶ùÍâgÿ¿@kã7„ÿª/±‹øŸþ½¼¢½ök[Uç4©ª´â]ß܈ÈñÜ'ÆþŸyC¼…ƒ¾Øü¢ÖÄ)pH][¡½8þl^" ‡®Y$¡”·wh"Š&òG~Ás¤‚š©?}B´r¦–þõ~|ä°}ßÑŒþêAMKŠs¤ã'­™”,¯\¼N6Ï¥Æ]M2Ñ lÌ<im=Ҙɗ§ˆ“Z`•öˆ…³ŠÄW3qÎ}ê‚ØF<R¾¿»[S ¢Û¼!a¢‚°F " _uºϺÏF!R <}¢§ù ’€åƒU¤Äfx½Øü;‚ªï`^A¢á"’Sй¿å?cFSÈkðh²â=_â8r!˜2©Wâ~[¶_óJD¶óB˜3’†%ÿ8ØïWÚ*^x ¸¥±ý”¿ƒiŽÜ¨[d‹¢ë+2ªXú ĤéØZ-’Â{|øôpÿxË#½ýöÛï¾ùå7¿üå·ß~û«ï¿{GzŸÞ¼¾yùê꫟¼ùßýéÛ77¿ý;?{óöõ›ü^ÂÅÕƒìµäÿZyrÊÿ•Ï„{Ñ ÉmWC0BKÚ¹¦Öj¸¬÷_¡MÒénZ”X©è²{§‡k4dúv\‹ª‡ý;ÊC(šèLAj1¹ÑôL¿¾ŽND!¢àË Ÿ°áˆ"e’ -*LÄÐ!ãê`µÁFb-ÝQ¾ƒ (û^‚ñìgD…KÜÍ?×8{ %U,™æ'ägyúL3µà< áL—‡#¬V¸ˆ9µu>]ÜÞÞ±‡bh±ÂF†#U’ÉóÕýÉßä>`óQØ‚W:-;Äñ{ª4üó5€I[‰mjDÖâ)XZ QF¤¹¦·ÀLßæO(<‰8ªÝ?¬_š‚E”ÓX°€ˆ¡w:vÕûQë‡0c‹’ˆW yÜ$Jb©W”†uÚsáÐÆ$„ ‡9‚‹EmÈpEq„)Û4Ÿ…Ü&ä½q!žsD±Š²8qñ4¢IÒ}fU’Añ„S6=üV,¬ÍЊ"ÂÆ•üSô19œ"¢®!¶îùõŒòÐ% S4Š*Š+ÿ”¡2ƾ"r•hBû þjgIÍjé?*¶™ IÝšõì[ÄNT6|-†®¬ºiNÌ¡ÃdØáÖk9ZÊN·‘j5)z6ø ¨ƒË‡ß½ÿžï:ÉÅêÕ«ÿc«W?ùúËׯo¾üòíË—×7*7ü‡«œ,´×‹†PÌ # Y—³¼x`3[ªrê°zè,X æÊ¹Õw(–¥O¥ä‘Ãü³˜¡bݱ ¦)±ÎmR³<}ÛZ¼ò2¢‚_hÙÊ êLöA¬ Pé[§g“b+1¸°×·£·/ô²6½Î–ä}R€´À-Áš­BÂ0ÿËbG±‰ DüMSßËàP[%ÈD×}AlÓÔÕŠSNj˵Îaf—«ÛàD¯gz[­D:¶Ãg^m.Fˆ§+¡ÚF±Œá ?œ:üÂå¬ï.‘k0= ¦GxÐR‡8STEjJç$ü»ES=]›©…ÃàœrNQ)¨òUûNf¶# (ëÈsÝf@ÒVx-^ —ï¢bXFÚ;ÃsÀrÁYæçcl½¨v!ÊV]›”Æ©ŠDl>³eÐY¶Êó°^UÜ4mØ¥"]æ}‘yšjDx™­"Ý ”§)RÒ™"”Å&ºZßÝr]ʨ'ÔHÕ§)—Ì‹O˜G9°àÄkaʧ»RƒC‘Y “ß-½ßp÷øÈ·Ò”-A<ß|–²}ØK”’•®œ3Ζ±-ãráTÉ bÊ›òጴœœ&’Œ'bzuÁ%kÆË&ž+bmSéˆY†zíÒ&ô´ Çj]çÁb“B8a'ÿµÆT0Š7líœØÔa¡SÊ[h¯7sl‹7kNJ6¬d݉½ôtrN¡³§EºQâÀ"îÊèÔÐ…¹ÝD¡ƒtYêÑ|¾”UÓªåã¿PìiJ4U§ÇníŽï:¨R†ã*|›0§‹fñí±à¾Z3”øü{Kͱˆ|€gÁH+e‚®%86å®H€ÿF†zEø«f5a®(F±Np\üƒÿôïeê}¨;Ù@Iuh~NÊ{ªQP¿¤Ÿ`ǨÉ[l,3gãµ¾Y.à9²4 iú½j ¦°&1#Ê;™Y »Ä¬ÅešÕ2CM9”K?²yÇ}CÜp>}â½âQV­A#Öd¶@RÕÙ¤<!)ùÑà-®T¯jº•&ó‘jK%«¥NzƒvµK@uˆa¦)ì¼q>wmM9—fhÕ1Æ*GRqîîîŠeD9H3ü <“µaéêV°éÑ6:ªe•¸ÊsêA”cÍ4ãHÊzDK-V£ãù-­q"ˆƒÓ†8k½b8è™Æ[½dÚz±"áVÄV¹‰VVQµ¸]AzŒffi~ÌîëçDÒÔAhû”0¾ üC™¸#Ðäj* *l#¹õ•ªõdb-|ipÅÑ)Íñ&=™Éª8‚¥qr m¿ÎÝMRó É|šƒè_{s /ÿxôÿeªSZ~HÊÿ’ÿðáîûïßýò—ßüùŸýù/~ñÍ·ß~ûîÝ»›››—×/¿þÉW_~õæ§?ûò÷ÿ·Þ¾½ñòÕõÍKNqÊéîþAU ã2 9 5$‰K£sÙ2œVÁÿšPÂE°,¶ àŒHm{Œ‡$Ò®øFt¬»l•MÔxã0ÏBÎd¬N‰oƒ¦\5Óá)Œ~ºøÉ2æÑÛs¬o¹ !]²,õíeo˲µ˜ãGP®,,ÿôËu8‰žŸ“Ž4ÀÆ:BhI£fDò¡2Ìñ0ÍA DHáà*Dph5ÆO] *½SÇ4VL——ŽP{ZÇR4Ð.5C‹O¾Ý"²°›ŸègS%dóC0RÆpFa\BþâFÆZ2Ð0‘‰:ÐﱉB-š ò>(¡hå‰]C“Ö_C(· Ú'ǯMªaœšÿX|¾GyˆÁ¡yŠTø|¬®2VŸï\šAµŸÅ©KÎX„X9+žâŸâ)µ•ogÏySnªŸW‹è 1Ÿó€œÌ? öÓ!°ð­ûtD´¥Ó&iÚª¸n6jO 6lr£žÃ*Ý…Þ쥢ÅIr?VÇ0M#Ë­ágJH¿ÔcÀ+öíÀ-í²É­7•ÒúaØaÑÁÚÝ®û Zí©¡ ïg²„›nëÀ#]Ë€C›ÏÜ $”@hrÇ †qó”©^[ŠÅJç@­É«õzÁ^+³‹EˆP‹a>N*"2èÀ½+ ÓØL*:Òr®ÒœÏÁÎHó”yà ÙS ±„K}O<ñð™X•WÛ³ü•)øFl¨eNÝ£U¶i}èìï!Ñ"=uxÈê,Hª!ý¼8 ŠûØ…–}¤•[ãâ?úÿû¼4Ö‚²è3˜’P._¾|‰«x±,A¬„öN´â˜HíÆJ7Žï·•êz]ƒ+3ó$ë´Å4gíþ#×ø2ÃŽÒ*C>¡©aàe¦mä17£¼^¢ógÓ?‰£“àúê:±²Œ0Kš²KzÁ†¢KõÀ¯ä€üp‘¦¢{€ýl&'¡^`cõpu×úNÌÉœñR¤9üÓ¦0~B¤¾®¨f|VKÔ" ÄÔàˆs“z0Ì`gN)Ùª‰Y›¬úC'%5ÃÉb }€;>y›GK_j÷üòìOƒÆ›:BTC̈Æg˜Áaä…Húc¥)›( 3Sï8IlçÙ>j>‰ [™·E)'~Ã7|êzSV íªc"0bÉÞ9¡Ç<œè¨Â1ôèX_Ñy)‘pðPD¿Ï8|§VÓbaY…[9‚h†Œ¥†”[¯ÍKÃè@ŒŽVÔôZˆ4X­"›éÓb#œ¡öF3œˆ¹ûÄ”è ••=æB¶G?ØêÃŒ‚ "Íð…ø± ˜½kl…Ø!4_wˆ }ã†I§‰ìy ž¢ë,žäyMCúR^ìÆn4VTxí1<ô…ýÈé”jq)EšÑ a'ÇÁ ´\îïùÙAJG&UKdó ýŠS^ (¢9+JíÀ=u»(£çûŸÜúEñ0Â܉¢ ”é’ì&ÈôËçK¸ÁÚ„ŽRc¥ÿù"7A5αQí¿jŒb=RZP‚ ͨçôY'#z^íŸΤt.GÝ€;í~{ ÿezTb=M‡¸;T25°=ÒTì²Áó)èÙ¦=ZÛe6‰’Ëù«?OâO­q_œå(WïžëÞxÁ£_æ…Ç|7๱ÑѧüpÜ€  wN×"ÄZ¬Ü áF±xžÎA¶•­ó°z^é¿ üÆ]Ó©"ŸÄ¯ß£·“ùÎà t2Èá)”Q,£X'(q£¸¬ŠÁ0Cei¬™…Þ–æ”´2³ â JöãQöŸáaÓøÿ¿ÿ;6#CC–Ÿg!<ŽŒ&Ÿ1åßÃ+¿D ¼EÑ Œ|<̰ÖdÈgŸ1ÃO¤‘ã"ÊÍÜIëŒ^ {ˆe”Èÿ('Êv?iÄ®š|yüjܪjnb¬õÍ‹ µÕO>3«Ýûæš·%ó~:¸·3BX“´ñÓ¾ySUÞ-U>*X•"ï·Ù ÑíBu¼ˆÙ]ów’0F¹†ßtDÁÒªŒË‰/yërÒªÙlˆ£óê!Ìëëk1ï—÷Ûö`ˆ#2òZ°8"Ֆߨ"^ê`ëdÓÖa ë‹’”Uæ8Ÿ·ç/~òçÑyk•r˜Î†#WñV>ÐÃD ÅÚØ2¬$Ö'd3£’Çç¬?]jÝ[ýòÓã%„d´‰²I¹Õ³®uMÒ®P$WÙW•|ÚÚwµ/0Õ~çÁ³ äÝWó]¶ðhl_¸”—j匞erÈ ÊÆcj©ç²Œ¸ú 1Mövésò ‡Ôä{D\5žÉ¶Ô~¿My|º¸Tÿ3ÉS\˜ÛyÏÍ'Ü ’[Û…¥«([€¸âšY"uÆ­My‘î˜`€›–Cà¢èÒ6lbc…zéñà§cï"ùˆH[}ÙJ}»÷çÛ{/ŒŽLRÈÿÿ¿ÿ=›Š‘qÔ^™—¤â—ìQœÛê/yá+Y–ŽB:ˆ*9Ç—ïm|w*Aœ¤&>£Ü>`í…03qÓ´UøVâ.5VÉUUšÒ!¶:$%Ò¤×ZôÜelY†^YãÔ&=l|ˆYÙÒ©õÜ–5ÛA…â-]Œ]¥ ŠÇ©:„ɨ»‚nŸ—”+i’†ëÃìÿºöx!DGõ:P–|ˆÍj­ÍÁ±Æ[`=‚f…·ÏmÚ ¢PÜ üÜ9¢À­TþÎó ÿ„È·škïÀ«/i0!søs æÐv?Å™Yõ¤uÒK;Î:ÑCˆ¯¡="#×!gÌ£FôþiX80÷Vñ<÷mpÿÄÏI# ÈÄ9%ê…mþ ÆÊnF˜š‰дP³sˆ‹M§'ÑÞº5¢C¯ƒˆ‚¸ Á],BÓç ÍÆý½&—ö¼½#¡Š†ôÝ»?Ü~xûþÝGá¾ýæÛo¾ùVç¶_ýê;ãî¾þú믾øâ÷ÿàwçw~öõϾøÉO^¿¼¹xóÅÍåÏTü&Ó%ÏB9öM¼žÛ-3ë͈3&ˆ†”ׄgµè¤1wbåd“Áôðì²yl~ÐŽÃæ´ ͈Z•ôÔÑ”¶šISˆž *´ttïÔŠì9 p.HC~ì…k¿*ö¹M.4bÑómç-ÓX}ªQ€ÃVÄ´Q’W…«p„HU‡hL'ÊÕä¬ùŒâÑ"ðÚã_.iæÙ':¿ZfjçMD ¦¾FF §îiøˆ½Ø./¯Y-ÝͱZÇ3¯N1±t¼©¹ò# !àqº¶RÄ9·mÉD3û˜VY8|4ˆ×PS¶"R‡Ð]" ²Ë—W:“©/xCÃÖ '·éæ5]H&’ÅJ\,–dŒóç¶á¡L[¿R¤$„8Òôá˜_•‹(šÂÁ‰šlQð¯7±~è.Ô˜Û5t9¥³Qdu9ÃÌIš.ñZª*ì\äZ#{Dì¬m?G„/¬t¡F`‡Q³5¨¦ö1B/‹•˜æUu^ꑦ³õ©THn5±ãSÅ4:KÐ%!Q\¶èS샫a-År8—ЂØ3´{`Ûõ@ÍY¡ïšŒcq. ù\i7*Úz4FÔ¾g(i&Î`ò q@ëDJ5*&˜˜¥ˆŸáö¬”•ÓÞAí蜊‚äÚJ/A¡së{èÉ ú%GîôWTs 4†ùTÞ{ëáÅÐ?ÂO"p2˜æ3[U:— ç¦S¢Œ²Œ» gïÂÚpºÔÜ –KÉ25‹¸‚¨(´Ä¢d•‚tØ0¼gÐÁÌU-š§p ¶ÒÅÄ>¢gˆ:Ôû0Q[ñ ÓS{Óùx]Ê¥½›Îº «ï0ÒÐ/ð‚qÉÚ5#&w¶“(5ÅÅÅäÆ[áÐüœ®t=®„bZ󩲤X§ø%§v~È ëûm׺1Õi5E¨y­½Ê| šÎÈz‘ª£$¯®Á•ßy°´ ¬³6ôf#ÄXÞúü¨1'€àLeéÚZ¦;ͺÂñkÓÀ\|FLmÓ~ò…„[~±@‹„mHÏ{DAýb}X‘P]¨ÇÒ‹þ„_ l†!ìWšvíG‚œíyã$Q]à¦=ø >bž&äÀ£¹ìv p螣iEIS'hêgeéÕÓ‹'>ý8Ô ÷°äåVXõžÿÁ»†,ü)g=a¥‚×]œ õ‰¨q¢#x ù,J6¶c¢ ÃOZSÎ\ Y‹;P#T®üœæøas¨Ç¼rŽ‚ðøBY‘IšèH•l¶Üì4¹` B®åÀaýNŠ|§Ä+c»©œ#¢M(÷Öo×IÇC<öHXv‚´!þµ9}è%;zŽ ©‰H¦œÊR•H¸¾¾Ñ (°€m¸ŸBV`²UÁ ï$ˆR ÒÍí£šmçQÎ ùýx(œrµŸhÐmç„6Ϲ2_ªXVz$«z/ÍšÒAY2ÛzuÑP©]ÜÝÝ÷«÷?Þ½ûîã»ïÞ¿ûþý·¿üî›o¾ýæ¿øþûïïnoåãç?ÿé×_õ7þð÷÷÷~þõ×oß~ùêúå‹Wo^j•M#ÀR—¢ògåèõ²º«8"퟼ý,°6äá1`-U6u´&ïȉ—ý'P,a%lû±Ñdj¼1P`Âñ÷yƒº€ŠÀ͉šÈä€ 0M¨2’>·A øù9é䟧FžÀRH¶¼ÙàA•ê(«^dz8aÊ0 At‚$`»Ê\µ}–C @e8ˆU|Ô ê«cŽz8‹â¼ž2gJ6j+â_Ò©…aNïÂ"R-$ b&mY_2~43bá¬#&Î(ÄÛÊ7’†úUÿ«3bwªcÈ\ÄÔŒ‹ŽG5Tm"}Á­‚µ*Cß 2ܲI­0W×üÇ&ƒ@„ào.r_Û¥}ëÆ”‰¦«Á«.ÇËj7äO´}/K®‘˜¡{#Þ6}#ô[•4°"¹+$ˆ|i‘ˆü 5l¨.oùÅï暑Œ¶ÓÓH>'#ìì@P0Ýz…äÇ·åäó‘ˆ6¥ÀqùÍá©|’ªàÀàdÀ#,Õ~R‹æŽÝI?UT7JÕˆçƒoµR~$d±s~«×è§ì¢ùÉHYEú)ª„pŒ»ª±¬rÐ:z‚>êa¦×לñT‹î7«ôxñÉlÊõö>Ã'}‹§&Ê~Ïl’ 1éÅŠ9‘ZÎ ×Añï;[û,¾m))1¥­rjîœÅWò?~?QŽÕÄõ²Ú’›²u›8h¼œ +ÔâÝbÄßöhéÔKÂ:NLr9M6a†îªZõ¢ß¨á ž.7¡$5æzdÖ;¦ð¨¼>´ _ºˆXÜkgÔþ¯˜vF6OoÑøg ?镈êøS¶Pÿʵ¯ÜœñH¢ã½š®îDÑŒl «å‡ùœÆæA(U›UÉœÁAšfàY“ëj®Ð1˜ÿ6ŠûT”ò¢!*”öú¥t=¿`»aµ ]Ê?ä³dO#:íiÓs‹ŽˆNÍ¿<ÞÍÏÇ©ÕYWÏ0…j.¤ÿ¹Fñ_8åf?B5Ù8]0ƒZÍê1 ÈðR/ìVñQ³B¤½‚˜Л_¥·–-žu¾leU(Lbm¬z–ý£ÿÿßçÍ4~IŠ÷Û´V³^;›¢ªº‘}X%›ô '@5sÃ"`ÏÁÔ*(yWô±_ßlèv»$ jÞݳ›¤áó¦•𻽵Á¯übhBó75â“„®ndäØ[Ü(“­k[ â+QËw79¥ƒôµò+˜Nɽ¶›ô£#¡àxK.?Z6Ó£¦\i©&·¼PÀEC*ÉY¯Y¨ÝÄ›}nƒƒ— Ã2eFÈKO˜µ›~u⓾sòèºzð)]ý齌Á.OÿAJü#ï1d$­ó—â(·+ÿSÚ{fÆï·Å+µ,=pŸêDå/±Æ$r{’[Ôðý]INk䆣F’¨mnU­Á2¼¸ðI5†ØB†ŒâÙß#·µø†9‚S¥bYSÝÛYˆˆ(:Óš=_úC{6­ù༉PúŸ.J•AÏï(]4ØÜ¨i1ž‡|‚XE5-³ˆÐ  b¸ªKDê†hŽB¤"k4‘Z‹8JB+U üã&aÊq8Aºzþ4eZùXU4¯_\}úÄÛíÞÛƒÿÓà'ÊP“ ûã…n¾»»Çï¾{ÿñÝý¯¾yÿ«_¾ûîÛwþçñí·ßýê—ßÜݾ×¾ºzñ;¿û³ßúÙ—ð‡¿÷Û¿û[_ÿô«/¾|{sÇÛ|Ÿ¹ÕS×ê‚ÜÓKºéXÎVÊ-‰Z¾Bª0ìù*m*÷ÜžrÛâFÒŽµ’ 28<• k*5¹ Í ‘LR u—ÇXûðT'1öu#2ñ]gx‹?5ð<ÛWCt)ø ³W )&¸Œ¸7yúˆ-ô4>~‡,ˆ²ÁÇ‘=P¬Å¼c˜ÔœgUóÓ—†tå^ÌçßoÓ7 K%î+!¨#B«V±Í ÏûDÓð*Õ׆–gŸƒùíêO ©4ÅÁçIÃÅÓÈš™PL=“Ü/]ѯÙO$“ޤ›Ix:¥Ã’œÈKB(2ªá W±¡Øí-p“wF4rê‹êzñÿÉ?ô¹Mç‹þýöôV•Æ¥º¾½å¬H^ žÆl @ê<­Ý]Ænc†`:@ºïº—/×·}&…t2þŒ¹ê¿…&ø¼t-¥D™XypE¢€b¤YUªs£f²†»Ü’\ &9  E†,§øNP!†ÁŠ™¸ÚªÐ¥ˆ©¥éÞâb—ž î±¨/ýÇBÑÎ9eߨ¦ªÆwׂµøÆ'¶jhpAl»‰+Ö4J5¢T·Ò1ÝI“Á’%‡!·ÿ “›B£Ì› d‹.o-0Ÿhòæ7ÌÝÜ£‰oÿµ€×°ˆø9½êcvP;À‡ÇªÆ‹¥¿Ò¡'ôÀ󷱦¶5“æú4Œëò]"kÂ]逦àIG‹ðþNS˜ÙœE($rgk Õ[¿ƒ1Ï$¡û–ŸNª©#NÎm•³o#¦LM§i¢ËFƒ‚/#¯‹œ4‰«&Ñ;sĬˆÌ’¶"æÌšÇ ¥øòN¢/ß$Hl ³jÒ¥«šØj–¹fMÕ‹]¯?½¸zÔ¹íï„¡‹Îm~MÏlß_úz|q÷éþîñûo?¾wûí/ßû‹w:ºý³?ûóï~õÝ÷ß|óp÷Aëðæå‹ßû½ßúÙϾøƒ?ü]Û~òõO¾øêËë›Ý^åBÝ’‚sP¼zºk¢é0}ç'&Úi£°*›ÚÆJÈPy$tFù NépnãoI•èáËN¹Ëu^¸øOþɨqçÌÆ±M)8]e²r„*fæßß g]‰Ü¡k]<É@Wö_\aYCé Ž< :¶)átàQ¾ya×9, ø…’bÑ´êܦddîs[abY1=Z!A)0Wº1¶rêFͤzÁE׸V'a@9Š—’¢ÍÐ{oŒMBøRc…‹Û1æÂkæ™ / &Gœ¸ØDZ˜Àw…E¦Ï@æ3²à‹_÷bjà˜'ãœô*_ÏÂäàw2¤A±©·@„êEš<ë˜(M¶jü*®–h~€ÈôâÓãŬ=ÛÈ€#pVØ …ÅJî2 Prúž¤¾š†¢/ÑÁÂ÷åtœU=5ài<Ó°™8©?Ü|Ÿ‹®ðvESð­T§ZÛ´±Nئ0–s›øâ2¤ÕæfНLñÿhªÆ¥;3 <(xp(Íš.ÚVâñÊP­µ€FªCá'v ]©;¼Œ¦Ÿ7\ÑowG³ ÂõlÔD±»ù÷,Õ5J펧šÎm×¼ßöIgŸ,åäBm‡wÛØ±ÅUãáîÓÝíÃ÷ß||÷ýí7¿xÿÍŸÿí/¿ÿ§ÿìÏÞÿîݯ¾ýôp«Å›7ÿÒïÿÖoýì«?øÃßùùïþÖW?ùêÍÛ·—7/u‡sgøNO…äˆ{Å<Ä•o¾[§kÔÓèY= ”lùÛÀþ @›²E« häÉ‘Ú-ÉÚ•EcFš¦}åF6±ù”qùÏìâ"T×4M«dwê›Þˆïö%F|ê»ÙŒ .÷þ/s‘ ÚˆCH®(z J4œZOz±tj Ù,]•®^|º»ÓNÅ´ˆß5yMÓ. Ý£åŸð5(iªNªp„ ”ùÅœ2±lBïBQ# µÕL£)29©‡<†µ2# â?™ø49Np›©Ý4 # àgösnÓãÅÇq ò³Yf-°9@Ï«…™X{Bõq+âÓÇÍĤù„"~†ŽÓ[VfL|DxÃÑIަD­ïeÀ²%{5%RÎ"ÔÌ ¬÷ÛXûòš€‚«!¾è ˆLs›ÖëýÃ}%cF3Æ®æJ'WX±¤œ´}2c^…èЛöÂ’díDíã°`ÝÍfÀrx:åDEl ¤íÕ¯nYýÖs›ú˜Têw•¥ÇjƉ_(qh»üÄ'LMs˜SvJW¶>ŠÝ³bmrð ×D¤#Áa‚<0–º7ÎÖ *m´)K½kÛ¢$`×0ð¼ðÔW Bí±°Šì9+Ap¾FÙÔÏ¡V ìzõCêm%¬ù7¥ü˜ snŒ—%FèAíÐBK2\If·©~¡}É"´Û± ¦1AbŽCùÜæ»J‡84 ±Õ—?ÞÞóºWª·Á¹ÍæèñQöØÂ’9k#*gãf!ɘY± ¨iO; Ûcò ¢+Q÷Þ O!jBµXQ¿z(jè5î=g¥°‡ØiFF¨v#j”,S¶AMÊ)²6´ú½µïI–‹óþ¡‹ßpV7ôð{Ð3G‡ZjŽB&}´£XGœVMÙÚݜ؈*we6bÄxd=²”Ùdïïõ¹‹(i“»¾¾æÿʿԕqðó€ž ¹S8{龓ŠD³ Ý\§ÕF…]ÓYO;DL\a³å1MüÓà ÅbY½ç)¹13B‚Pf{àö/ º²„mÇÝÉ$®»uĪp@< Õþ<”Q¬Æ1(½bFíü`‘9+T—k4" ¤¢iÄ–)ß9oµ¦Œr´¹Ýœ ¶[Ï$£CK~^”ç<ÔÂtˆ¸Š(ô)"bXÜFDBšq[¬Æ¨•®ˆ¡Ú±]Ê¢ÌÀ:3ÉÅjœe®¨` tÎ’O¦u{,·gè‹üOþÛÑ ÿhO3tá—*&¦ü €?=,ÊL9ѬóíMÐwxv¢p¥é^ÑKKOd`„3Èž”KG(̘ø~¦iˆ˜q1“ÓÛéµE´Ñd5MK*c…c(–÷ۄɳQ¢¶³Ž™}Ñò èÙ ¨­´Ä¼ºâ/,(Ç«k¿Þ’ ª®Ý/Õ|¶ßÊq•ÿŒ½?mÒmY×ó êûªÙϵÖn´Î±…ÂßÁ–åN¸!€A °‰àg†€ ßàA8ø?°±,KGçì½ÚÙÔ¬¾Þ®Šûºï'sŒ÷­šs͵ö‘D㻲r<ùäÓe3räo×ú­4xÞÆaXoE‘­9,®#>ò±7îb­Ëîk+í³Mx®DN£à—0ÔsNŠ»¾èAÐþK­ÖvLÛ¸ÈÒEVSFÊ˦îFó—^eÏÏØÖx»[öõNL„c¬XˆƒFºÖü†pÆp­ç¦:é"5›°¨e¸;èæ™9ÝX;>ŽÁ½m}Zøx´ª\'‰U³éŽEã‚Ú¦£ïûúÔMÜö-Jv9¸†ÿ‘¦¬‰Ä¨Ñ’RD—±¯ i¢ÛV6[£K²Ih„˜ªfIJ«®ÄATü%Œ*n‡æçmºIF;|*ùnMɯ“ʸ¹ z`Î{îó¼ÛWÞÙ6¹Ï¦w—|aòîÍÅ»ÎÏ>\üðÝÛùl6ŸÞìîlí=}ºÿ‹_½|õòøåëgOŸ=98<ØÚÙõÅu†4/Êt ‹ª‰WTŽÀ"Ë3JP‡²8,ôÓý“¿ÀGUUgBp.ö¢þ_AJ]Y=[õ)^Æ—elº-׿Âg\Ü=êTXÒå!¨™I^!{­,èŠãz *ï¤A±–Ñýv±ð+^¡» Rló½·é ¬JÞK^Ìä‚”˜O##ºw/ß)vfÀÊÍ-­i]žÐˆˆTœvˆÃU¸ÑÝ’å *b¤é‚™ýôÃWÓ0£`;¬2£©HГ¨£*5Ác-°Î«%ÁqÁWŽŒ‘Ëw´„0wf¹ VŠ‘_ÑêEœ Ñ&ÂÊ!,–Ã$-œM¨æw½«ëy›2µX2Tq±kÏÛ4¸²G¶¼K\yçÈ”rûÁ’Å飉ÂHxÌ !Ø‘Xë3>—à=W•Ö¬…²AžFÙ›'j5¥o¼¬6QóìÄ“ìtk\¢éj[Påe86 Lc¢21ØaÇMߦ‚*?Õ¦SB>åz É©mJ+ iuGqöOBÅ÷x»:3=‘±#©lÓ„Ú ¾ÎGÞëí”OÜT­«µàhŽ{²2¯+—ÈfK[\Ù¢ç‰oŸ1N®2Wßu.¯ŠG)´üÊ2Þ%f‰ÂD€ðF)Ó¸Öñ¹|T’±’‰xdVPuI=e~J2FdCøDJo(w ‡DW¯ `õ€›ÎªÁâg(ŠãÑTK#Xº+©ÉÐ1FŠÔŽ"4U’kc¡sš«f(6ÙSf¨S¤™÷L4Þa)3ìðòœ®—J¬³‚Ÿµi/(NÕí]cGÈÏZ˜°‡r§W{ŒT#a-`W0+²Ë6E'ýT”"¾p 9 "Z¦Õ Ûjܱ߳þ§ÑÅ¢òK A*ë¦ûˆúHëq ctD¡?-ïaöí)Hž-5ä²Ñ½+OçÁUŠ‚Óˆ0¯H–ùêvKèËJÌa i’ ¸Sœ„J †‹}UyßÖŠÞ½ÁŽsDÃ’ ïò«ÎÞ[P5>K°Œ´A’þcŸ¬XÐånÉ šªÈ‹Û…q±è&lW?!•VïËêýWÕãfá1;†>ñqÐHUº©uÝæ¤Ý„ädK0©än’`…_ÄÀ^M%«ÿcÚÚƒ˜9–õ8ûÊÕM¥+RƒgFÕZZ™núëʧik¿š@›ä¨í/yÄtDáŽ/ŸNçóùÝíÍtr3»º¸¹<¿¾¹¾½ººDlý~oçèhïÉÉÁÓgÇÇG{‡Gû{{;[Û¼ØÝæžKt>eš}#;%¯D¡ÉFƒd=( ÈD“‚™h 4 ·ÂvCèAY2ßÚ®†A¯b±þM»b¬éâáæD~ ÕáE¬ÔBô¢áRØ­&ë––Ép U•Ü£hKÝ€ØZÉÒË’²7æ) "‹ÕÀ@zòÜEÛ¡b³QtY1̵²ÕÇPƒ|¡`á~кn;Hq(KÂc\¢ð B ±;-R.â. Ó™˜Õ +ZÙ˵h‹ò‘,ÞVãhÅ­+y%„)”‹ÆÅFWN,#4–+ jˆL*9ÓF@RÿÍZžk‰áÓ\Àäø#*·–Ör®Ž‰åTFEU¡+ š~:ò\M¢ALF¬W _<Ô"_5E5.‰å€Üº£TBÄn’-yÌÀcŠ$~QezÉýç"ýÞÍÖ@¹YŸDÉ5„“ª wñ#h­ë ±‚ð…N%Ølÿ½CnŸß¥AJ¿ƒáK¢NÉ“a M€Ä†'©@à"&|Ó´$y4Ç­öˆW?P• ëÆ¨h^ÎäéWYðwæúû²ZZç]J£” k£}%"`¬”¥»»õÍ$Éq1–]覵&š\Fk‹F#JA©cÌ©ÞYVt?–"Û<þHëÉ'CCÀ\½[ÌîïÚÚÚÜÝÝÙÛß#ßÛåFK›‰Ácaµ\½ín­©Þ‚Ñ«hÀÕ¥`D« Ÿ¡MDz,×ÕÄB©åØ’9­d) xZ*ÅÞ Ì—™x1VYÞ^“âOÂ’B %‡ÅØ«jC±FXiŒŠ^8é·b Þ--‡öû ´]·®'W@d}„#ĵ²¤lÝÆhá³ARHD«J`%¥ UvëXŽýVçw|Ž=ŽdKrÄÓ ÆU¡?‚\ò4=ŒÝ%=q“Ƥ´jÁ¥TVZêq,–dÚñôZ‡¨"YY¹4[à­‚[b£ªs—5.ϼመyQŒ4\ï+±ü7»ôùcÀüÏ Vâ—·.0–´Þçe{%UËÔ¬|ÅÄÐÑV_H1(–˜uôhKuì±|µ~ ŒáÓs@q…\J—`ÚÈ­ÖÎú¦¼]|ÕéP´!2ü9V'憣ê©U®óh½å\Éì c¿fÏK÷ë  ×ÜÉï#X £›%‚ –bN´„VÕOƒÊÒKŽ#]ñ#iuÚWŠÖg¤´D”Ñnµe§8>Gµ-•â€CáÑ"è o;Ž.™æE„&èµËbNe–ÔÎŽrdEV’×,q’ú¥«Šä »‰Õ¦&ÓÀ³°H;­ 꾓T< ¯E­Ÿêšö"w·¸ŸÏÙ·Mõ§¤­ÛÝ\Òºrù ¾k·ƒÓ‹iç‹çƒÔÄ!$£œåE9Q†c™TÕn>èFRÈÌé("±å^Y(I’ª,‰÷Ê€j—ÀL1l©ÒcVò+èü^»Rh]Š©Ç`yý+[®Êb” Ãպ׹j¦²_:ðÉwÓ¹—fÃ’!Âa.ÁµX0ÞâX³Ü¥+˵k±MbF–z÷>Nvd ZUy?àË1–—RUØW0î/„©Z1¥&§§'d¥²ƒ©v!ÆŠŒK JYÃ÷²[ó—‡ :ó7yO™×IlÏ«1¨{€ª[ňÏUË¢Í~Ðk+uàwð\u¯¬vÔ*" 8}ÎÊ«W¹±±%õÍá¯ÿ•üPyû­ƒpè¿ôbŠŽX¦[N˜ú—:]åÜg‰i 2ÑMÀÐ DY–ËW/ZvîUXv¥Ù#a^#¡¡m®ƒNS±«2ð~ã'jªur[(bÂUA')»ìzøØ2aÅBŠr‘ï¼`l\ÇÑfÄC×°HG bnò AÈ(HÒ'>áx,’“!MmÚΌѡ¯Ni|$y®‚e-A¦³–žØÉäݺßW=‰Ÿ’Gµ"ò™¯ÿÊU¬ýÙºß÷I­mùX™mU•€A‚(S4ˆ˜™ï”ØD–¼…›»$¦(õ’G VÁÅ!1 Õ'ÌV¨NeHTS4"’c QÌ©šJ=…<ÐÖªv1T% "r†Ja†cI'F9³)ïŸsTI6‡û’ðÈR™¤YŠ;£%~´F6BAóZ‰VëªÕƒ÷v ÏjÈ,^ZºB‹Ôÿ%¦ Wwó»Ù”O0ó³¤×·gg—g···—W—:G···Ž÷ž<9&==:><ØÛÛÝÞÙöW”ç]¸“ýZñ0Jn’ªÜK}8Æ}B¶bÎbt»5z£‚F¦¢_B5|XÜ¥HS%vSJG$·ùô)¬^H1ˆªÉe%‚‹Bâ'äÈslè¥bYŠ¢ÊdH‰M½ì"fÙ¢ø¤@˜¶GÓ°blµ±w$µNp‰ùbÚ]MòšÏÛW8Ø·—aêñ‰®í|žØ®+/§ä)†cB¹™Tù\v±Oó±cSQDL‰˜|YûHú9ep»Õ6må¥0‡NÅÓ–“`†Æ¤|ù¤ªd(«×Û:_ýoeQÿÊÕ_~âf³èÆRºÎˆÁT6ì1-_fBÖƒb˜hÞNµ;ú/;-u¨VÞ”gx1]» 3bäž!ôŒ_'•žþÄI lµJ:TC ±§ÇÙ³e-ÄŽDƒ…ŸfàSV Àœ˜5áqŠE·ÁP13és@?2ø™6?ùú´;7ŒéãC#ªò÷Ū—±ÿy†îÛ$xúïU±³©ã1¦íGÇM~j‡TŒ ±òI[c;Ê!hNØ©QjÅ|¨ÜPYM:­zºèmµYÛ¥•/îïg÷kJ|ÃHcþƒA»ëôïêÙOÒÏF8aLaR3®üˆàOÃO7²ÔEMýó{>J+n{çÇÎCk–×TãÒél¢t;ÜN&>— “jcmk{c{gsw—&l [ºpûçÌçwÿPÐ[×ñ°™ÿFøH÷d]õ¢[×݇ˆäŸd鱘הcqd t!ëUŸI*åbPA7å*|‘lðEw|í¨˒é‚UõxxIbز5k ¥Òñ8÷1ÄoP¬??l’ÃÉÿ88¹dÛ(¨¼¯6“Ühpo iײhU)·tàCqê­JUjcJp½%ýªZ+Ö­­zwë ™ÎdßÔN¹7 Ødõcˆpz•0–Rl=1 ª°i9¥]±3îyÑ©^J„–Ò{U9E©Y£¤sÜ©6CÞŸFHŠÆ·f)6®6FÜÌ×DøBîa–s³i,ø½J\Ÿ± ­ón‹õûÅúÝ|M‰³ºßR¾qÏO¼'©˜‡…¾þ¡è­ßâN×е¹’Qª¼Ý9’„4ÜÈDª# 6yI©RÞ9=ã¢CÝÍ´Ú ÈÁE&z%IÍàC£¢06›®–qRgZ@(Z}Êgu5ñq™@c°p¢†äiQË´Ó|Ÿs .×P¦=¾$÷ÿÆÆ½vÕ O©ŽÆ·ÁGÑù #—y HÊI‡¥ìs„”{²¶PÍG]GRêCs\†«@ÄZãH¥ lÙ½­ 1Y'ÞT©{Z  7]𩱘ϴo“–Ö]Awü:©vkÚ¶múgexâ¢“Õ L%ú-sûr5 »9U"Φ2²ÐÒX²”]üÒUý}ž*“Öy˜ îøÅuN|bè¹¥~ïí a: ÅŸ…8¬Â1ûù Þ†1ИŗýZjx ÃjÈþ)ˆnƒ‚KéüU§e4M\ê Ñm)!!Ð=3à s$ÜÓÉÁ…ÏsÎnÓ»…R3l‰ b¯mõRY… ƒj[ƒ8–ϬUÁa×K7Ãr݇¨ê†fŠ?Š’^–¯ø Ø!x=Z©-55:üØQG¬tL/Ríæšð)%Nf=ŽXîyùnèÂèG’Xö Jð6fï¤:8a6Øüÿú_IБm'1@Ðz‚ꉿ)›GN#5”i©%8Ôô"'@ÙUä©h#§EŸ¥ M&vëtg¢ã°H°¶/qP~ÓÚ8¨ÑT(9¾U¨ËTƒÍ,À^ÇÈR1Âs1±ÕxQׄ P­T)Z.Dj8ý_Aš"9Nd\A.ÒÇâÌ(¡i¾ÍB‰«<­®Ž]›GÉnV’2ý3`¦éØ@ÌGœ}U”¿8òˆ€í-AÖŽAªl†QçpAlI YÆÑÊìoð’“EUÃ-ÈféÕåÍííäôýÙåÅÕÙéÙåùåtÆW·íííî?}züìé“§OOŽOxèæ§mœqŽ­r'w,¬ ³×uÊ} –/c笤†bKÕ…iU3 ˆArgš‹ò(]A‡À §V[-¥‘2ñ•ªÃK4Á@hµamkNC×D(©µ ¢Æ  È’«aS.†‹\SïÌà !t:DËÑí‹y`©’Qê~£(tÉ0;à ,¯$ÂcÍv~FªÑ˜U <Çp5¸sqnŠX‹NCý6@E%G_]×4À´ÑŠÅIU˜Bä•%™¥îd:uáÀuV…Æ}Cç„VŠblP¦Ði”ú†ÁR€-p‡{zD¶Åþù‰nAýÚ¨Ô6BU‚îý|û÷"„¶ª â:/FÂõ ÷ɦç L„*€UZ l5S0v"ÖH06bº#Å‘è@fÕeIteóh¢œÚ µXŽd„Šà1¨ z/tü¨V`‰_’I®ªSç¯X¼T5¤½½=ŽZä<ôÍŠT- tHOA&üÐr)%ÊXORHÝ4nj4Êu%Dx–Á¯^Ϻ Nog“ëéÍåäæòöêüZéüÃ¥ÒåÙõõÅíõåtzÖŽßÛ]ø‰UlÆ©ÓӀѡÚÕ‰Æê«2£*<*2ÍR'±™í:@“Ø x*´¼î<¡}ßÉ çÑ)vÆE[sr,JCéð7j~„K ¾1~ûζR)B¹»NµHJá®4òk᥾kÍrÕu¹åÔb)YÁ£¢‘¹2®-H±¨U ŽF4Œ<†'6ã^yÄ¢é %+…Oåùün2™)iëv{{;åffššÚsmmmðòèÞÎîÞö¯‘ò©÷¤š‰µ6âxŠ›„hGPD’­ØN‡kܤŠßôXB(õ*ñÀ³ õ4fÜ<Ž0]«ø¥Ô‘°?1"Œif®±â­¸#X„3W|u¨*!’©}ˆ’^†ø1(ÈSyt¦ÚJ‰u É“\)kºüóž'K–º‚._-²Ê°ÖY¾Ýq*a§‡ü;<¥8£™ŒLÁ¥%T…Q¬Æ,C#„ÿ(J¢¡¸ e7…߯³® ›£YV–á0£6‚8Nª¢öA‚ï|³¯¶nr]©j#†)ì÷KD\ËyOTktl±‰Ýoþ‹ÿíª¶›<.ôsœ¬K:ãL¬XÊÆÔâ 9œºŒ‘Ó“D6Ñ&IÛsÑU~‹cbá–—æŒÔF˜»Ù®ÕÍ[BVgP #ŘiÅA¦öÝ«¦y{¢vÙlÑc¦Tš5£W5Y%Õ"€ˆÅj±†w0&Ü×ã55žÓVh–×÷R²S!ã"¸?ÔŸtiüÙÐØM,w–Ž0ò8A>Áïk|­ôÝÏÒxÀ6»¾Ò•ov}yusu£}Ûå%_…u}u}}y=¹™ê¢¨ ¤¼ÏçsiebË®l*³Å~q¢žPa†»©j£þÕ.%ª‰Ómq•³ #golBÆŽ‹ª*¶éÆ©EÂÑ=òSÁiEúߦh½Íª‚ni©ÄLÑŠ¦‚*KDÆbôjÑââ̵hU‹j ]U£PPt‚Õèž8å9ñ½rtE€GwЦgN¬eP"ㆠ°°“¶b5ˆ>Ž–Ïù!ž3Õ´ 5Â6lJ…îÃæ”6l`C½¢õæfrvvq{39==Õt½8¿ÔtÕÄ”©£ãý““ã§OOž==yúôøàpÿ`ow‹Ù°ò:%Û™xÉím@Í”5'­!uÍdÄiRë »;T:Õ ]•4Ða¹>c­Œ”^Kdú÷‰gÕó.‘uv…>ÊO™ªÄJ% Œ­½m,(—`d=Ü…0…ÐÊsÅõvH“ÑŠ®"NÃz«H•õ‰îÚ&¿T‹³xqDm€ Å1Ó*¼Ðb’#LÑZTÄT¶çf–©Ø´Vʨw¢¯Zð ƒ–Äœ æ ¹e‡[Qô=£(q4ÇE׃eºÚ¶‡\©L þ‚¨ô˜©[FøŠ(6Dà!zÕXƕǔ‚ܩШÈò+äêÿ¼ñ˼á—ݼtª3îî³ùTåøÂ»Ž¶^„WØhºóªÑ ]ËÈYJÔüšèÝÝl6[›ß³»Î§ó³Z+®..f·³Ùt>¹¹•º(™ÙÝÛÛÝÝÛÙÙ|úìds{ãèøhÿpgwkÿpocsmggccó^ݰQ?,.r{}}K“B—~w­dµ…I|™üiÕ`°!hR´0hM#b‚¯dîzKèßUépºÂãTâ¥\Fª$hnåè<°¥ÛA±q*‚XsœŽŽGc‘ŒKv,ƒ^1\k.vS“3}`¶„¤ë¨í&p]LóbÈ6±¸Ó7 ºï÷¡Àä)2 ”ŠD ŠrÿºêÝÈŠ59M<‚ªªí¶Ð${T-+çHÐa5íù—o'ט£:ÞÎéŸÉ%¨ûµétöîÝéoûî+¾þúÛ‹ïß¾??;Wš“¯^<ÿâõ˯¾|õåW¯¾xýâøäàè`Kó³NV>²J¨D`Ø.ýWeƒˆ@ ‰˜ M mP6Èz•ÆšBF‹Žá4A fÏHô€iU!áB:ÇÂ@QåêåÑ’˜ŠM2§Ä•Cdõ6§Ð9äkAäªõ´òfÖÜV§¶ò@$Èѱ^Ñæ3~aÏÏLò°CºöJÊ<>A¢ë:^ÓT”Q©x%àòصÞîìîJ&Þ‘‚½~Ôim;9àÄo;áåWò¬(FÛʽz…ÇšöJ’&„SËQbajäBã¦è®xî_¤¢4Ý=™’Ýà–p¥B‘×õø«D#vÚ’¢ä1áÁÖœØ2¨Ô®0Rc]šÃ4 \_ÂäHǼ%¦®¡Æ$Ǭí§V-Æœ˜ƒó¢èÓ‘ZVÆøàÂ2iJQ4‚yp®Šæ¬E¢=t]S[ö~”’ ƪ$‡¦‚êQ63óWe¶Dh®K%]ÔŠAjǹ`­¼õ¼óÔP3n«Á6ð[äOÁ'Ôš—OA"IÝZ>¨_W–›Ç!CêC[¤‘$Ñ×ÂÌ·¢l¿Òï YèóõSXn{µkÀ¤2·k@I4)¹b…Òp¤éRçt PÝÇ»Óø–ù¹¿h~z;»¹¹½¾¾áYÅÅÕùÙŇÓó÷ï?¼}÷þÍÛwß}ÿîûïÞ|ûÍÛo¿}÷ý7ïÞ|÷îͧïߟž^^œ_]^Ü\_ÝJ]ðy"ÃØÎ®6Á”ï% 3”eÇ #…%Ö€¨ô´„GX ë®ÈŽ‹k?‹vùAñãý ˆßÓi7c5ºç^BÓÌ‘w%¦Ç§Ñ4ã«ÔûcxlLFFâÓfWቴԂ%Ç6v7¿ŸOæ‹é‚Ä[1±¯q{ßHØÙÜÞÙÚÚÖ ­VcVŸ˜¨>ý4ì’Üjù3ðˆ•Å£ÒŸ6Á5WgwÍœ<Êüýñ)›ãºq¿Ò=+íl[”AŒded•c:{•L±ÏGãŽ.…Âàq5RI²¨ÒÇß#C^Ûm2çâ²à˜¶£×BE~×÷_VÁê\^ª]r1T…vqIwî;Báÿ ¬lw~õÞZñ$žT…ªôŽkEkÍȽ„ BE °µËéÓAñµþoþþþ¨Ô–¶ì:¹§dË(šÛ ÝCÕ0ž½{‚ØT ×­õL}ÿÚ.«oÃÛvC%”ý ::æuÒ0•£ Õ÷Æx‚|šâY•ã ¤ eq’¢oæbÂ.†øÆÏÛÔ#©Ÿ2ÂyÛ;Tà¾0®GÀ=mõ ”K9cËb6!ˆÇ³ ŒÐl>Ìâþ‰w é€iºDµŒŒ†›!y÷UIºr×X®ë=.Äš¤´,ønÕÕ­/¦Ý:Ð)$*¬®CGÙâç€fÜÇñsíØ&Úl8›ÜL.>œ_œßÞNÞ½y¯ áÅùùìf:›/&7³ûÅýÍõ­–ƒƒýÃíÝí§Ïžìîm=}ñääÉÁÓgG/¿|¾w°ýìÙÉîþÖöΆæ ;ckcm‹çm÷ü‚$ xN*Us4¸4VQ¦nI z¶*èA½MÞzÆKjk2±„œÐzÝ´ó`t»0„:Еæ{00VjÌ Ž1/H\sTF•¤£ ýéŠ!¶‡˜¿?Ò/ Ì"îí°yÉ -¬PDÑ@WwiV”QIáN$rvTÞ c:MŠC:™‚¦×HRèÖ„v·)¡¦C¾’­1Hn·«Ö.Q#„¹" l6'ÇŠ£Fö­Kšºæ.^g ÏÆ¸ 3=6ïïx¹ÿæjzs;yÿöôëß~{uuýgö»«‹ËËó‹Éäv{kC;¶—¯žõå˯¾úò«¯^‹><à{w7;nÞ·6·‘% 2´Òá¸ÜøF:IZè˜ošcŠCCnJ}ú« ¶aj–Ÿ·uMá‘kެî‹7Ñ›©\L]×îN¦­Ñ¦¬ ÅcXM ¦:Áil=jm'Eoˆ¼Ÿp¬¥vÛó;ˆgf½ˆ¹Ÿâdó" ×j™T´ݹÖ׌|Èe‡þÓUÇyþ#Öì"« ×XÄ÷½4+ÞiÞ Â£5¯»…^]E`™ Ü 둌Õ œóØÚqVOS—©î"Í XáXŽDarÙ&ýI Y¥Ûø®oð˜'Àâ(¶HÂò“E®Ù’G‰°¤)Í$¥ùDí†Ú¬‡šÁôC3Óµ Vu&ïw±¬nsä•/& ßÜxÑ©R‘èZD”D$шÁ^By'ƹ[¦ L¿ôÅ–†ni/ìÇ@÷ª Ê£r ‚Må۞Ȼ˜õmžç¾Œ|Qà$™èªŠák‡¬ZxÉÄt1g¶dB58.U¾¿ßüþ[9QGJÔÊXuÇ2]ReŸ*6Íw„—‘8KÒtú=ªˆ„«u4SSç…÷mqÕå=ãP©6›îR…‚M÷”]±éIEI ³è„9Ö\In¤ï’ä–%BÐ’æ½ù0E¡’’ÚÅsO[Ìyç*Î "ÖÊ ¹”Uk³ž^á…ÉYºKª)G®hQ©.D’nöâÉ¿jè~ý®34u5]ŸMÞº±”Ìfó¼‰ûôýéÅùå»·ïß¾yûþýéwßþpöáüýÛ÷ÊÏÏ.ÎÎ.¯.®ß½ýpqq9¹N§³›6tÚÉù¡ïB>v÷vµähK§³Á'•CÓ´Á6ÕÑW_0•sb©ði&üJÕ*œƒPNÔŽ$ êdj­Ø *EÌ,˜C±»K£b=‹¨jèÕÈè(~É`Çñ˜ƒÑ¸(GT‰CM—O^kYÈ|Ž£¢ ¡«–bl¦'ì<â–§ÈR,fË#9 ºNÓÎJQ›p<):©ŒAÁhÎIœÎ°DÒä2´£ñv>´‘9¬‚î2xW¨LäTÓ¼ÐJ£UñæúææêöêòúüÃ…î=4‡oùÒ©.²šƒ;»ÛG‡ûÇÇG'OŽžœèèù¹¹©!ÐÉ%_,Œt«·Ø}h%£¨Š© ®/<(VJ! ƒéWf”8–ðR®E³ Œ¸ #*gAUQ{•ªUÉëªõ%ê¦Yª{å"ꩳTÇ€¦GœÓØG³eŠv»oÄŠb²:¨UQEûPݰüã3µrÓëb$Ô¹RyB’bJéóí3 J1±dÈ:"íƒTÅqÛ©—p0Ñ BÊÍZV¡»0v—Ó´*9mS®Jû¢ÈSæI­PCÕ Í]ÿüöd1›ßMnùjÒË‹ëï?œžÿðýïß±i{÷öÝÙÙ¹¶q××7ºòêçÍôözªÝÞd¢ížZª™³® ß|¾˜N´>b]×Öíím9ÛÝÝN<IlM8ÍpSÝÜÂM3ÜÝþ7h pÓŠ¦V«ž¿†’¯.‡0R"§›ÜuÑ¢ÑÔ jßV¼pŸÔ“Ô>/e#ª,‰°ÀM2ñ># 0Ø“²œ<­V`X<¾?‚È<”\Ž!3ç{]ldo UõÔ‡Ñ*àcѦc;fÑv‡È„f«.rRgë&Xû6VKÕr¾ÝohI¼[¬i¢ÞÞL®¯nÎ?\j®jóu»ó©llooìîmhÇv¢t|pt´ïË·Bª µŒÉ¦‡¯a¼ÐÛ’†¸XºŸÚØEŸä2P=­bÅlpÃm­‚Ãp„µÕç"nY×ú:Œ‰‚.i˜6TÄÚœàNUÄÄP48}¢#"Í£€8jÍû(|!×Ê»û©ÕK+wÅ6¢Ýà[+Å(U‹J°öm‘‰ñäˆÙ²\,…6*6B¹H*<=»ðÜUZn 5*’×ç —µ”ƒ-#w)в ÃÊ%ÞMp°­c„-¯b3‰ÿR,8œ¥DÒ‘C;r´‡Ú áÊv¨¥ÕŒi,„åŽJè8WT 1êŵÓQäfßèZbê¿·’þ?,Ó"Q8ʼn¡`¾âo%_Ù·•%µLŽH}̧º4, ÕÿÑSA,¤¤}›r´µ³‡…œ*°[ÆØ½Ðvåƒ}–Ïiǘ,L#1…‘ö4&!BSudJÃë{“ØCÔœ‘ÁõS‹Z†¥j\‘âncð¢"äBÓXÍ,œÐÊí¬¼ŒŠ‘$l;™Òp¬hAk3:¥KwÂ&œu³Ê+<Y¤ÑJQy¯bSÉ’f%,Õ…U Mw1é#NG–ÉøÇXsUJ Ç£žûWÍ6ý19Ä[_ëû6O± ¾z±vu¥{‹éÕÕí‡ÓsmàÞ¿?ãågštÛÛ[{ûÛÇLJOžœóÕ‰9æÂi’]™U›x3ݱ\,†*ÜÖrÔ•Y€¢ªV2nž¹Ò“Nh”[u ¤W¨¨ZÖÃòÜ0^$GÓ6E8¨—y¦ª+Ó­ÈÚ6ªÃµ±ãѳ€+Åy¤Ò9¸vd ´­šgT²é{Ñ9@ˆâ85 »Ì) Â íq…ªIlƒ_€WÕo"ðH³ ©MUòŽ^+ˆæô!^«DQãøDSTUóOo™asˆÉˆHhYq˜ñ¨jæ†[­ÃØ!‚E“1B+õoû5Gª–âx§m ÊRþ‡ÃhÕoþ—ÿÚ?Ù6mê})6ØïË%ýÛR W„KH¤Øˆ¤¨ƒ~²€PñѪ0•§H§…°ƒk*¸!ñä]ûcÀQ¼8âÁoªE&u/c8„æ¥EÐgFLuÉ •F£÷Ð{§=®8°nSåÏ B–E¨¯˜v$¤‰HZ¿‡ÌÊ=ñØB“D ¾ìã^[¬ÙTŵë«Ûë«›‹ó‹ÓwÚ¨ñ€íê’¯NÈg ´]c ÎÕ¢òÇ›ýQåõM¶bІ÷?ó½Þ<òßÙÝ>8ØßÞÚT¾µí÷€ó}ôúã×»Õ²!ñ4Ï1‡MI®8‚æR]%œ»ň®›lˆ.ªÃ­/¤'”‡ CEVPŒ‡ÊtèY±µ.YÖ\v<>‚®;2áBçÝ®ªÍHŽ1*›lc 9⣗j‹'2ÅP‘¿^¶£H†¡?ÑõŠ|ÏZç`GB¨ö¯â“‚•Q:pQ±CHT¹4| 1ñi”/ÃÅ0ákÁ×!_Ö¡ÚÌ Ìù€Uo‘»õëë›ÉÍìæjr~v9›Ì>|ø é«M¢Ý­½½­££ýmÝNŽ´oÛßßÓŠÂþ/Þež%1>í^T5<ÝE‰wE!Lï‰H[\,-¡Í`Dè%zm¡[#s•¥Œ‹Ô[À^°ïr‡`‰óÏV¨ã%Qþ(ÂÈ)• ,?Ä'dîµ|E¤Æš]t’ŠùŠc•†ÄâÅ2Q²Å:ØN],¿ÚаGÝq(ëñXDñ ¨µ×­âYšâJ ž]ðx2õL —±t­î°¡)J&”•é[Ã^mVÕ+OmI 5S,j^$;„â]¦s_!&ÃÌ B¯pÊvIzÆ©*ûM¸‹2›xFèr!µ’T§Ö¾ ^CfHòÎ-¦hÃEÁ"KèÌ1‘±Iw­ "þsÖº^UÝK¢ ä5P+IWÚO+ :UŒíØ…GyÐé1SºZœd%@?hV¹7R«|1ç&mÐBÐMà´õл×ÿ—ÿûÿþöö6¿*ïwå¹ðÅ• (ÏÈX ©mAW‘ÆÀ…ðr ^}&ê¨}¡à‚HÌ”{Ár@Êã¤ËìììØZÔS‘zndv‹ƒÿMi%‹ĨiD@¼‡ô^» q{Ã…fdi,i:ZZ—"yÜ …Ž_[Ó¦šƒŒz­ŒLžFªˆäV5ÖÖó[Ÿœö*·Õmãr·¾Ps£REŒœÝÉtÞ·AGi¥úã¤å³÷ë¼3òŽO¡ó–Úéýd:¿¸º½ºº}ûû÷§§oÞ¼ùö›oÏÎO/ÏÏ&··~Ø{¯ÞÞßÝ—“Ý݃í­Í mÃv×ï7¹Ý½[ŸÜÎon&³éäüüTû7M´½ýç/޾úå˧Oõë/^¼|òêÕÓ¯žñŽ¢§O5ÕkŠ”w†xv%~C­¦¡ Tì¢Ç+cDQ©Ü¯·"ÏÒíú7“Êíã€æB¼$+³mhS$MÕ‡ÌRKbŸ3$Õ:6s‡^”V¯°i—ÙMÄÅȵ`Zû•% „4S=÷tñ¢Uì¨tàMMÊD»ƒóõ+Þ·¡ ¶HÈÓé^U<Ñ’M¿CWEZA­r…ËŒ3l;­(ü‰ëÈxÔ ‡·*é@²¬“³Öð¥–ÈuäZåˆ\cY$g~K¯6^ºдœ-f²¸³¹­“d:[Lµ1[lLou²n¼}{zqv}úþì›ß}wuyý§¿ûÓÙôf}IONö5ý¹„ׯ_¿xöìé“'Çj®n&X_xÐÆË¸$\ù4EFü-> qEt1áÖÑæcÚ<ÔÑÝe5s>Ÿºû‘´íøbÅ@Á’eg(!yáX{NÞœ'š8ÙéO£„ÝT¥·w3òØ’•P’¾iú"––úìƒ`8Ü´ £#Æ0Gs£Ø!ïêÐîQp…P}eמ`\Q#å"’’EÙcŠrÀê¨DÔ‹ ¿$ª‰–IÊ4¾m™xäLµn&FØIÊ]êÙL»TKX7)rl#ÃÝUþ\B¦*Íø¹è Pð˜kSœgÔéD€;|¿)6RýGF",dŽë¼͈ ‘ê7CU„â1ÊöÝÌ [ û4ZÉ›2&XÑFESô+¡ #¨|>¯ß!c"´ªZ±s‘bdTÕ%SÕéqUI ÍL•[IÁ]I÷ph^¨¶ Õ2‡Ï¨Öc­^u§¶êX ä3‚uÕþúhªè¡(³èx‚QÌ,e 9‹¤‹8Ÿf˜—¢La3¾]_Âz´ÕtÏššî%¿+Ý…1m58žPÄóx²Ž/á®å$êj¼–°‰Ð!>†.bŒ0­ VD+ôÌ©6?„âÒ¶eHD£RâÍ‘O¢¤ŽªÂ„A”“”J‘Ðd*ù™ÅzlÒÉšCÔ4¹sBAŒâ±Š[£ÜÀ÷ÔcóvÎ(ÜÎæ³ÅýœnÑDá´T„t‰Œ.%7«FB4Íq^ÅQâÌKÒ9Ái!#ƒzOn± $ÌT©XŠc#ÖÑz¹#ÉôoG™%©J#±Ó ¦6cθJÖbª#<P²_M ÄjÂôâJ­@=E×2˜S+IkRu¾«â]гd'E)U›ÐÎ@£ê‘a)Š–æ+{ý9YŒM ¡ó9†ZŸâ¶ ˆÔ ì8¥ÞVáõ»u]¶øO켞Ö]Ù¦¯(ÚìøµQdž9M'üè/‚ΰLó)L%œ’(U¦…Ö{l CmÑ#a.±m%"­Ž`Íñ^1*ê<ðÍ$ºâ×ù¡ŽOäò\’Ø·Ù䌌”T Ž8éH¥ÖB™ò‚ÞRÅXŽŸD‘â’R‰›ZA(,ã:f‰³®¼4iíÉ‘ õ(|K"ê*%ÄŽSªªÃ©íkoÓmvRêEÓêó¦]tÿaĆ“Z %É $•©ÅžÎáØKh‹EÉÄrJDª H\šN^CSU2|”ëL¨µ”ð;jo‡L¬ ÿGQÒ–ïDÁat¤Ví® ˜ÆEF€Eí§Qee꘬#±‘…‚ëÞG¡‘eÓ­+0’bàÀ¼«¬;–t1µ6‘¢®|êç4ɾ¶þ?ÿßý÷ü¼oÔ…ÒcÊsËáígåbò®G€€(i8ÅwQKü9 t×I„h*fd²V áïú;Ã’¥Áº~¨Úœžxv}}õÛ?ûíânº˜O67îOö_¾|òädÿ_½zýÅÓ/ñò«_¼zùúÙ«—/×··î×7†k~ZP½§¦úÌIÑ-#ïµô¼rïüÂQ«]Gߨ­æê9:›’þédh8Ý`;¸_}î ës1ÅÈaÂuž”m`¸L ¢{ðó12-ƒ‡µ‘x‚¡K¼\)j”ë"T¶PÇy ¶ Í]H'§ˆÁ¬z#Œ¬@U©í2QW.ÒI|dÌ¡¶‹§Š"13>X0ßÛÙÖìÖMÀt6QýÎöîúÚÖdº˜M4[7'WwóÙúoÞøpùþ݇o~÷íõõõ×ßüv±˜no¯l={~Âw¼|òå—¯^¼xvrrtt|dWDÃSj%>£ %ÿÑ"íi- -¢×>„*tþê¦H;P#ß±R ÆLµJâh W1Uã¡ Ä\â_ý@¦F³G«án2õȪÃÚÃHõi º#!FªìEÚ§Î ÚÕ«óÙq;ŒxRtáaZª¾ÉtGA˜‚TKÓWÊ šlMv¤…]›]é)s­r5²[ -äÚue¬ÌÕ:œ½‘ ‘ ŠåK‰!ZHF&yŠ’ˆ—ŽTÒí¥²KG)Ó¸r6Å”ý MŠ‚ B+Ç»â4B á*iu1åÒ²‘àfµªÄA"•U&§q#NŒ(׸¢£þaâE¤¼*†ßû* +Ñ$Ü-ˆH£D¢Ó®ÐÝxo¬0´¨ÛÑįva&ÿà ÈÝ»ùWÿÿ„,ÊvÝ:FÅvØÆåÓYòøÁ° Ëut“àÚ H04L¹€X¬”û¶8àt}}Ë¿Itg1.ÀT_¤ÚPCx] ‰ÚnC÷À‚òãÿ¨óV|õÃJéÂ9É”z#z“Dʇ •S+Ä¶ê °¬)’ЗJ¾µÎZö“KÛåƒåÖÑdÅŒq[Ì/ûC)tGq‹²•éŠÜ3ñÓ¢4š›sG+eÿ<<¸»ž\]^Ÿ}¸üþ»·ß}óÝÛ7ïNß¿??;»ººÔ†Î[ýÍýýÃãC¥/^¿><9þò˯^¾zõêõë_þò×Ïž¿ØÚÚ>8<ԨȬçüü\Î纾êªËWÀûÝí­ƒ½ÝÃýƒý½ÃÃC5øžÇÉtc®<²szÔ6‡ªjOæZºÆ=&¬@uâÅfUÆVA<úAy;[%Ê &õ*tE¦ !KSä) /©Õ!Dæ}Ù±M ÇY©R—ñ¯¼‹1aLÃA¼`ëEP…ùÔÆo!E¸M9H± ¹÷,nDÒZÀ1GR•Lê&ciµ~ˆ,ÍcõŒ‹#žOÂŽ8±ÙЊTWN& œ¼¥w펅‘[~2Wâô?Eº˜MyÀ6¹YÌfwçW×W·—×§ï?hž8;eBn­ïímðCòÇ''š‰û»{¼ïÒá0+yaLcƒN˜IˆÐÑR„_n¦˜ ¦>7‘n¬^ÇCΰ.­Ž‚¡º¢FȉaÊeCÌ`|ÉYQ/‰‘£1ýC­ŽT(Î2:,uÕ“#°øûBÖ‘Úè2»N"1kÌ!DÞaâš_y Å $_*Bó;¶¦Iº¬F©y)uŠÍxhâ®I6t:ü1ÜnN®øWÀ"$I3ÝPŠYšY{U1Q!‡,Â+‰¥òX6ÒaèÙŽ<¥WqóÇ$ŠŽÒD QV¢h  7×'Jbaȶ"™Ôÿœ¬—£M™RÕ¬¡XV,]ßšx€„CbŒj,Åt”‘.K‡˜ÉBFEÕF„7ÿê¿úO²ùÝNޝ%ž¯q¢ªNYbe†)?ùXqœ,§\]·ò t4¿e€ÛÁY?æC4ưFú’£Ù DÌü·«-â@ cLÄ2W™n˜u>·UÜô»bQv,³¡Ãñ±" PhDTQž™"qá÷´‰`†œjc¸Ù˜rµ¡ñ Àõsé1t戙nz8¬k&é Ëñ²²JÚ]©ücX·¼zuysuyuöá‚ÏŒ¾;½¸¸¸ÖVnz«  ºjOØß=~rt¬ëÜÉÑËW/öž¿x~trrt|ôäɳíÝÙb±±µ5ÓNm2ÕvòôìT±™?æ°¹Åínomèb¹¿»sp Ûþþþ@徭$šdð‡-Nâ¦I‡î†GÒÚ¦úLÐ×k9uM‰Ã‰6ãTé@ߊÀfV­!‹˜%³¯b®¨èˆK¸rET“lÖ'J^(tÑq˜N­OíAÒyÝKp’šÙr.ÊtŠ2bDDÇHŽ!S9æ`”–PŒ G²šH¨~Fˆ&á~ÑT0µØ;4˹˜(EH>m "s‰àæC¼¾))Ýhßæ—2åî”trÏnU±¦‰|sÍôþpz>™L../¤½³³±¿¯›‡ý'Oö´uÛ?ØÛÙÙÞÚÒ„Ë8b=t³˜&\Õµ\£B|VŒråN YWy4Y/B]o !ÄCDl€™]>DU5kct—‰a,CÃsãä’ó™°·%wã"ƒÞ.]c~qêö„ß!NÂHlBøÑZ‚x^U§B'„¦˜¼8Ë9U".%$QI×S_LªÖ´@÷ÆH,™Ž7 ¥Ik)•;&–ßmV²Ì5Àf%ý–å¹€À‹¤ÑÒ¼”Dµþm|°cÙA7ˆbìø¼Š2U1ÙŠí°¿Ær”V m!µÒÍL‘æ‡ÄŸ‰¦!ÇuºväL|¨º €wç!Ô¡Tµ`:ð(ïM‹bÓàŒª– Z§ˆÕÁˆMÛ!‰‘ žb8ªÔaóŸý¯ý\Éy°$–¯“U/Mvܾ‰A é#¢äÇG*£¨AŠLÿWÊ‚ý¸`ÓŒÆ@®4Û%;€Pm_Ö Ø‹e,¹ òB ¢ ž·e<<·¨H¥Ý´ÿn6, šÛF¨&Ip>tN£âQÈ€ "G¥À¦85Zº ÙƒNL™ªØqÝÝó~¡9W\ÙŸ ®çÝ/òÆË E++Ú´­/x+ÛìêŠëÙßÿðÝw?|óõw¿ýÓ¯÷g_ý»oÏÞŸ^]]êr¨kÙîÞΗ_}ñêõË_ý…_ýæ/þú—¿üêþâo^}ñú¿úêå¯^¼|©¤ ÜÎÎîÑñ‰7ßë›[›ÚùmmnòÅnw v#‹ùýÝ\ûÇÍ5ïá¶¶…mº^KGÎi5‰‰ ]é5ÚHfˆA[Ó+^2"ÊèèN3]“¿d–ƒp^€NW²"2UËxf‰ Ÿc³ájÑRT$–ÁÔ“.êN5ÐÒn.g²ÝY¯‰ûŸõ(u@м)€NÖêB¶º]´¹:ùJ1ÛÁ=UU‹ÇPEïqÕ6 Å¥ˆ–;Ê~e*+ÆM¬jC“žyÌ­˜zlÎíÁýB§°§Óùd"ÖÚõÅd:Yœ¾?;?¿:;½xóæÝdr«Y­ÍÝnBxØvôêõ3¾t÷„O’noó¢^Üiä’ï{¹\U‰ärA©j­‹âaK•°$Üj1#D8AøêºAŠô§þ½äwÉ1V˜¼¡QA ” Ñ¥0r”bÀ=aSQÜî–´ü\”oš±ÉV•]•®5AÄìóD_vDw¿c¾ ÉÈ÷”¢¦¶1X4$æåæ!Ók–ÅãeÄ; jËÒR·‹RÂK‹Ž!näU éÖ˜LVŒ Ãl;ˆèåÑÄ$×ÿ¨¦“&,Q®‰Íÿ˜…+ƒYr p},dóc²ô›10F\׊M2œBoZCô« D'êìØR :ùÁ·¡bç<¤ieO¶ÀÙþcéïÆíaÅëJ1w|B8´‹GÅèPËuqgôÙpì{L“¥:=w ækwsü ¡æûiƒþ¸:òÊÿÆ&O8Ö·øF‘umÏ”t]Û¸»×et}±–_‡OŠ «PÅ8ª1ÍÖ“ÉÛR¢ëXU±K¶b¥Æ'Kt ô±ñÀ¸¸¬ñ)Iá±b ˜èqí+FÁm)µ4"Uµ}Äýû†aKQ?Ò#* C£>bäã5B*«^^’¹Az™þF6þaàsBüÏð}f­Ì1ýcᇊãâCŒÙT±]¸EÄ>V+Œ«ºp’ÿŠÕ±<#—ª>©¸Rüüž3ÿö¹“‹å´{óŸûWþKÞ kSéì4Z(óA_¢Éy†1¨}Y¦K9Ÿü·-ôì^›uèÙ ªs,¸/ðfØõ?…!YWÁÁ7,Åž8µ%Ä¢;vŒèRÔA÷^*É*}bˆáÑ6›m–]‰ˆ ¦¬Uô]B¬åîp“oâàkˆK.ô@4‚ãœQñ}€OBG6·BŠO¹ÎÓ„ŒLÔyvè^Ñ=n=äp£¹Û\¿›ßÍ&óÛ«Ûóó‹7ß½ùþ»ïûg¿ûæëo¿ýæ»ï¿ùáüì|r;•­Íƒý½§ÏNž>=þ ¿ùÕ—¿x­ü׿ùå—_½þê_>ñüøÉÉîÁÞÖö6·g¸S#7ç³¹n©ÌÙÙµz2¹½[Ì4H ¾©ánsc}{kcww{ow{gg{go—·6uçè‡élÓ„´ˆþ4ª]ô‚ÅÚ,â¿hx!'ïˆSàèŽòœ©?[s)Yxq¾R,IƒªQQ6Åñ¾×J®2¥ŒÚ8 !”©Œ]‘µ¡t%<Œ±vkM6`ºö“°2ã|… B#œ1Â4Ä3ÜK ³5"%]Ý>äè¸@"q¥‹ [€pÇ*&<ñ&Ñ ?f^llhÑ’Šæ8ßDÀ‹÷ë“É|:™Í'wW“Éäîý»³ó³«óóËÓ÷ü¬g²³³urrøìùñÓgǯ^??:Ú?<:ØÝÝÙÜâ-$8Ôlö9'›²® ‹“‰ãr‡;HGhBG Ýœõ, "tÏ„NàÍkF°gf‚1RÛ‰^Œhï@º²Ñâ÷¼aú*§‰È± .féèÊ‹e„b\n’ Ŷ›ö¦!$Œ"õÅ º¤¬9$†ÜÏÏÑq'H ì¸oUìü1ñÑyÜ–_e0ã¾@ˆè4ˆñ†z„”4–4G,ר²ý0÷,‹‹ Éý¬DC‰ ¤~3#ü³3fX…åÈ3¯Ú#a ëÔ\Ý7œà|9æv9BHº£\P<å5l¡üH td”+ú¦iׯ¢žþÝ1èwKP¦Ü©jf» B>­ž`Þàh5kéØ]K Eýã@Qb‚([Õ1*d-ä'‘Vj"*~æªbツø&šŒnœD¾­›â â’ÙQ(þ'1D÷cøL±G/Aç„x ªòõ÷3!ñ‘1š-ãžÊÌqÏHf¹ª>Þ-©Aò¼­‡! 0¥K7É^8 C5Tû¼Õfž§ñÑQNWѼl:ŸO§³ÛÛÉÕåÕåÅÕÅù¥.l—W×ü‚4åk{ssg{{ŸÏìŸ)éjwòäèøÉÑáñþáÉþÎþööîÖÆ¶âäûÖ·î×·Ö6¶7·v¶6ùŠímÚýyÙ娋íLû·¹’¶ws.¢yå"½Ý;‘³1¥`Z Àì£t.UjœV^ÒpSùš3~­J’œ; ’­UçSœ–åb'òUµRŒ¢iZ'`1>öKó]LðÆ Ky Ý‹@¶ž÷ùI2FqÚˆ¦HßQT¢£~jR—> ø\ÜrJÉI’ñ“Xæºh§ŒÑ`gœØm9µÚnPM(™‰¦ê  áéÕªéj­—šã$¿ÝÍ?éá·EHKr+/ÓmŠúd3deðh¨·AÅóx« \½Ñ’ú–J4´*¢è©±§Tb«1¨Os®-©É¤èµ>@A•K¥*¡ÊS…e¤JH±ÚÔbEîQd¢%kÎŽ^ü˜—ÏD´„*ÿº»@¥¤6&*’8ÿIƒd’ SXk 8*”ä#ˆÇŽr Á[ßxÇÛ¾¦ç¤­8ÍRÐ'/œt”º‡ ¼e"(µet~d„%GQkÁGD?QÕ gIN”a} Šp¤Q…eü˜ó&ÐJ d<7]"‰±'YiD¨p8-|fÔÎG°Òû+Hm‰¶Ó,¥„n¥Õ±ìøÿc(«£³½*ªzU÷q¤‰£ü ñƒ˜W˜¢¹™ñ~OG•wº/mÒ´*\÷¨®YNºte §­J ~~ô^ÛµÉíôââêÃé‡÷ïNß¼y§üÇ3íÚn¯oµò×êî<99yþüé«—Ï_½zùâÅóÏŸž<=>:Þß?ÜÝÙÝÚÞÝÜØâó-Ú^úKªüR醶në[;›Ú´íìmïìê²È{†hÁñ®> ÝÚ¼¶n~3 ±ɨ14‹cÑIÁRÑ=ÞzÁæñà#€Û}S„S,m :Œ}=,‚qÕƒ"Öì7ü,’]L—œ\uÂL|„ÊÀV´TI8áßÃú¤Ÿ˜ ­™ÔÛ‹æKˆl›B~r[Ùé‰8íÑŸEæIW“üt*;™Ë oDS$ú%’Œ“»Õ©·\ð[6]v/tX,SLw Â-˜ðY?sÞÜÔ=ÅÖÎεÙÝ!ø—> ú¼FòîöÚჴ «4Å P›'c¾;ÜžF÷DǸ¸R›€é& Ÿ`•ÄeABiÙ€l•Œ1=F¼Äl@d:"ö9ªƒ­Õ~jKÊ£Êa8àó=V]«MaC¬uŒå?ˆ=€øãT1ãÖ‹RЉÀE帼’Ç/§ÒÈZR5d™IR0+˜pœ+µ«°ÍŽ ‹ J±ZˆY¡NQGÖ¹%ÔàæÇÐ,´’‘>mÓ,HÍCŒCw˜U©X OUöxéÿ^ÜüçÿëY'…wÞÃ)ù1’#ìži6í8$•ølbæÓç^‰ NLl6ª;ÂQGøh;mäÌЇ3X.–åØ~Dù#¨îrüBÜFCE¸n®KfyH0Ä$wg™Ç‹CèÝZŽÖáä€?Š® œ:ÉP®EÎCCÞ©Æç—0L0Õpç2{Ç;ܹêjßv;¹¹žœž¿óîÝï¿þÝ7ïÞŸ¾{ûîòìòöf¢íÔþÎîÁÁÁÉÉñ“''/^=ÿò«×Êù‹¯ž¿|úôÅ“ã§Ç{ÚÖíñ¢’*Ž{í½x4¤òÚÚl:WÒš~öáLÑ]]^N'ž}̦jÒÎæúÞîö‘?Ozp -àÁöÞîÖÞöú–?2KÃÓKX&ÑŽºéAŒ¬{’?$«Êp,¡¼is­f6<T)óaºMÅna\,fi«‚7t]Õ•å‡\­BÁµi©#f ÉDXè®H²e}Œ#/DÁÐAŒT ”Èb5‰ozÊ1+)HA Ù’¯"úãwcZæàÂ5?‘‹yÛôËÏôQ·à[ZeÆêÉ5û »Ìl6Ól½N꯿òàöv®4ÞŸ^Oooß|¸8¿ô'¦¯Ô­û»ÏžŸ¼xñääéÑ‹O÷÷µ‡Ûác‹¼H³4(éÈÙã ¢6)ôÆJTE¡’Ë”¢e"Ìî Ž%itLuW“r^X*´;a‚W¸eÅÈÑÓƒâè/*.)ª%Dlñ…ˆªø$ö¥=Iš‰Îï(aÏf‘œÜ^UšqqÚ]‡oSKýaöSä«ÎÇ;ckê ©D@“œä'UId¥Nþ$Ôå ÊKƤܕ4ˆ¼ÑIT%-Ibp[º9¦Sǘ¸ŽZìd »ñÔª8pÚU«œEÛbI„bÔùn‚<Ž”ÇohU¥vŒpRÕÑ«Æ;{fYèҰãP¨ÍØ dÖ¥QEq;Ò1ö“ â„ß­‹Õ¥Jº!„T UtŽýæ–*צ*³MD P¥uÌvš¶)»‹¡zÞþ1 ™«Û˜E?÷¶Œ7¶ø×ìØp1¤øJQÑ„cªMÓ ÅUL˜ê¸ÎÈžœÛKÞõõôêÚßòîrr³øáûwgg·7“ét¢su{{óðpïÅ‹'/_<9~røüÅÓ½ýíÝ]ÞˆÉ"¹á'Ó2Å™¨Û‘µü~1|V¹>…?ŽÔZ¼P\7µw˜>ºßwˆn\¹dÐcAk¤"±×JtãÈ"©19*8Q#q4^RÏldIóHë2@2Ì5É0Ô^âT°6™‚~«b^Wšzm:"¦¼kE&òæÃ”q-NI¨‡¤b²E‘i^L”å ‘ Ñ©’ªÜZGª®7Qµdâtë î^ô—UŠ#ÖfªÜ"ãÜßÁ‘˜¦C„–iÿ10*$&cL v[PQµ‚F9µ)á¡•g =%ð¢ºþSˆ•îN9S¡M쌊~[mñå%òÈX꾆nD‰)÷xKPP%4×%lÝ¡¶Uu!·Ž;ÌØ5J@ñ*Qn¦øÝb‰c팇Iµ°R:Q”Êj y *)Z„uȉ3„®J¶Š÷ b[ëJ™Öšz,˜XÁV ÍUb‹«ÀºªŸ–5VZoYr[OÑ u3ýª/ ‡E75\U,Õ îY›·¿›ï&£*:ZDÝÛIk¸Øx:Ò%ô÷?7ånRðD–oÔ(-”ÒT&G,ÈðVaÑ¥‹réä +0é§òΗvÜ+mÜ-ִѺ¹™ÞÞÌ” &ÚMñéí!¥¶±µ±½»µ{°½w¸»w°³w°»»¿»§ÍÚÎΦGÍîêòÜÐè’æ‘] VÑ´®J¥µq󞯎˕гo¡"Ãífg–ÉšãìkqI3[Ì Ìª$±(f„ ^ÁÐ-m©.%$#îÀ„âry4ZgÞÄRlPQCQ¾$ÖxÎWÁWòTïS = t,i-I6ºU£/=-^Ri9žRhÙ‘^¬qÂF…ñô—Z'Nì5~oG¤Oú2pH»Ã±€ˆ_÷==ç`\$ûËŠZad•ìI<{b.iŒÐW~w¯ ñ5Ó6s¹ñ}¢!T™ÙÞØØæc3ºÞ¯+ñ#ìnš[ê¼Ñ) .z"xòòX‚§Œ®U{S%Å;>åÙEß,ý³±£%‘úé Yõg†Šæ:‡cct‹gµf ÔšÒ»T!ÓjEËŽª "¥ÔÆ´¶ýæhokÂZ\¦O:†Ù‹‚Åí\ÉÜRÒ‰)oj½zSˆH`º‡¦Â*ÖB¡ë½þjî!£ÿ¦­ÙJŠA•²O0^ ܆DÝ͇=‚8IüK§%¿ÉßM'亊x‚A?»’äZB1{ ÄÁtÊ5Ô…&FyªÕ´|ç2ÐM’}éƒq’Y®•Í·$‰ ¸ªh¡Ép·îRÉxHn4¨òtåÙ¨u¤ÊPÉÑÒðášTE泫&XÕªw=Ùxëüq¥ÖwR× 3î(Ú‚‹½‡Šû‚ô8R5ªU33ðiö@e§s8º²Cl©4Gió¯üWÿ‹Zv­»ŠÈ%â½iŠ^®C™ï7Þ„Ó  ÎZŸ{!òù!–;Ò²ˆ+ìз?HÙÏQRéÏyEÑ­#SQN¬ÄZ» ±3äød¶YÖp”:R4%5Ls°M4´¾ÉuuÓæÛ>Ž(E[’X-yÌ“ðÆTp»[‹vÀ4²@ßÄr7ïyˆlܵ›]CÔ8˜?æY@hõ(“Îõ现 QÙª×+[w?©sv´eÑ5lý~c1[›h£v=ûîÛ>œž½åãï/Ï/?œûÃ3mÌöŸ<}òâå󗯞?ùìéó'Ï^<}úìéáñ!?Kº³E—¤…¼"óÐÁѶR~7³»ùt1›.Nß‹¾øp9¹¹]Ly—ø–¹±¹¿·st¸t´ïçm{Ç»Güýº†›["LÓ@¬)©CñHqd:Ä-Áˆ˜VÁAÉF 9 j’¼$C{¹çõ¯n…K;»ÁE†n(v5ÌÔTÁ…¤D0YlJ ‚K“èJñGÉ%Œ®¼ƒß‚æ2£Ð‹¡¤”]w+b-b÷ÕbhË=°Ó¨»ÏEÙ¬a*úL„ lÅ!ô[Ѧå‰NPæ8T+®}Ñ5åU<Ä¥eß91õÏý²jÔ9–P¥usK$rcq·¡­on›ÜM§÷o¾ÿ0,Þ¿ÿp}uÃC›ù|gkóøxÿäÉþ‹ÇÏží<9ÜÜ^ßÜö‰"{„$OùÍÜÄOÆYéÑ tÿwTÐ:”,M2E”®p{Œ´Zí0¼K¡~Äý§þä ]¯%سaª°6òhÄ ;Hyð¢È}–D‘Üw÷©»ÝÎéWó1 sËn@}Ôþ! Y[à 5A ç•¬_´½yrÛ»#Ì(–VȸðØ6í]†'Ú\C®2ô”u«†°,Mduâ1ÉèD‰nWžl»ö¹"[H³"Y™ƒÌh„mz«rðúVžgY+'X÷§Žªç ÒiIMeU»KBLÂcDÀb™©ã¡D»Á‚)¢¯W¹¦Àc@bǾ—B¥ãðÈÂ]ò+Œ‹„î"ÖÚêä-X ØÇ€(z,¹¦«[b#c’ÆIÝñ¹Ô“kmËKG–§e–©EAÉæd0 0CÒÕ#ØrsgÂjM§&ïîcr«\F”5¼ªXL5–¡VM“Ž/Uh`41)®Ò"Ó¨} píÀOII’DNò² §Y|ÜŠQrÿ8ÙR “SeÈžÏ×ÀÆè˜å¡j«ð¤fXòÈE"ÀI†e„8S/•P³V¥f×] mŸ«@,^èãL‚E`¦1¥²t$5“rëàS—!ÉÒ•ÚõÛöÉ#U#AÇh+Ƀ«­Ò2,ĵv;º’ñ|k±~·XŸÏ··³›ëɇӋÓÓ³³³ó‹‹Ëëë›ùl~Çìû­­½ýÝ£ãƒ'ÏŽŸ¼xròâøäÙñщvX{{{Ûü÷]z“=µ/ ­ŸH”$Š‚*·%µ¡|s[ûH?2di¦7|~ ŠWÑh_æd!èe7«|y£ÐÚÛR®¬bÊ p¥Eß:p?¦€þ³1Cj^REŒÝtsP-õJ§R¬_p, V/Ëc¯Ë´Ú)€p“ˆSëë-¹³£%Vš#ëþ’Ô *Š¡¶‹\ŽA„óß:ƒ“ZÜøèš ?E)ÛVð‚û²-JI²ô+D¾ýy¾X›Ï׋õÅÝú|~s;»Ì¦þ”Œ|ʨÔ÷öøÂîîöî6ßW³åËe;ó•6l´V¢>¿•¹ |Ð?-¨+Ò(’ Vi’n(©­¥œ<´‚¹SZôˆVJ•y‚´×º§n‹;D«V[/y¨¶9a=`0éÁ‚{³Z$µ2CAçzƒçéñnoNºæW]iç60XK Xzë9÷RRꟾp¢‹k¯¶±ðI93Öë‚ÕQ&uhJD0Víú$´ÈP‘œæ_RªNÿ.b,› ˜'âYJnIRK×Öšh0¢}ÙP±tKwµŒÛÔƒâÓvG](4þ£JVÃqõ’N,o#“³ ûqjã9jÒ*z<:Œ<'U‚$;1`ðâ§ÖÔ:)>)3¥=1dÇ ~¬–Ùà8àPdÄýÒDGkIŠ·Âlf±\©ªlb£*Lb¸…€nú‘0}µJhhÕǧ[ÿ-J¥2“.çq É O»©:‘Œ“#i©i)ÎA}œJ,1Ô¡ ¦…0«h”ªKÊ,Ož¹È#h†Œg¢–zˆæ»‘E£ *'c¹ Ï"–'-„Ñ­Á« §Ô™.#:°`‘ (¢Î.Í%3í+ŸöXÏÍWÚC“@ ñ8? ÏÚü ÏF=›™,k›s}ÝOnç77Ó««Û‹‹k¥Ë‹Ë«‹ë›«›‰®i³™zR »;Ûº˜íìíå»Ù”ïíîìlùú¶Å×yä‚דھ{#íLGxlÈŒ¤\áKiÁm©©HJ·’÷ÑÔ“»P#ä*qš6MnÔÀ”hzé7÷z¬Ù«͸/­ÉW*Tu, ™b«•IöâJ®K›eJ¥Ga«­*sbÀjÔñ¢39ÄHøC†¥š‹ I¦Sz }ŸYŽšœ@´‹]‘¸îr×Á­ÀtŠh°p‰•Ѳ(b©M©‘Æ…Sʪ4 íG¬zéÄ7E|1©îAt'2›ÝMyè;ŸÎü4yÎ~ÈKe¶Ÿìùüx—yÌë-2g5·xÅD,ú:nª£¤"h5ø´&.u‡&GœÐ«bxC˜ÍÔº9mšŠe”\ÿS“B®Æ6"tRçt~r­€Ë>][uþù­¡7ÿùÿæ_æŒG LjúHÊ:2j.0]„LúwäÀ ‘<½œnw^á:SÏ„æQ‘ÄGÑ2b›[ëV´&J!!úì>Ã'sw[‡S”p#”W²XOn"ÐÉ#11°=<ÿDO@>ÒI#IÍBŒ@Õ‘%:¯6ú‡ 8GŠS°Àv›2) úÑ‹SÎ^d¾QtœdÙn­­mN'Z’ﯯoo¯&g—ïÞ¾?ÿpþÍï¾>ÿpv~vvuy™/SØÞÞôÇŽž¿|öêõË—¯_¼xýâɳ“£“Ã㣃ÃÃݽ½í-žœ97QNÁ8äµÍ;¾•dM›ÅéL—ÌûÓ÷çóé✷„ßrL4nêcmöŽØÊÅ_ ’×I1^ÏŒiy›ºt®»¡'‹ˆÊ\Ó¸‚Fs¹ÇpÊñâcª8Dƒ“†3åö]Â&sp­¸ñ$˜â9tÀiZ¶Ò‹]˜Þ…nš®E¨éIÌ{ Ó´4xt"ý™29¯Q°7*²õ ° »T ž;(£U~<@T e‘ª‘±30¸LR—Ìh§¯ˆœš±­ËVF/2kZᔳª±Ôe¡[ŸÍù!ùëËéåÕäújúý7o'“ùéû···rµ½µµ»·ùäÉÑÑñî³gGOžînk‚óâ=ó÷¹:­­meéW;ˆƒœ!ÅAðÙ à¶: ðÌ-ß‚GнÆ_§|—QuÁÆJ.’ø8T[þL ¨UfÃ1¦à®Sçqõ ðgHTâ’iGÔ’9º²Yu]£‘u±ü‰ÑçE²Õî?Ø¡R­AqU åCìÜ:šåªu®HE¢5 ¿KVtÒU%¨tyÅàø‡z3ÅíFËbã'«6 ©Ó‘oœÑy½Ê¨€²kV“iF§WªP´5œ)Ýq[+ù¸„TZ8ZœYpjbH„½›%qX…caÅb"“J4RŽ-š ªBV[t0Ǫ*˜¡* 8ÿÓ,"†‚c¤ÖK2ELj£^Õ±R NP,céd1–ÆÁNô7†n_ãC]þ »w¦LîVt¨:½°„•0±fÓŠ!œŸZ“x‘z”:VŠË -u¦&w…½ ºnÒ#PcÕ‰ÕÃÅawKºˆ¥I%ÏDkJMºÆÈ V-<Àczb‘*ÔìÔ4J ¢ŒGânm>™Nnoonn.…«Ë«««ëÛëÉd¢9#“|åÇîÎáa¾°í˜ŸC8ÑVmÿ`oow{——:ùªåxËuE•Büqv¸+EÝÚºh±&4¤e`N-,ªR”ŇèE§BEûëµJQY×=¸oáGU~N4 BÜOb¥þQqÀ˃¶=D$ó å9=nH¯MzÀirîèqr ‚‰T0ÐM±W ¢›"„[U80¥0â”êU7Ÿ.ÖækgÎ//®ÏÞŸÿðý›Ëó‹o¾þúúâòææš/ÂÝZßßÛ=>>|þüÉ«/^|õ‹×_}õÅËW/ž¿|ztÂ7uhïÆ·Éooã›oð+H¸¹gü"•Lh°6x—Üï+òWÄÝ}8½\ÌïÎÏ.´eœM'“ÛilnÜíïmíŸìï=9:8>Ø;ÚßÞÝažð††Ò 4ÇS¥õŒªœÓcJ¾¶PfžR Ê5´1"æ"™§AÕš²A|⎋|žÎœ*Šˆ@–ŸkÒZ(þ(L£VxʘãîY‘ð¤Ðºè VÖºŠ<›<Û†˜w·TçxÒ8Q[dßV†¢É#ÃŒÙÔ<‡iˆ/)1iý ²4m/Àà´ñ°Ùl‚ÑÆ… &=CÛÚ(ˆ $Ÿ6îÁR•äàÉ«L²«BV 9æNu}}:Õ.míêòæêJw*³7ß½Ó<Ô ÔôÓŽíà`wo[Sýäøàé³cž·ìjâaÔ­älW£ý¶ûLDØÑp¾kŠ’|N$% :§T4[rY4 |!G¬»A ,IÚ–à!ÖR8­¶u—%m€žpµôÑH<ƒ³ÆvT"Ô^âÔÖH*ƒ0X!C iä̇,‚÷­Ú,V±ÍçNC»He ¦d=j )×Ê·r6¹–5Ç–*.(ày(C -^†ÉÁ»&Ÿ3Ö¤P„/Tø÷758Âä®sD }ÂU)Z3-}²û|§Ì:Yˆp§ŒÎŽÿš{>u°’“Åm«LmÕ™&妥B2[9ÒR4ZGµ¶\V 1fè(–¸m85™0¨»RÝ!‰Àw^UÍNÓÎhöñ ¯¸è”œ«¼šX*U-ìg²±ƒ[Ù1Ç!ÆÒ›ì‚™ÂIUPó@`u çq_E¹«[ÊnÜU¡ø¥6ÌÙ€»Œª{ Ö®2é·f³KN;|±— bÌt–€ Pª¹­q¦JÀØT3h]æbÒjlÍ?D§¢›]¼ÕÅîÝÉCÜ>»–ÑE G‚‰"mÌyRÎ_]<LE"ÀœþÝ•Þ9(Õ×#kNÜkÛ´XÜÝÜL®¯®.///ÎÏÏÏÎoxÝôæn1Ó6lgkóèhÿøäèù³'/ž=}·GOŽOذíù×Eù¾¶kþj6Rl;.õ‰*ÃÇ@ŒãÔÅ•ÈiœâôWÈÂ]%]j=pÕ#´¤5º’÷q•‘í¡ån¼aM7¡X²%ü—d"Cã›Ör1ÉÅxiÅ4Ì„©ä*\w¡¬žjs9ó¾%b¶©ßªh!Ól±pyG2ÅÈ;YÝ=æ'±–wôî74 a®¤zÖ~)öΘß%mÄ¢Ê×sŠU»¤é4jTûx b²ÈºÒ¯E¨®Î<ñ”óšß‚/;œÍfs~é h9¡û6Öy̶½íŸ·ÚÝ­Ÿ·âÍš¨£íFëê×À~]íœáp’ `硹‚Ð*"n¦;‘Ý^T§é£¯ìNHMÙRäh’1<Ú[ ’®bººÂ&òKªKi´9l­OB¾+:EýÆçQ™æZ4î´n´5a”†8”øž‘‘“1ÍÚœâ[‡(Ô,UŒA‡4wШ‡AU!n.Å–d7„ÏæŸTE+x]ñ­!—üª §têÆ°É¯‘ÞÍg‹›«ÿrü…ÒåÅÅäöv>›êb¦]Ùþþ®öiÏž¿xþäÅó§ÏŸà+ º»´&€’†Ò‘xˆÍiÄãÞÌÖÑU›“ËáKšw«ó®§<+-aäÝ9EKXo²?.ËÕp ˜P/Õ³®a¥ZHˆ;°^Lzª§c¬[B¯7Tº˜„¡£;cHt‰·ç𘩠Æa9ú¢mÊq$Ob« DeÅ-ƒØUQh‹êÇ@U€»¬D×7±š²®Í hˆ£<ê9€\sæ¨ê¿fg<Á›]&~ X·èª_Bª1Ωz1Ä'àY™»0H-)hÅØàV²½èíêÂw7›bj3l•j„–T[1ÂK¼=gÏ£Šª(#CÕÇÍÏ…Œcw(ö° ‹<©Í0¨¹í…Rú8â7qwTݱ&”DÃCf8˜®p䵍ޱtË&”Qa •.ˆI’¹Eó+5H fzkÙJi’n«­¿½zÛVRí¨E>/|g8Ü ªå˜KwûrH2  ›¿Ä×<>‹ào]¿›ß/f÷ÓÛÙävrq~yöáâüLû¶óüZ(_M¾±®K×ñáÁógO^>ʦíù“§ÏNŽO÷÷÷·üõñ¾ŒÈ;3V–|U#Ý¡NE’S‚VùRÀ%ƒ ¶XIU6rç«j¶w>‘ª‡-NBÜ\·N™ítLë؆­ršÙUÑYáI6åcÛÁ=’mÒ÷°/Ö[*É‹®d­VïT’ºb3bã=Zt—.¨ƒba‰¯Ç\EÇbN¬g%…øÒ`ú*N/A“"yˆ6ƒ„‘µf#ƒAÁ6­›ŽjbÕp2º´6|•ŽN±“œFi(Ec?QÙZ,+¹HÚ>‚%©Ç<ÄêPï–¼øÊ«]îÞLĦM·+|ŒÔÛæ–Ý­­ÍÝíÝ‘è^eŸÛ¶Àó¶7Ç»F¦=ƒ¦·±bÖ RÌÈ ¢#ã&HÅ_‘äÍx”åj£SžÑöfâw£>á*ÅèJŒ1ÒQen´Œ“Ô‹ð "qç3Ù^õ)½FC\e«ÒK¤=B,¤ÕJ#T›é| Ê¢äÁŒ8=¢Tû6¹äS¨I%Bt²Ã¢õ‘…Á@‰°ßDöR­“«õ<‹{¼TUŠÈ˜Om‰9Y±dÒ¢ð{ÓÂìÉ¥ ˆrAºŒŒMãbPaé̺êMÛGuvµZ¾ÚÊ»’ä+9‰£ 7¦ÙIU-”VëØ¨GÞ3ŒËSEª”¤ãã佩Ñ'˜èvœU"¾m|[Ê!Yy6DÓ£ÊQøzÄÎ Jxä±ÓáÇMN™@EÕš°V;!¾ /yÌ©"¶B@»X´ÑãPž§å‚èHŽdKŽÃ³!¡ô$cJ’eíÒ(Šà+EåÜmZ<ûqN’J‚Œå²ægƒq—S©ÛÔã©$3Û|©w< Õ+tkšŒIš8$¦…˜æªž½$ɨM^¶Yq:4¡³fY=Zk¼Ìè7Þ°i=*aöV¬ø¤.7’Xhß¶6Ÿ....ÏÏ.Ïøð¨6nlÚnnot]“îîÎÎÑÑþÉñѳg'ÏŸœðêèÑÁþþޝf2¨VV[äZýà/_k]'÷œÀM«}àp Ô‹\dü1mú“çsÒöFEÑ¥~ôà÷mwvÕ1N£0›Þʦoˆ"¢gFõ\(WS€S]›‘S›­ª">‘¤^ùýæ8i~¹è’æN2Š–^Øja;U¨ç½ùczÌiL“xاÚNbPòx,ÑNú8‰!ý‘Þ„ÓI½è³"´¯E Á´<§—'üqª6VÒ?v=ô ÖÔ–˜u­‰¡‹äýÎh+s³žçÜox£¶˜ònÊ©0çëžgk:46×wv¶vv¶Ù·iû&ÚŸMðòÁYƒS.O€ŸQ'Ö'z›¦ÒÚˆ3k”37,¥œ—>3(Š?Lt“d'©ZZ)ÂâÇ‘Su &Rt-æòMŠ®²)ú0ºñeÛÁTµÄ¾I©éùC#ê|Ɉ„N[U[ÉSU=Ãà{ÖĹƒv4C§˜î©ZIèz` 6iŽò²M@»6sÓëL„™R™p5¿pàä³ÍL÷ÌT‰Y’‰ÂoÚgKT-Á nÕ,ï¶äÚän–Z¿ß£'QëCfÉ&_¥´!Ñë6«¡x˜rF.¥a %À4tãeaYlœ"ßèømÞØ˜š/% 0µÏä²¼Ûþ#©‰I]ưgSKGòœá¥¥¨ŸU¨ŠEP2!`ÔøA‚Æn’A·)dJÌÉæ}ŒÔv"HUGç¤VH1ÀéÈ+/Fµ‡¯¾ìæýbš¥‡ÔŠjð9U(VóêfŽZi¤¶ËŒ‰Žp>†jˆkfËU÷sYÆWí#o(ºè²2+èaø[¶¤G“Å-gÄc@Ë–Vµá‡ç¾ƒ]]n¼Ø°~ø'­çg×gggÎÏ>èpv}u5¹¾Ñ|ÐY°·»}|xxrrôìé“§O•žœîïîîꚣ˜ˆ­|yê„R“ðJm 84F×puÑL¾šÝJ¥À¦dÖ>½*úô՚ѕ2€Ç™ ™Y§ãJJM‚°¢˜Ê1Ûd䈥‘ËG³SÉm¿OœÇñ³öKJÁc²Cútq%kS(§­¸„A®Ñ½';'ÈŠ¬ZѶéĘxªe(š9êOƒ±½BÆ{˳W}ÊÚcK·+‹ù½fþt2ã«Ûæó»Ù\‹¡¬èþfw‡Nóö6¿Nºµ¥g;ÍÔ4ðM›¡­´Ô½¡·Öýþ3&L9r νÅiÉÁ%ÛÏTp夎p¥lN¸éÌSŠbDÜÇ™·ÐBs"®J¹ø Þéxã£èTE>°9’.Ý[–iá< ÕµF/Sn‹Üùû ®«T¬‚ÓÏsÎ ¸–«£«$haärÎ]ÖH¶l/Á@º:?Ñ!Œ‚ƒˆPäJ1K[K] t î…u7ìoàêèk~íÈ @Iÿý´.³ ˆvïøB2¾Â”;áÛîãˆVÝÀÄÌ‚nˆµ ô?ɬh‰.ãFd"üi<Üü¹#VáÖÿÿÇ#}$ÐGž1Ugh>UÎÕêUg¾hæårOIrœ‡xAÍ÷Ã)ÊQj6†î˜U¦4¡­ûÃÀɪˉ& à×3ÅnÙ w‹ÿ4Gĸ˜~°fU e1öM‹ÙsBÏ|¶n]˜M@¢[Hcýœ¢ù¦ÈÒ©êúkF ›ºöbˆ0(ƧîøE"Â'énuéâ[>n§—ç7óoþ­»ÙÝßþOþÖéû÷×——çggRwìo¿~õüË/^ùúÅýÑoŽù™mmÜööwöÖv6×·wtËÉŽ‚á­ÅP Füó:><êï:½Ó}Áœ&¯ÝNóÅæÍõüú|z~6ýOÿøÏ.Ïnþäÿäí÷?\|8;}ÿfgcmwóîųƒ_~õâ׿zý‹_¼úůñÅ—¯Ÿ¿zµwxà‡\¶tù´=@óMÐQi<"^u_ï‡Nx4ëüg¡µ’ "Ág"õmºP™•:b©[ìɈ\Ö‰k‡@ò܆$ëãi¥µ¤¦Ô,h`Äý0 YT®ËHŠ4$&kœ†¸ݱV+ôÞ€õUõÇ^:ânËËúÈ~j•‡èè2!”w.¶ÐtXÜkÒiþñäm6_L¦³»Åúo÷Ídr÷Í×ß÷ÍÛÛ«ùoÿô‰Þ\ݨ§^½xö›_ýòädÿ/ý¥?xúdÿéóÓãÝõ­ûM͵-?•ÇMÞw§µGSQûÝñ#Ì|j 1'¦ .IÒrÑëY½Ü-i!Wó9OMÐj®ÿ¨UGòMuW€òÁ‰‡tbæOd:¹\ð5¤kó»y~øÒ2‘ œË-ÁÎàW0ª‡çEéFBr£†66éºX±8?IlûôŽeUjþBªá`^þÚ%£˜<ÛŠýúÅmÀ,C‘qðdAÄb¦ŠuHÒL¢nN‘í6ã#Ê|CfƒŠµŒÛ‰!VŠ:HL%+ëò ¿ªò&›Z§0uäí:Ù«ÊB:z Η€PFœ•ZÁ“ ÖÀ |ë!Ü ¡j-Æ×iɆBcøS©B«Fu#tãîxÜhh7’s¹´Ú¯ßŸŠŠ.²ÚÚ«Ò¢±†„)zæ1tnWNÃÙ컢©CS¢»,¹?Z#b\T;¹™s±8ºÂ’bWçþØÄÈ`Áû»±¦µº[ëPgáǫJyƒ”è.u(-l`{¢”ü8€ÇlÜyOogÚúÞÞL'·óË«ë¿÷':¹¾ýöëo´c»½¹Wšû{{‡ûû/Ÿ?{õòù«çOñ‹/NŽNžìíìíè¾P§/òৼē¢TAT^b5ÿÚEHœÒüêÝt²˜Læoß~˜ÜÎNß^]^ñ>»›ëÍõûí­õÃÝ''OŸ<9zöôäèøèàèp{g—žðóƒò]N°¯«(MgåO—XÀQ G§M«²Õ 9™ªºVÛJ«ˆ$„•:GDò0û)>œë¥Õ‘K.̨·Ú-_VϽ]UŸ,7Ûc<Ê/ûvÔ`€T¹´|ð¤\E6S®aÅ&9cgˆd‹÷´~"JË'âñï¹;Îj–L˜Äﺢ…0Ñ¥AÀ•ÐnHÑAƂńˆ`RòS\×X7Ö’ˆ1‹º¡P‰Ö—;kŠúsn1QC7HV t©->)ô#@ÇîìÒ‚«a ©±¤éu~™•br5:~yAôÃÚ µB„ _|b•˜2óuDòßú·ÿǼÐÞ°æy Pgˆ™\*K{KÉØO+•JŠ+ȶ4¹dZÄ6"®1÷ƒA…Ê4kQõr`Eöë¢Z÷*Ú+× fnx jõqq`ÇƒMÉbÙ² ~ŽTÍp ~ɯ°š&©>Pïñ„?°Å^ƒZdz5M-1·ÌÏPy˜ê)—Ä{j!xïèýÆý|m:],æw?|ÿn>½;}÷áüìR—®çÿþïÜßÝýöÏþôúòR>4Úû»Û_~ñZÛ¦_ýò‹_þò ]Éþð½·¿ux´»³³M ¶7ü:‚–¾KÓqù%l w ‰á»[›óx|\,uÿÝýÚílm¾X¿¼œž¸=ÿpóŸüÍ¿{qvó÷þøï½ýá‡ë‹ó«³;[kû»ë/Ÿÿú—/þ¯_ÿâ—_üú׿|þêåÓç/ööy†žk§Û)ôd^{ $ ?L“¾cøøƒÍ+P>êõ}_eT±ÍtÄÖ ÂG7´€^É¢/yôàØ‹ ÙeÀ´a¶UQ„Ã=l øPÍ(ÝÇà°€0ÔfT±)7õ**¾À¯ ó¼²0å²ã¸!–#•$£ã¾1Z[Ñ9ï8Eð"éKÂ4@"ƒuƒ„{ÊË@ç€Í—#>0MøZF4ê“éìòòf¶¸ûÛûOno¦¿û³ß}óõ÷:>¼;“QèSúÿôIDAT]7öwv¾úâõ?òGðääà/ý¥¿¨ûÝ<ìîm.î§‹»™$t7«eˆWH-ÔjoÅ´¾8‚£[-âk±ç¨ù€š9ª/BÖ$nܸŠL&0KEšfÀqëxÁ‰—ÃùXKQÔ° âþÔâ€n®‡Ô9zP" aû]âÞû]ý¥<£ÆAó¢¢êøeGWÅú©/ŠZ y€ÄE†:΢£.½™êp½Ý÷¹ ^XpT¯¢_ô+ž)»/Í‚¨E#uD€œ´5|Ȩ˜Úž×\2ŠrÿP4Xv]yˆU-hÿN‘Caú­>M%m‚¥žw}%NÕr9–5F\7ÀõÚ«8chÖtdS±øJQGµ´c%ÑdBôâ'€yú÷¾03h1³{W‘3ÇA²‘àLî¾Hgש*u•ä­;êŒx‡ÍÌׯ"izm°ü!Yæ…>¢CŒ¡s7’-äæ§vŽb¬Îc{ÝìÉK¯Í ˆ¤'C£Ñ È©¤J¨Šb°ª úȧ&'³¾lÒÀ@ÉË)娖Çŵ'¡ MLéG( «¨«Y™¸(FË{4ª$C"0Äõ!Á$ÜâȺÀbåÎöݦÚÛZ4Þ` 1 ¤¸‚’m˜½Gc@U ,Ý䆸nš˜aŒ‘†”1Ý1B˜‘è7:Û#V¨Fo@t´€§EŽ~ :¿ ½X›MæÓÛùíõôúòZéæêFiv3±¸S[›û»;ü ÂþÞþÞîþÞN¾Á_×F4²©Ù7¬+ÌÍ/UIÐ ”϶Ò+Ü‚“dÓ52š…¼7ˆiI‘ å~!_–@¬óîZv‹$íÓHo&5ûJ§ÓH[Sé„FœRTŸIDUÊ9¿H0•¢5VtB¦Ë;Úäž÷ZÇ#By}Ã?Má‡4]^Òq$¾»BS&&-µÅ©>”פöiYËc§Ñ+FŸfµLE;J#EÛ!ZZ‘„+&x¥tB×¥]HfH"“¢š¯~¦«Õÿ~t¤>G b{dàx(UñSåÀà º´šäŠ¢hŸ1m ðÈPû-žJ‹Ù‚ïÿà;wI wkkC÷ª;;›Ú½í91åùT‚À«0²Ÿ†Ë‹{LmÏÄÈLfŽi*ÖÈr3Ÿ¥y›à­.Ô=|ý#ÏbVǹ—´µJ[Ê…½¸+Ô!i»GSòî‰æ=Ýdfš"!T1«€d‡þ¡é¢Ga›¯¶ˆÉõßÞå »[lÕpú÷Ni}cÁ/¢ðMºCâs››wk¤ûµíûõíû-çJ ÔCéQK¢¨î¢1ãä54Ýád>Mv³Y†‡E~Œ2Ue蘞­7<%_k|IRBy “Õ‚ªOd:d`›¥î71FüXÃS’,ÅòêÿôNøBôm‚yF¾â3Å.¾HΓ®â ú¢™ÀÒ9AuQ9E:ó4WÓ6åÉèA*5^AoT‡}.¡*ZUâéÅŸn$D0®C]—sqµ)£¡ˆná©«Â!VÔ“Œ@}ª‹nœ–P]pI¬J^´²ò‰³‡¤ùI,¬µÚ¸­Å,ÂXf+].óŸSé*e*tz¥Ûá÷Ô†TLŸßÆcó[F•¢¡9X—S½eé0{µé¦‰[œ†zMB¡éèBÅÖè~>¿›NfÓÛéååõÅùŇÓóÓwggïÏ®/®o.o&·]Ìd_^w¶·övëãwwü‘:VÒ²§tWÄÛÔ Ýén2œÜîÖÐ < 9Ëý–‡®‡ÇJŠœð™kÛ|;¼_”R¾¹¹­UJÝ£ùA¿G¦M‘r$v%ɤ6ÉcŒdRç§ØT”b¥A|Ýj I“¨ÑoŽ/¤f(!ESã¢hIÆH¹VnÝ0·ì¬¤²ó°8š|]x)5«í0B8å•פW±K’VИh5™Ð£Ž!¥˜ÂRmŠNÝ× œoü^5H*y†“MŠ5¥˜wº]ñü_L§³ét>L§·A„voÄîÇö»Û›{»Ûû‡{û{üˆvn›Ûî[ì’¢bÿ‰!0Y“ŸF)*ï®zR1 ´’ü`¼ hU‰5 áR²$EÅÖmÚþ (™æŠxÓë:oÕúKä\á©ïrJvXE)—QžÜÍïïç<޼ŸÞ-t×7™ÏµŠÜÌæ×S¥»Étm~×¶t¤õ)8eК?ï‘•¼Z"Ô®Ö4š©˜Xâ8%ÕÐ$‹¥—èd©…7×s±Üí`) Å ßßôƒ W±IÄÉ»·¶GnÝâþR>‚$KhÂBæý‰ÖuÝ1^íÙ¶h2**tÈ<’åÞ–ßÇ KÃêc3e¹ãëvo&ÚÆÍ¾ a¡UX–}ÆðÑ]MH>¬6a)Ý]ûbè«¡–ì{­Ë:™ÖýqÒå…’E½*&‹5wä&3¤Œ‹U=5èBÇ;€l_^<]yÏ”òp­ãÎI³~vÇgN\Ý·PövUW®¯:±é]—ð5‡.B|¶Üñ°§Lxž‡åihϤdoØ}•ùÓ¦PdHU$ 'fN\+8[&o)ö”Z±ytR©ƒBt&Ef¬n”8ÌêLZŸÚœã:Óu[ð¹JnÛ´ I‹Ãü~½1¿ßœ¯mh»¶XÛÊS·;-Þ¥)g·¾y·.N¥ìäèC’6p[ö«¤Ó¿ï™FmÚùE/mn± ÿTk;ÊÒð‘ÙZòÚ ü1ƒê¡Òºäšhtcdìß²¼Ž¯èÁ#®çTðƃ'Ó&ªR²Ôv`÷ªîϸ5tqP^Ü MùT ú¡³B,»»AõŠwØ\’,3¼\­©,¾ ÝNPåƒ4ëËÏB"ÿL¤ÓHá!wýßü?ÿ~U ¨7³ÔÝqÊ£`Ó*ª{|¿Àùœjî|éH£øZÊ õ˜Ã£ËáKRwÊ"R+»Ú•Sç=½–Ô ùŒò2€Š­%£® ŸÔ‹j(ÁJ11tž2ÞÌ.ûü‹ARhfC7PÛÏ.ŽÖW´šŒ±cfr­ÖµµØ+O[žû…—aÁK.¯R²)ÒFè~¾q¿Ø˜Ýί/'³ÉÝÿíÿôæjúõï¾yûý÷çgçÿñøIïúêòþnqx°÷ôéÑÁþîüæ—''_|ñâõ«gON^¾z¦ÝÛw†Š±ÞÜÝÙÚÞÑ…Ž!çý²;âñ`Lý„QÄŠš¯þ¸Ó-¶×T ¹î·¯ou±\?¿˜œ^¾¿üÿÆru~ówþøOÞ¿};½½™Þ^îmoœn¿zyü«_¼üÍo¾üÍo~ù¿ùƒ“§ÏŸníì{évñÜdÊ™”9VÇEN}•nKO.%*T½¨U £ô—ñPò¡ý€ˆtx´’Éœþ±.“¡4ÄQ"z«*£†ÿ2Ç$‡Šc« ãåÖA(â)©š‰%ﮨIVU½%xσTA4B6\j­ÑÊ¢Èð»N#A@Â6‡êu€j‚íC» ÚÖáN5qA,9õ»?ì…¯àóýŒ-ÛÚd2›-î¯on?œÏæwÿñô·®¯'¿ý³ß~ûõ·2"ëº~~ùòų§'¿üêËÿÜ?úíïþê_ò¸yGWD‹ùÝŒ(½“A%ö-ØWÞ½Sô‰§ºš„‰‹Ñeü!ÙÙqzØ p{C®Û#HÌ‚¶Í À›«Æ¦R5êö zZL)—*äà[ƒ×òßëç<¯Ô6ÍóÀÔ-ß‚zÌonnÔå³éônFã¤Æ{2xéysŸ§–»ºðü\s•Û/¸vK–%ªæ }ÉxkÕ¿›+ðõM-ø„Fü|—nµß—t¢³ÁÎMYk8_1•PSŽuŸg”¨S½¢”T”SlŠ8çaD«Á›Ö줘6ŸjÍÚÒäu×`9 b¾³<[qî´ë,K“y$ˆ£fˆ‹L’©bBñ´¯‰&\æ&®‡a£“C–}U. ®*ùô‚]b¶kwµV$› §(…BÇYºÕFXXá(ï‹X|…Öº'Ò¢$ɆÄ*´ÕvÐá;jÖ:É]Š$:˜FzÙ¾Àl6S9:”–0Ø1"B\Ëa÷à•‡è´Ðén*†¯<ü±#AJ&ùQt¦ƒzïhA¤ª6ÿ¥íŸái‹ï¸»å‚è ÅèˆÈ Žó ÌQK‘–}‰ÏüjÖHŠÃ¶É¦àQjáäàª"‘áÄ‘EŒõV ]f•ãw‹åc„HRëTöÅ·å2!®“K­PôµZ´\êÍ Á1³C϶’áɉÏÒMïrÖ}òbcM»§Ùbz3ŸÏî¿ûöÍíÍäíoß¿{y~ñõ゙N§xéìloùgG7Ÿœó^Ÿ½Í‚»;KÜÜ\ßNnµFßÞÜN¦S­D‹,ç~PÇï>{Ó®0ý²‚FIƒê5™Ç/ ‰·7q ½[›NÓÛÙíõôÛ¯¿»½ž¼{óöúòJ¶´`ïn­ïínî==9xþìäŸi}½¿°³»¿µµíAÇÉk\<Ð=î'ç˰ëF×q@8ê¦ÖßÉ?'ýˆ$f£SàÔ–VÂLùh´ehK¯’¢Ú £î¬äCŽ´H½=ùj)ŠÇ<.±X‡¼– ð@¨ ëúYv¸XdÉùw­vb²¤×V}ù—e!Ŭ6-(o®[­(¯ l(q$®é«‰:›i‡1],î¾ÿþÍt:ÿîôÇZvxº¶¹¡iöâù“—/ŸýâËךö{{Zl²Ú:A—QÁ4K.æÉY'< Eùìµã䈖ñÓ1RìbØ ¢˜â$¹ f îXX£ÓÄÃå1-f{’7À‹3ßGe™;ÒumÔf·ºœ^|8›ÞÜ^_Ü\\Ý^‰º™^ßL®o“™Ÿ>®ÝϽšg‡&uæ“îò=áØŠ˜ãgZ=X¯îµo“°ß¡±‰0Qp1s„3;{F=5J$W´ÆxhWœ´ŽÜ­¯„¡†pÁUJ¶‚Lú’€»›X·VLæZ@©U=sKumÍ?z[×ÇCÆ%éÔUבPi¾†ÀfjãÀ‰Š” M uáÖyí8ÊG‹<—Zc©›º5 ž«Vj ©¢¯œºyp°«>Ú?ØÝÚ‘ÊöÞÁá‚w°lÌï6ÎÎoOß_¾{söïþ?þ}öwÿøïž¾×öq¦kÂáÁÖó'û¯_?ý ¿~ý‡øË?üÃßüÑý#Û»û›;û›ÛêµËÍîÏê.àÑìl4:UC-ýÙÎÈÏx4]¥ÏOêùãmiÄÙ«èÏûq³phè¿ "##D&U›£f®TõKçc M\xy¡Ö‰Îô©ÖŠéÎúÛéÕV€ÉåõäâúöâúÆéö\śۋåÓ–f—“ùÕtq=]ÜLç7ÓûÛù½îɧóµéÝÚÔŸyšåSêºÄ‘XÍø@{ºÝ;€‡h#B9? +ŠlÖË»F“¯Æò¢¥‚âåÙó±dñÿc°ÒRAe1Ç-ýtäÈ >M9Ÿ@ÿ_Àç4cýûûŸ=ö¼Í™§(BÚ³aæžCwTæpFÂ[o©[ª¶™ÚbÛ@dm°¹ÏÈ¢Q.ðá‚™žè\ꣵ¾¦û9EÝé¶§ ú—""†·ñè…9¸qê¼U‘ç´U¶dvh/áf !¤SjVWÀíy›$í"‚®¥hÝ“:°ÙÈ>H‚t˜vG÷w[S­€‹§W·W³÷?œ~ýÛï®/oþ½çß¿º¸úÝo¿yóýwº[½ã¡ÜÝb&cêKÝÙno¬ìllæ›<òò‡mN@‘èf™Ç [;û»ûÛ[;‡G;Û;ºÉÞÛÓqóÉ“cmО<=Þ;ØÛÝß=<>ÑBwxüìncëòìæÃû«÷ïÏÿ½ÿ?Ö^ðÏþäÏ.Î?¬ß/¶6¿|yü‹¯^üÁo¾øÃ?úÕ_üƒßüáýáúÆöÚÆ_ü¤¥’ éžÖ?F{)¤ŠF+¸Ë\§w¡NÌwâYb,ö Ÿ–ÜðòÓ?ráú1,ÍÓŸŽŸÕ@ÅÊØü¹c|Z²+ÓI8†#‹ùp­S™_î:ßK çXì'ªîçàóE÷;ürgèuH•+ªV²°|³î9Ú#®ӊB:Uí²Ö:šXﺣS›¯®®î‹Ówï/N?\ŸßüñßþãûÅÝ7_}}v©Ž¾½º‘´liÌC0-»Û,%ÛÛ›¼±‹'õ*m)÷÷>ÀßÙÙá™Ûö6¯ÔlóõCª;>9YçÝ®û|"mkcgoW±íìó =ì˜6î7îù(–w4X<œâ]UÍ`цñIí hõm­í*¦[†AtWk:°Ê bFYyQ2໲¿õ*Kx8èbPÏ]—0µ † oñEÆÂ4 ŸgœMõÜ„¼r6¸$ ;pŽ2ˆ¬‹¥1 Y.‰ÎI®rñ[HcS<ûTÄÖÍ?†»èIgªòõØ-f\`°Yp8²ß¥‚Ö¡`~¦)ÀdTÜ´î(Z0ØÃ¸¸-O%œ ÛŠAx°i:]ñ @@ǹ¤»Šw8E×á~m2ñ«6«tŸÒŽgE¿¸[lþ+ÿÝ¿êë2û$ú«ÍåÅ( –d´É¸È Ôu ­m©jµ6Bˆ)¨ŽãÈ °9þÑÒÄÕMJ}x|*’â„•L¶M ̧ðšü'°"ƒ'sÒãq2J{Æ*-*ƒPEC‡ÄÕ‹. æÃ¡±NãÚp̨¤~PÞX\C`Kݯ“jÉX¿¹Òj:;?¿|÷öýÍÕõïþô뛫›Ó÷§ççþÞQÆß¿ÝÈš³‚饜λ™0¹åèùî7î«Éuñã*¼í¯ðNæ3­qžæïo›LÕ®éíDãçßšx³ùbssG®®µ“¼¼¹º¸ùöÛï'7Ó³&··<ùØÔ%sóähïÉÉá‹çO^¼xúüù³çÏŸohÞð—:Ѷ†´º7¿èTõÔ«º@'Vd:!øÚ¶*öéTºËôç$V{›XŠû3ÒÆç¥òösÝóÓîÏ ø©Œ%¥,7JþqòÙŒ—_4]/..5E¿Ñ”›Lµù¸½¹ÙÚZrr¤Mš6mOŸŸ<úD+Ÿ¶¼ã ŽÌç¤Wî³²ŸëvG®ŸHf߆ÂOJ˜ýÜTn8×ÉñÌ.I·^)ªFò0¸ä¤Ö '{•2®6ºøùB¢uâæúæöêvv3}óÃÛ»ùâôíéÍåõôf2¹¾¹Ÿ-îf‹ÅÔío§ ­ ZGny›ÖÞÿÊ#º™-%<ÛÏ[ca.¤;×úÃ良eI-û GKŒFÇaÐóŠHEÅÇPk\­‡„¸A½E¥«‡L ®(TÑ ©ê C SÞˆ´Nvµé”̰vëjÑ ¦Üx¹Wž‹£%Ä2"k²%„Ýb£iw¥ˆ‹Ð°¨ú>*€©ªòq Et©us#°d¥X@´Û‰Šr «ú+6æd1K p¢h‚ž VsÑ:wÆIƒmhå„€ÙQ*t/—¨AÔ;z ªz< WAêQ$Wuog½éD"<ÇQGMßü—ÿõ ŠNè0Q-pvÊ~´f³„•'Vz×õB«Õ?l î©"¢VJ¼ÊÎ8^T™!© b¹+Æ$ ¼¹툖Ðd\YRÍXÑêb2ìÇ…!1Q\´êqT!¾¬U¡ù$˜xI#Ú"Ì}¥»5­}Sÿ ‡Ӌ‹³ËwoN¿ÿöûóßüîkm›./.tÝò¥ÍàÍu7 }›ìh¥Ô[±™ó9_É$Bf•ë`Î÷Ϋ¿¯ÝÛ|rs;¹ž\_ß\]^Ý^ßœßÜÞ^WW×§ή¯o?¼?ûæôíÛïÞ~øöÛ®¯®ÏÏÎfÓ‰ÎuÝ<ïín==9xúôÈû¶'OŸ>yúì©{O›6?¦I ýi¤®Ì# w¸s… ˜™ µôQ<æâÇðÓ5:>ínÔ’ßÇÉ_ˆ~2äLJå÷€Ç»‘OïÛà¯ÁY[×MËtº¸¼¼yÿþƒ6 _ýÍÍÍÍ5Oán··7^¾xz°·ýË_~ñüÙÉÉñÁÓ“#­)|Ó4Û°¬X±}VUÜÅ#9*TR…ŽT{†Ÿûøñ„¤]ËoŠýù¨UbÔi"Z¡¬©QNëuÈoÏb?uw{{{·¸×àíÍD;­woÞjkuvz6½žÜMù- uÂ&_õ§EÄ_ð¦% ]­&ºOÔ-Mu×§µB¶ŒYSÒ¢¡t}u£tuq}uusþáüBÎÎÏÎ/u|*IðÙök²¬úž\qzñS°B‚š©Ú ,6BúDy†5€n=a#*4;M^ð…ˆçhu=òÔ¡¶ia1qyÆŠé~)>b ˜ŠÙÀ¤€‘Ä4†íWÃEø¹Žÿ³›Œ»VÛˆŽ‡œ NWèÎéèDrqöþCc®Ü ØsۣР@ŠÇåCÛl@ç0F³JGr ³x}žhW·ÁcÍ[³Ea¨*”°Æ92”WeJ+UAçwºÁÖ°D<怈E^Pä‚8‘ér"²y2ÜoþKÿÚ?M©Ù«Ü M‰¬‚íÕe`o9ÖØ0ábã²2°+T °’"ÏC¾UÔ™ƒM!Z"’+[vàäË Â|«–!ÒrµÄ½3Š6pÂìyqªÚUéüqˆ?4£àâ“~-ÒžÔê)h ¶¸×¦êöz2,Þ¾==?½|ûý»o¿þîâìâ»o¾ã^ùæVk(V™9Ã+éTË\ø–ú¾öm<9ƒ)Ž¿D¸ÙB;íÞüóY³ÛëÛlÚ./.…gg"µèŠ8¿¸|÷îÃååõ»÷goÞž¾{{úþôƒ6p,Ó—WZѵêíìlìo?{zôôéáóç'ÏŸ?yòôøäɉç…6mš|F¤vòîi÷O%s–z{éüÇ0Ò©Ç ¡søDéã¾?Ÿ£Søx‹Vñ 9â.òèSîGRu_£iÿ¬¾YF3]& 5@.mÊ5­ý1ȵõëk^jÐÄÓ‰p{;ùFóß;†ù|º·»ýÅëû{;¿üÕ—/ž=9>:89:Ô<ôÃ6Ùô¾öPÐ Ô?èK¦JmÚô_ßâ–P~Rú °ã¬E?U»Â28()Wr3I1«fÔ½tÀBp¯_çü\+„÷mw7×·Ó[•iß¶¶XÓÖjv;½×ýÜlÁ³q]Û¥7mJ\øvÿ˜ÆóÿFÉ;hF]‹‹†îïx­[Í˳KmÏN?h»öáôôâììý»÷R8??—KØÍÍææ†|ò1¨­MÜ(\ý'tò¡E!’è ³¯3ᬀëWW|y1uàêcøJØ@-ÎùÅU ´bhÛ5ßû*Ì–±šf1Ó!yn®xµS3Ó„já\ëÛfÅòñø(hÝGÐmÚùãèb±S_jE(•‰fä%E!óÀФШ²ÍÐAøÎ©ÈQèÔ÷~“­ØÒ!Bª„”£(0 ª-j–ßà­YÞodäªÂX)*Àæ‡xŠÒ¿ÅºpZ‡3„TOå’Sðv÷¢lSŸ‹h=ñ EÕ¦8©)æ§@cFûÈ%ØÝÏ@‚QÕøÆé ™^èÖ¢vhÓ]ßbCz”ÿ€ƒ%ø±ãeCÊëþí·ø\ýœŸ ©W(´á$§æhjäyý8³¼„? œq%\»[l(é÷î.I÷UkóÅš–íçfs¥»ét¡4ÑÝød¦›òžÀi‰æó ºUÖâ|u•…W1ÍüØa3ÒåN í ŠN:1Ü&Iåu++q‘0—Ó–ÅFÀïC~çü¤ôãð0*/alêÇSZô±ô¨$W‹œìËUcÎc)Á%ìO¥Xìœ?÷”¨ìE7÷<‰÷Ra ´ð LzÍ4íÚ{†²þùýš$ÞVDÏðnN)é_¼‡Ïjé›[¶rÝÿ ¿|ù«_½øƒ?øâ~óåW_¾þÅ/~µ±¹ÃçÖ·ü© >ò2> u‹/ß»ˆR‘%ΡõaòTÈ42; úx}}9Ô/uïø÷œ‚Eþhº(ࡃCo§]úÛ°V5ügAú:ö¶ž¤ŒÉ§™ÍËgþ½„»ûõ¾ÿpqqûý§çïþvr;ûã?þã››]ã×îgÇ'»ÿøá/ìoüãÿø?ö嫇»ÛOŽ4µùa+ÞL¹½~Ÿï‘_ÏxO“{Þü®!”ÞyMWró%ÿH$¨ÏÂOk÷%+ŒGÁÿÁ¸Jñô©íNGAФa¢ÒáŠÒ,GUyj¶Xðž4uëùé‡ùlñþÍ»ó÷§×ç×ûoþ­µÙý7¿ýæúüj!‰›[-|ɇ–üaÓ pœÖNѧ€|iׯò¥YbQ?oñ~V>t.溥»õ­µÝ-ýÇ';›»‡{û'»Gû_ý꫽ƒ½×_}ñôù³Ã££“gOdäž,/­H˜u •yw7Š g>YÇ`Ðþï+B¬!’,qÖ"Vˆ²ÿEL§q/« ©¾£Q° n‡‹c³Üì^UI†íY+*$q3r¹QKyƒe˜ê2^’ÖÄ—®ÕèªMeß‹~³3A¥Ã!»,ؾr¾ÇËà&ß¾«{rÕ$f׃A¥1Qð²ÎìUB9­èµiºÔ#ŵ*è²bp«fd4ã+Ð6?¦p­ƒ®]ÆÈUa%*.Fš–†˜ÊÅ”v ã.|ùש}%a¨/©Z‚yj¾êå.§Ø$Ðõ|Š-¡øþá>¬€SKÞ’Z„{ BØCPjNŸ‚õ>…ÞSñãÊËHÀóq?†H÷4ƣ̨å ðu„Ä|î´+ºÏGü}GY*kñd'¶Ð‰žîѼjÝBÿmÂå½e÷|MŒÖN-¼uˆïõåWFY[e:K-Iœ» Vå{r]âx· ±7ä½.ò®pY¶Ý$r¨ èW¥H}R¹ž#½¨–Ÿ8]é«Þ±W0ѪZM+ÿÿ z{RÏ´ÏAi mÿœñp&d6œÑFžçJ“J:÷¾'õD÷å]ßÉ´x3=<#‘òQ̦QîêiŸ…Ö9Ÿ—¼ÍÀS¿Šÿ,Ô¶©J@tŠ¶Ý¨W³:CX“ÈÅö e¹úØã@hYàå7x”y§óY‰[¬Z¦ZbÕqÚ¼ÛØ¸ÛD~±^¿F/SXðRË×¼?¥ÓÊ‚#i9¾J,q­µÄÉa(‰øTê ]ae|áØê™®B+>ÄJU·ÿQG#|ÂìCtƒçSˆØC´êQrY¦=£¸rnþËÿú?“z MFK-åJÈxSÏú§…­î]lϹ˜AÑqçYáNbK¸€ÙÁrÍ"m3™ Ö¡„š¯³Í%÷¼’Rd¬¸„𑚆X'À˜ÐÙY•pÉBK½µ(­(~ióâ´h6-ýìsKl¯F«W!^Áô]žÖ´ÙÝlºàsš§ç×7ß|ýÝ»·§o~xûý·ß_^\ŸÏ&ºoæ.6£à>±kç lûqrkXú´QÓÌ¯ŠŠ Br»câMqH*<8–™Mk¥ñ•p‹ù|q;]ßÎnnù<Ùt¶˜…ïEµÜXßÞÙÜÛß9<Ú}ñòÙó'/_={ùòéñÉÑñѱ†Ñ?3­­a’ Õ3•ƒ ‚ûq<¦A8K=™}êø1H.Iˆìã´ ˆö<ñqH‹EŒ|+UUlÇ.>;eFü4 ’U¤?â —i¨ö‘1Iº²ë&ǧ§|(áôìûïß\_O>œžÍæ³í­ý½í££½ßüú‡‡Û¿úÅONó1R.óXÒ‰¨ù̯Ÿ{‡&øÁP5çNÖžÄeâ CÿHjãþ0j&gi7õ©Ä #¢´ ¨iÒPk7pÜ<§{zSm¾¸¼ÐÙûÏ œ]_]ÿðÝw³éìâì|z;͇dMRV—dÜ+ÆPÁ‡ŒÝÕìðÆƒ³™Ý¦öj4Rzò)u5DKË_ü ÔÈ÷ö÷¤´¿¿¿³Ã—ùîíïSch$…ÐÐæ ¿‚‰°TC| pB—)˱hj S“Xàü”" ù‡Úï5±üi²”§òÉ<«ÈêhO툒ŠL©Ü…A"ñZŒ´{dTïî'f[‚øE}Ñç!‚:ˆ¢œé R½ïÌ~Ð9RìœDSጡ2mä°TÕ]c,536»€òp”Øu•håÒ¦lD~ H”NxG; 6]TBµ+UÂCÎGá(ò$лÝQhúe¶×tGÓYâJ²€bø^UlL˜A˜¥o‘ ‹Ëę̀<ŠtIM²;§2_ˆ˜Pe£XF±ZœyÖÀ_¶&Í(‡(æ'1˜j~«ð¨ò½S½×¡ò° ÌJÇûÙ(i1ÜÜÞ\ßðkT|JKÔ-G˜ñýs>ê0sòuHäà't²ÊJÊ“¶zœÆËFÚÀÝßmðtK §Z/ØÏ±·sQq©Šõönï˜ñŽ·ÛÛ™’ÇŸ$ãwnkÍ—’æŽ.›››[ÛÛ[|]}~ºžûUyQR#{G…èÅÏbyr~ž5ÿ`1n°Rü©HzVŠ"§à1O¿¯ÍÏ@N#:y7Óo6ñ*ù›k&Þ{Ôíìììïíìê ßXÉg” Z¢3Ló¿X9Ï9ßJì祟 «áÚÞ?7E8áÁÐÝ`Á…RkµÖÉŸ=¸[Lçºûš’fs¥ùÒ és•¤E„]—Ö%¯4äeH×ïÕ¼ÃcÁSÞýÖý뮡¶SŸ†ÄƦÂéPÁ©˜«µÖ¶ªwΘNmGÕÒ•#E‹»ˆNëê–à¾n+ŠƒÁǾWÅ X *£Ü¢Àc7¤Èó¶ú@³ÌYϦl°1 Å š7ôêš«‹+uÓ n”+9švöØ»”c  ä®´Jk›B€çC[0Óm›-¢Š2‘¶ÛÌvBˆHÏ{êE‚GÅ€f˜I+€i—ÉÝŒ‘'E­ ¦º® >ЊißsÍí©? 0½¾¼}÷îôêâæ»o¾?;=ÿðþìý»ZhµiÒ:"/Úî1 wþùÆû¹Ï· ˜Ð9ú®ØKß¶Ž £Æ¤½fÄ Í–R.¾jž‘ô:kòÂ6r*‹á¥ØwÕþD„м•HV67t­æƒÃ½ãã½—/ž=}~ì/998ØÝß;AÞèì>Æš?à1žû7*ê1±e©eú3 ñhø;øC?æ§þy ã‹«üˆÕ±äï±1uÊϵíâÇÁ̵&›Î¾·âþVõùÝû÷g——7>\¾yóN§ÆÕåµ¶»;ÛšZ‡;¿þÕ—»»›¯_¿8<ØçñZ&1koqƒÁû<™ó˜Ž+o+¸µéÓ™S XîŠàçôG|ålêúŸîǦTât“w4à¬Ø,×]ë=Ed€Öí¸´û˜korww~~¡ÝÉÙ陈ÉÍäíÛ÷Ú–ˆÐí" wê5¾W7[:U})Ï9«>öagŽÿxìîRµ¿ñN% e­1yIGì 9ØÜÜÖíÝÎÖñɱvßÇOžh,wvv÷ö,4Ì™ÉÄ e.ÃMµcô‡_ -¢ I¢”+%ë-ÖTtÁwÁ~Ì–ÏÌzëVÞÔwy—¦7Í~gà6µÔakaáŸ~™:°sÐÕâ¸%–†×ŒÈ£@7ÐzZ½œÌQo´l8¥1QFóáÖÍTׂ(¡êkkúèRuæ»jñÔ1ÓãéCÄüß§êêºKßz® ÎSý‹aÁ>,÷XÈ9nüУ7‘ûÀª445:-B#"œ1Ðip‘¦M‡°ªuòV›@ÁlþKÿú_ñS3Nt›ªh1Cšf¢s“*wJj5‰ùÑLÆnª}èª[ÍéL™BÏËENT’{¸n„Ø’Ô J0aŽ!a&iÇRÆS,ºÙ = £ˆe7^9òÒrÑ$3ü˜¢BÇʪ.>¨§TR,“ÝH°L•Íêü1*ÆßÊ¡%áêúúòâúÇ‹ï¾ùáý»³ßýöë·oÞ½{{zúWmÝ´dh@”¤¦ûVµjÙa${öüdÿ`O«±ß“™ÂÅÙ6¢'Hï@ƒUÀþ‘` Uå 30zJ10åÏ@70Ö.50CüT´#ÄdÒÏÆŠÍåâ#†+h¦|ü´Ýš|ËR*,n04ÄÓ ŽšƒPÌ4Ö]4¯n´s[üðû³ºiùþû·77ܹhrt¸ÿääðøhï/üúû{;¯_½'›6ßšx߯'`¸Áp´N5]-³¬i·ð1á ÇÄ2Mgþ‚Ÿ›pnµ´5ˆ2ø#)Â\ꕳÌZì)ÖšÈÃ/šÙÅÖxjtϦ-þ>==U'¾÷þýûÓë«ë÷Ú·ÍÓ‰DÔYÞSñ% l¿ø@B–þ7¼`RöÉmÜeW]Å8ÞýÆzÁf ) _º­Ó™Ÿ\ࡼvpüP²÷mÛ''Oööùñ…ÌÉaµ}äEÒãVO¹ Ë{Abq³›’y0s%¿:Áž¾ ¹ eW»5ÿ^þí ßJ§^S˜ÎÄäSó<‡CX¨Zqù˜?;8¾]ɆõÖOIN@BkÃkçÜ™Ir§Š‰^r«,š‘DÌDjÆm-DÌFŒNX/ ôT\)ÀòI-}\9WyAìÒuŠ ¥¬É52ÒÔÕÜOpÊA“•ôßþš(Ž€ÈDâ1°SÌ®é¢\ĶªZÈ%é!f”Së"òä™.‚¼ÒX-óŒÀœ-àÊü0ÇUh’™»ÅgJ°¹Š2;å8$½Bý,¨9E}DóY‚ð³´Òø0¨Iùç/]•>ž7ÞßÎù¾Ü…àÎ|¤sÁz4ü¦ŠõQ/Ñ1×;¹›6ñÐÚ£ö›’7Y€ë§ßš¹Œî!X)R^eÇxÿþ¾ã'uûÏV®”9åN8eõª¬œG#|\zõlztR.£ì9d!:>ÿ,ýy(ÇÆ˜þ| Ñÿ(Z4yzq¶x¼–—,Õ·ÌôÊeeÜå¢{¡!û¹ÊK&N§#IF= mu JªJÚűc«‹!«ËŠB˜šGL%˺ý¹gfæïZšMog|;Ýõ„o0qš\ÝòÅ%|ÉíüvFšÌº«˜Ìî¦ó$n‹w–æþøÅ\íä]¡Õþ§5€VƒôæãHsªðç¿–ÿ!Ÿnû9­ûq­Ï°J ™#këÿ«û´ÍÏÈé¶f+϶³—T.¬ñ´eøÍÉðøaäeN·!¢.‚…dÞÏUËVeŒkv 3º#Õ²ø.°)s”—Ûç9Šm4U?Ë”¤qü°W²ûè’jGû‡¤bš"œP…ÞÌõÿ7wÖ#Y²äybîæ¶¸™ï‘ÛͼKUw YHbH g@ða¦A`À² øÂÏA€/ü_ø%ð…ßf¦««nÝ-3"|·}sçÿ÷Q=ÇÌ="3ï­ªžiqñcºˆŠŠŠªŠÊѳù;kʇF:ç45ûP‹!'‰ú4`¤BRŽ.Ù¨|àdÎS6t±àôîþöñîöñæãýoÿíïîÆ¿ý·ÿp{}¯ÀýÝÃv­æèŒú ¯sÕ£ŽtºZó=Á#”Ê©®âøÉ’Ù"¹UÊfGG= ëõhýÄ÷L¡Û² Êî\èßĶַ¥ølËÚ°Åìp‡Ü³º¾Ûëk° ‡£““ã‹‹“/¿¼üâ‹Óÿào~ýí·oùí»o¾y«ôÓžK õãùP]h#œžAIªSq≻^: ƒY*”ÌkT+R¬lYJC€:ê¢ÞˆF8þÕ#.¢ô¤ü‰P9ÿ8xœ»bÄ‹ 2;5šÐ†¤”¥` GQ’–M¤Þª™à¹Eí@›þS QgxºÆ¨‹È>(³P!VrW$$Yo7«-Ÿ;¿y˜¬ÖOÿößüÃõõýß_ÿÝßý_iÛ,UÛïÞ~ñÅåÅÅñú?ÿû‡ýW¿ºº8õ|}ÒÐ=|–eëñÜ4v¯/îDt¶B5Xtê@תzMÞÏBœ Ð$ÿè Ì®iAÔ!P !¦±?¥²Z.HSW{åb:Yj5øÆ0`±”‹· ®Ÿ6O¿ÿ‡?¬æ«ßÿýïÞÿáûÅtþ‡ßþ“±X®Ÿýž6£çíj{( Ùˆ“} ¼Uàªá¯..IÆÔJæ $ Ìtáé÷$XwØ;èvE'ƒoùíñùè»ß|÷æÝ›áéèôòü@«VŸï™vâۜҘ˜ócØ*,U¿%°`eσNW²ˆ"`RƒâOìŸqÔï^-å«Íy÷¸ï£\Ë'c/Ö³ÄxgÖáAoØçeZÜNÉjÂáÁAŸ57ˆ0!_Ä”¢#¶ ;G”ZËB)w“–¸\¬Pj u{EC‰;Rho6ê%·8(Ñ(Ñš(ˆôR(*鸜žE™P¨S»®Ý×uü²³Dk¤(WàÜ ƒ.èRj#!:.» þŒ*¸Iâ¤Ь ”0atŸ 9ÙZ ÎÁ)úS=Z˜WRDÊ0ú»«Î8PÕ†ÈÕ±Ûç½i”67u??"“ãËSP8Údæã¬)AÃø' en$³Aó@q6ù^åGGÿõËuÒ¸ ¦XìvÀžS…2\T%5l[ï/¤XNп Ux©œX ’¢”Ám ‘ Þ÷±øßÄ®ÄA(UÊ‘jpo„ðpA3q ‚¦]u2)8ÛQË`ƒd­d2Š›Äˆ5Y–xÓóQËX–àì@ ¤!{lR¹Ö*õòd<{|˜>Ü?~xÿq<žr—›?J³\¬<¸©É}HÅš? y`*C›8þ &,Ý1UŒa𸔘H»UÄ,B4ó0”ÿ¨ ÛeóÕï÷å½õ/·ççÃ/¿xsyqryqzv:âÚGO˧”õÄ ¨ƒ8Y% &¤²Ôh’™ ñê°“RvLe,Ùü6ô¾J`Ruˆ—¥ÜúpDCå­é¨G¢ÎâFz¡„QO+ B q 3q)dv÷ Ó´GÍDùQ”^$PÀãÅó1­¡Ad†Å¢ÆÐU½ÂD>"€išÄŠeð±$)B¥_4Ã+ '³ùzý|ýñv2žŽÇã»û»íVçÒÕÓ¹ØÉÉàWßýBÃïòò|0苉ìMôûÃËñfæ9)8G‘K Ÿ„á­Ö1;€|AF”t'›À”VlEÉ”¬¬èH|­ÂÏò'¤Ð²6˜¤©ÃHËB³æôŒÝµµ#z¸½çëy|…åq½X=ÞÞã>lä¨yZ¢!NéX˜åØp-8>Éá¤êÂqR :Ì9¤b8ܹd‰WW=rˆ[£l»)rƒÎÎδdžŸޱ/å4´œòÃÊ·Ú¨«ÜT1¦Ð:P ëbKÙ…¦šñ u^)þ”ªŸã1õj¾^ÎØf›Oü~à8ΫÙr=[­„óµŽÏ:ë]¬·‹ívÁ‹…Ÿä Ï×­×O¾•âéþ~|{_ÿüáöî^Ü|¾XqöZì(ΨŠ_î>TM)—µ[Š«¹u h]1Å…ZYBBvä0»"ÒQ3RöÂçxÁ5!i2;mÝ~÷¨«“”î‘N»ƒ~÷ôdðæJ'Ì'¿øæ‹7Wg—g§gCÑu»=$¤\™ë„N—˵Î^øÊÚxüøx/¿­Ë-šÏïÞ]}ñÅ•\·¿úͯ†Çƒ“ÑHãLLä„»¦#è[­¨íy`³Sl¿ ÁÀ;„0Zæ‚Ê*B Â8» ÃDÉsñõ¯ƒŽ±3 ]¦©.!’ÊS{Îpx5ÙüŠƒÅË(Bväˆm¶ò6ädÜ}¼]/–÷×··›Åj,¿mƒs§É$eaÛ̓µ‹ *5ë°¤pc{6Ûú»±ˆ¢ƒÀsU+lMyØ-2<ÇͰ*É“LL&÷ãñýxr7Ñqö0§óÇ™Ëébö0SxþÑùìa¼š.:ϘÌää-¦s>Æ?_lVr–ùB¿5>#A]|IŒ·6Ñ$G«3ħ!ô•wh¢Q#‰–º$Ò' H%Eã#/“"Fœy$îœ]Œîò¢/ º T ¢Ð!¤ê‡ýSP`Ê$×0„+Q7€ƒZìdgU€Ÿ 8µÔ¡z3C¿RŠZš q €:¤ÍGÍŠØý¬j+úÞ}5cDR!#öA#¤ƒÆÔΈHt9hJ6iŽëpô_ýÿóÐ;×0 ° ʺ\ü®®fNøk:’G*Ûw*Ñ_5×ðØØôU;jš‘Tž¨UT1rÈrÔB%Šg5MirÍU¸Úˆf˜D†`P«¹™Ñ   ì‚kD„¨¢t‹lY`H¿Rô 1+‚1yQ›SL¢‚Ù(:/Ùâ²Q WNÌycZµÂHÂø{SF…âÏ+m7[^´!Í;ô›››ûë·××wüÓw·wãñd¹ˆGõ·êȵ¼7vxÍ€vY¦‰¢L•Þx¢—òêé^fYóúæ¡¡Vu:’_£?XF¡CV<³=èt»ýA¯Ï¥ ¶ÛåÁ ݳÓáÛ7gW#ùm——g§£Ó¡VÙÎQW¬aŠ2@Ä «Áu9Ú¤”tÓÆ9ö#ÆD›&ü¶—â:P‰E®¥”‘]I˜M”¬‘¦!EaG“ 6AuÌ#‚ ÍÖ›&ICz‹´¦K8‹èèºØu§áIìâ‘taˆêúÍJéŒ|/b7ó¤§\« Ž¦QFÔ˜ gE Ò]‹ £H &Yb®›iô»,ÌCRK¦ÒÉ’ ñ¼Þ.—Û»û±fÄû÷´Ž'“G-iýÞQ·{ðÅo¾üâíÅùÉo~ýKÞÒïDŽӔˑ®›×—Þ¨2Þ`È{¦qÚ”â^ëˆ@uBf9L/¬Šª‚¦‰°u¥œ¡öèX²SÖYÎõQÿÐ[W¨H`F— !Š›çN/˜‡§±¢8ß*é¢Ilìl¸kþY>ÄjŽ›rûáãz¾’ß6¾Ão›Ü=Ê«ÐòbŸ–EBå1i½à)ËC@A†+K -R-NçWú”-‰ÖÑÁœå…ë1½Cš¿G†ãÆ ]ïäìô¨×åaÒã~¯ßžŒè7v \ü0·¨0œTšÁÿSÇ­‚§ â…á¶úål~ÝÕo“˜ôú¡Ô²˜¯äHá·-Q;mãÙDcMF÷v<¾Ë{›ÜOfãùL^Ú˜8yu«éJá¹Î¦Iä›]òÞä·),×m5“7•b—³9/º\®ÙœÓß‚—^®ù\áZÕá7h £)ïiååvC¥†Cέ~5@½®Z8‰bˆ¶ t4F”£i(x´½Ñš„­ÐÊ5¨þBnåО“Î̃2ô<<”b–¹Œ¸—Z”d{LPsQòtÄéÈ"%ÀÓÔ„}¬@jîY3F@|\5)†¿$M8R\ f4R±‘yÀ44Õ©9NÖP0ŒlWÆô¥ ¡E=Ù ‡¾ ,«hm¹²sþëý_Ø%ã–'aCœÐk’¢f £Ÿ‰–é-`žZÜì8†„!$úM„Û‰õØŽ´#A U+aý_À”Y» R¢Euçe ô®¢{L¨#‡QmK0¯ÕÓaÔÕŸÁÒ#[Q$:ˆ¼Æ~P›‰DñÁ¹TЯLcƒAgÂëç9Ÿj^ÞÞÜßÜÜÝÝÞüðQNÛd:]­Wñ0O k>³ãÅݪ%x;×u:–ÀXjÀ±lÑ™R&¦yé˜ ¢×Mà yÈn¿J¹vå{œh)ºçgÃ7oÎÏÎG_~ùöììäätx<ì³’ò½œÐ k&a×ç””2SŒt‹ë’ÂÑB§èÊs¢6š7Šhåí‚^øZšŠ ÿ# ‡¨(£Y¼I|…G¶©LoŽ­¨Å+ J ¨ZÎQÄ­Kñ(^¹…ž„Žëh m£M¹Ç}Á1¢º& =g)¥ÈX(Õl-Œ ÄüÐ0˜b.Xkô#¨Œv€lyÛçCo<ó¾À»»ñr±þðñz<öçÊg­lýA§Ûy~suquu6<î}óÕ—*Úíú5^rà k±ô›ÅR€ýæ~ “RIÚ¤G ˇQ°”1nv0¥DkÃ’|xÇ4_vÙÐ*B#K5FYS¸ ~[`rÒ¡µüYÃÅX—¤NtX5ªîPЧ°å¿á·-pSn?ÞlëÇÛûÉÃãv¹žLgË><>>Êo›M'ZÌ´¾Ëª½ysùæêü¸ßÿúë¯ÄD~3޳6càæFé×ÍF„) 7ðãŽé'r+Í Lb0„2ÇUK“ëpžP`TÌôŒ#C¼øXÛšÄÈÈWH–IöËw„¸uOñ0ºíÅWàIÈÍmò@¦ËÍb{óášý¶Û»ñýÃZ>ÆxÚ¡œx…Tê!ø Ü}þ%YŠÂ®ÒZ ‰`•„èÅmïž´´Ð Ü’ÃV–>œwrÅéé鑬ÇÙh0ôŽûþ²œ;ÛP;Óq¾›ûmä!§CñœϯÐkS¦á(i¼j€~ûþ,oEÙ®å\ÉìnÖ‹•)^n>žNî§“‡ñôa,µÌ'siLÎ.nÙrÃík Ìðb/ý™‡–:Ãa4œ_œ¾}wé§Js¿mp¬%–÷@©„ÑJ Ƕ ÝU4ˆ¦\rZ* E\º² ©”J¾ Á;ØÔðYx­Š•*Åèqc›6ïE¢A N+Mn òiCxK«£àÎE™j;à¨Ë²ï›4:Zë±É4[5Ê€ „! 2e²”êøPÂ!W˜óŽ¥0ãPG6zMð¢Vn"Xs•è@~Û|±™/V·w‹Åòæãµ–¸Åb®%M‚ {ýîïÞ¼{w5õÕbÓëq=ÓËãTQ«óDù1áZ$@W‘B¸€sEjs,¡¥;NÝ"K@HÍuÓ<9¢SHV‘0Y\u hЗ-@A×¥°Ëe´Å“a$Ô*‚¸á £-DX\ëf­ŠãFxÊ;Ù.ñÛtøpw/ïDîˆ, ýƒdøcBsqü¸Zjðâæ¾C'—uÜ(ê’(<à¤:GQõ’ÒÙÞà™¦ÎÉÙÙQïèätt<:N¿KÜqiõ\“%¡Dº$´‰šÙ›¢½P™Èé–ÌÙþ±Ã¡?ù´r<ðÕˆØ'“g¶˜/ýŽÙäQ·©Éc“w+¥iPòjÀäÖKºTŸâ¼u“‹!vµFólª_àä7¿ñdª¿JÁ»E¼ Ç~_›!ݹ¢Ä_[-_WÁ¥Ÿ¤…h[…hbK :ð§!®Cô×'Àå÷!Ù"¡ ….T!¢¶ ²d0Ó;êðàQÈû1t¬Ó)]à„ c@P&} ”Ò†  ߎx¶ mZE¹x•CÛ~›² ÏvØðRŒ€þ‰h ÄÞ¤ 8M €§£€ý6ÒA †øXËGq—­n‡ýI¶E¡…]°Éø>æ¼"2XN?+¦¿%zì“9(óšpRd™Þa„¶>-½±×O4Õ)ДcdºNÈI÷AŒDì]ú½ÉþÜs¥8{lp“ØrÖ¨‰¯Ui>]<îÇÞ¿ÿðþÃÝõÝíÍÎçd\d™ÂX¨°\tU.¯­×é*ð”~ŠPnÔ›õ)ÅoU(”’uŒV=–T‡æ=ÜÌ7Ì€€ËzD±Ý^GrŒN†§g£‹«³w_¾½¸<ûò«w§ç#%ŽyÞE¹I2<ÆÊ÷pNt¹þ]Ð2Eø³4YG6²þ)ÀÂ{4„,µÞvâk˜mm°È«>i'Fª£MSëWJfºÕ©):{¦ð P–ÀS$º‡ ؘ(îPsÌß"@LÂäfÔ i†¤9]½™1tr¨Z~›NO6›g9m³9ûm××·³ÙL'1:›Ñ·Ù¬DîGG{_~ùNƒm4:þâ݈= pß”j4®"!ô°¨µæzTí· ¡IgŽt. YÕŒdU B£Úò´NÇóD茦§íJõÍÕŠ:?•+WäRVU›O€ –]`:C˜.¡zû@Φßh!ïd6™mëë×Ëùâñþ^>м–åt®:e´âÔªô¡Ù›£B,h¯lž÷Eši¤„ÌaC«É§ ò\w°qgl¯{rz"¿ý¶a¿'ÏM~›Ú ) D·9†R5EXNëQƒºúÁ&ä 2ŽÎg2¶ä¾Êo‹ý6¿á\Î’¬ëb¶œMæÓÇéäáqü8V`6.fsiÌX¡5î3ÆcK/Mÿ¼œ×ïçÕ™÷b©Œ¥ôË»{‹ùl6ŸrðnÜt"|Ôpö&Ûl®,çÅ g0âKn[µP•èÌ\ã@JÏEÅCA- -§ÂÜx7;£‰¡DcNS—ÝÁ î³ä‘éVu $•ލvvC§KÕOȱ"‡G¿t 3jÛ25Z|ÜéQÀöLÅd rº;Á¸ÙXB>Êp«ÀÐ.þ’@)®=!hèô¬#¡æÖÄHDD(eÉoÓp+iœ¬Zþ–ùQä鉋ž/ëhƒeKP”z\äSô«nO1 |¦øŽB_Ä5d4~¢OuŒ€@ úŒfÉj ‹’_“É$>fB@›–° l²Í0”¿VÀ%Ô_)¤ÎßY¬X«¶ž°Kf¸÷ÏÙxŸÍŸü$¹4B³>©Nd¨â÷¹mÙ¼}(ÉYóÅÖlA-픲EÃÀ6 CÚmy²ãGGZ5ùRä`0Žõ;PŠŒŽhí5€¡±¤è˜$jSýê¥]–j“Ûü3fÖåŸ$–Àk­k‹á€Hù\eÂvÚäÈmv·–xM|Z)y]|)Ë[öÒ¢0Û`fûìûUà#ÐÈäõèòÿVë…|@C—ûØxÈr×Og³ñl2žp…ôîþñþAÇñíýxwxsw«ôGÑLǃ;áâš,/ÅA€˜…n¡¡Õoe,Ô=%%¦hµeŠŽ…S›¥ ëè¨# ÙéL¼Cðyþ5\ÁG€JÇW E,`&DgÿTmˆö¼Êt €»ÚÕ¢è§`¦†Û‰)D.9LømPG^)æÞ+àéÌŽ [ƒeA-ô™$€]ôiB;ZÃ솣xrªé!KP‚dµ0£;ðJÒ ÏømaD×eæ{@N’>K$6@‰6”¨ºÂ³¹@1÷4U$.ùü‰­8™ vÊg Íynh[­Õ—ê!.)È ŠÞ ¹ä&ˆ5f¥ñÛÀ€¦·ñ÷â4Zèôޝ&y¹¨½I´àv(P̦_—gûL‹¥$ëòšÞ`Ð×:Ú(¤¸–SäMö•õÛàÜ€L©àëQˆ»ª£3ö£€k|Ä'äù<4âY¢ÏD ’ả³"Ü’¬Ð2+9|qÒ“TÔ¤G ©LOŒ„Ï€§¡KÈ@p^ÆKԢ߮Üð¨rÌeŠÁ)b±Š+¤8\b ¿½ KžTë«*Å9;:â3òÇrÝðÞðÛlÇ@ªQíR »L² d:€¸_B“W{[šQN øŸD{“B¢p¦“bh†L ’&^éøÍFÅK³Þà‘ï±Ö$ä6u˜¬‘w‡ «‰_7AWDçÄoíC<®ÈhâÎ „!„Òí=&©àòI -MÍ–Ÿtâ…´´@-Ò@•È4Ðâ¯Ù Ƕ¯Ðxo˜Ý5~{cìŒq³š ߚ¬’³•áÚBMª+/NÈ1êÈñÃPGrõžä)®xÕˆ}»9Ï.,§²ö<¡õéãD8Oåá-&s¾Ö0—/ȳÜ!ƒ ¨!÷¢î«3å×hИI«`I¯Ñl[Dˆ&D´Í5(ü2WÐ.ÕÎÎú)HY3¨)@”rÊçðD…µª¦N'¶Eˆš_V¹Ž=š=hgEXФ;G½Àúëié¶9#*ˆºíì¬a^8)ˆqãŠU`D“¦Tµ ÀÓ¸‚UÑЇ8u–S3ƒN¯ûì‚Bé¢Õw gÈ [‘¦Ø+€b¬VÕ¡Ëbd¬Bˆ–²…¹Œ‚ ”6af¼M?˜ù^ãàëŠBH F-šÔ9`ZœØ\Ÿ²î-ú…V-ìañÞ‰F‹rƤu¾n¯.ÂÌr%CÔK<ž`Zb,57«2xF±}+醷Ö3 ظæ~™Âz-50ÖŽŽÇiýÁPN[¿Ï»hÂJNDò¾Oƒ–b9-€e¨’elR‡ I«x ®ÈO*ƒÓö¡éŽb`±`)!NÅÓ(£¡°J€S6RMtÿ¡”Då«$JNŸ-6Û’[!³nDÊî¾Ä‘öÚjAªHPu;µ+E½iÓƒŒó74[’ Y°nZ›k4q¯• á+ÁǬLˆz :ð£ËÑB…@®­TU²×È)‚/sÌæK®fe{… 9ìЌٻAĤºnª(‡ß„frôS¨|‚b³}^m¶|Dkµö7²Öóõf±Zû¾:9jòÞfãÉÂϱêìGY}wÝvÅÝuvõkópœé)ja˜+,Ó…g@SË'êiíã¤]X8“šb®ÚjwS A„×!r_¬«UòEÇB¥ì OHÓ\QÙÂèO”d,Ê ¬’¶~ÀiUЕÁ0À$¢AÀ8®Ã¿ ý¹`ɼlë?L^¨%¨%qÙAùŠ&°„nZüP8ÄJ0iC¿^ø(å‚‘£``…šEfôÍDô„‰œ¥Áƒš²@Z§4h²ÒV©}0Y"B2Â}-²ôwí2kC¨HPâAZš”PèÓ2ƒäO—Í:&ƒ3.EDZٖç{òÛ0òáX«¼vtÈËŽÒ(f÷»Çó2GpÖääï,”œk[Éü{Ò&8*Ä-­nÆý¡ª¢±Œì”ÕŠ¦%ðð:Ú‘‡6è÷úǽހ-·~¿ç7£r ‚Öºð)”{)`4Ò¹­Ü%jÀdIJY-XljeÁhjÂ{Ñ¢ƒð˨1ªþdzƒœl:KÎsù´Šz Ä:Žž}ª òå~ Užx@ž­:片U7~U¯•Q> ›/n1„ÃEtCB}èu ¤Äsû3½"YŨÅ0BœÂ±A©Ê£¥ ´³Tø(ݽÐtƒRj ‚»ú¨¨(Øhà肃 dV‘M˜ &†™àõ-T‘á½ØÅz·W*ñjõÓ‚¤hµ%ã†Lz¨8> ™”n=¸ýÂçÍæ`»™³?Ä["¾TÀ ˆŠulTI%i¨‘ÈØ‹ú¿ÍaR†ÚS ÿ;E4Dà av°Î—¨Õ1dÏÔš[J•ø.ÿŸ ŒBW© ݯV(y 6O¥óâ¡-¦„«B3^Õ(SÂ[v}mH4•:dÍÞXAQ‘ॠA\ÒQV»n¯SM¡VëÛ„::°£œ¦”@ë¨ÖÎ#- ½£^¿+äq‰žR÷_‚˜þfOÚØ4é i„€¦Ý—‘MjÄ í°`/ë'R ‚˜Ä¢¤ ™^àG¨ØE£`j´Õº"+A+ñg±™;—ðZ ú/ÌÖl‹Qhz á6ÈSñÍÓ,®_±²æM ‹•fƒ] BzxÈÛZ£n7.ZæÁ ²”ÅEÚ½åxê-!b»iŸ¾?­ˆe+ "í9)pÕ•mrv·ôY*’—ÊE?̆½‘ŠâKÀd æÁ`Rœ.?s“4›IûœŸƒ¶ Á¯,=¯–ÿ©Šh]…¸-åüˆúù÷ôœˆ XW´`jXÙä®|;ڂѶXhèIKÛMú¯50xšQ8¾Žç sý’B¿mYòÕã”Ý]ø}Rt•?ãº2úùpÅšW±ËCy¡þ(«"QW©owEkÈ|T¥5…@r þhþ Ad± þ õÖ \e–ÖŸB-§-ÀšNȤ„kúφ=î9Hú="nÆ.òaåT}¬ïÑ‚ðRu܃ȤVv!uÚjMÍH (áàÓfØ €€‰ƒF ‰ÄqW¢&†/õ¶P›\Œ…sœB8V8P,2’ò(Þ{­´Â9aŠ P Û¨æO ö0æ,¢Æ»ve;Ø­÷ ‹ÉÄO'3?”°âqQøÑ'ì¬ÎË$·-ç]g#€øRK ajÊèù •ا‚¬â·ijÀMhWX‰!$»…ÆÉE!±¯n¸;êôû½~¯;È›¼ëÖë‘ᢪ ¥¨—³táR!îEÛHS©ÈhÚW 2I(EPį1¤þjqAz‘*ŽÞ­#Å}üÉh`Cö°‚š¿ QîçJ¥Ö3@¶¡(Z¡ÔH/¹Ý|ò̉9­¶.j’v? É"T%°PåèD•h¯ÐHÞÎ*a­l¼[+FŸyÖ,°¨fU'×ÍûmZOYL7rè4m:Ý~í\®Èû iÝn7½’²ÙF€=¶X—t£r׿A]MhE‚þ5ΦEzªœŒ ²T^ÖñgäîÔ²‡­P &niØÕb ²Ü'HÜ›÷Íóš~#—¢1,eে棳Ëĉ¤œ "ª‘PÁ­ˆ¶h~zþè(ÐÁ,ö2V&ͨ¥¡6B|T²å“ºÐ^Ñ#PÌNõLx Dî£ôÛ6ØwÔY/`ã‚…ßÓæg5p¤v- aÛPILíTÙÒFN)TÄ:Z YJåàe?qµ<ä­Ï %‡“8^n›°aYyÃR÷¨Û×i±F3¨Y„†jô»;J§7ÈH®Éˆæoü'Âæ o3(“¼0T{aùB¯BÐG@PkJ@ðiCHmkňsýìDƒØ$C¯@2WqGŠîc°ªáJf“ä{é™dȤD2² ‘e`a‘(My‰¼HPžòm µÚÈâü)à Å4eõk~kx¾A ãKʰ¤0Ü•$¢&hŠDJ@¬>èA@ªŽÆ:Ÿœ–¹"ödaÁŽf@£¿äl(ìP¤… }  $ÜÊu­†Lh’rô #KÁ0¬²¢ù@Ó„w0òÆx  ëGšìº ‚\òj%—Íe"X¦0eRB,Y»)¸¥Ý- †Hú‚[•Ós_S2æ&è©%,ë´ ²Ùg4]EçÅ1ΛÃÃðqóô$ß»!€ÂR„ü3«¡`d89ê<Ág Á?æ­«ãrþ¯pLÒ¨-knŸÃ£/Ì (º¸öÁ“(jNý˜јÁ·2-l„IºÃ¢0§ì+`ŸÉÅ<+Ðúå±….½Ý†'C‡YáI¦¨a»2М„ ð.dò6Cý(|ÔÅñjQÂÅ£WQ—© [¬K« ‘nò׊‚¡ èTJ:T7''¥8WíQ6f¥Ä»sy€Ô_,àͺX[?¼?_ÄÒ'¾(…§T6”ðáÇãÙÕ*Gí p¼H[¢ˆŒ ,?gLðœ;•ŸNÅñÕ4Ð+ÈiË OÝ ÍŠÜð¢íq˜y¼µ Þ34´‹F“ZÝ4¢¥AÈ¡UJÐ.H@Ynjš¾ Á&UD€b. ¥ 1þ4àRzøvÆ`Sø8×lZD3ÚÑ·áÕĘ~bŽ D‹(»ˆI¦G±ŒãOO£‹eª@›ðiÙþ—¡’Tþ;€ö5‚…µ‘ª-†i4©zw0™|DÑ"R >«ï®#ú”˜ÂîEÁOåðg€uô:RÓVòý¨Öˆ­Ø©M¹AÄ‚ì›xÉà5øñ¾ _s½2ÓoÖÎBã@e¢ˆç‡×+ÈãpŒ¯ìz$VØô·í¤æÍ Üt¯aÏ3vܰI±ÖQyœÄýmúéñ OÀÐ"$±m ão‡IßÉŠ¡B“™‡DnF;%^%qQˆ~èš-‘‘(HÔ­Cœ:ÃöÖB‘ëeÑ©VgËúåi•Ë¢—Æ•· ÁUˆ/,ÜÆËfŸù:S³±$`Üi:bóÍ‚*¯¥r*×”ÖÚ©SÇC­Ýöál° ŒÛ;M|‘8š±ÖHœP5hÀN’Ì…"%Ûë±Ô.]øZ¡~8”'7}sÛzÁ›8|·_\5^3ø¤«è†àGî,'ó÷˜5Wºž>òOtÖNØQ‚,š%Á‡-gi¢4n 'ýáJÁÙîRª¨ÜzŒ@Å(ÕŠ–$PôJTD€4ª,²çVNô0°Ïj‰ß< Í„xý‡@ÄG2X .}'¥m=°Ãtß<í F­mŠÝÜ=Øgõ9•~{I¸#d.e2µ@¤°µÃn½œ6ÂqW†lŽïÍXã!ºÃÀ]SAá0hax#—ƒ“¤óØr'Ä'Røï Ø{ïôºÉ$L"‹ ª!$±‚³¨¥^f•òd´ ªQí Ÿ+ý²:j„Dû”¯¯“å2ÇbÁ})S¾7ÅÆ߆_/—<û%}½•ÕQÜÛyœið´À“ßCaôdBg i‘)‘GsÄßA²K·B™h·„UKϽmaÞm¥eí1½tŠ©T@¤ØÕÏAȰ-Ð$F‘,Næá{zˆhæþˆY ãQ„@¢,gjcé®"XT)‚U@åÜNDº@akˆ,R[ Ø•Ê!øÚa˜ü°W<*|‚é‹äÄÉ:0ÀñW"¼ ÉXPƒv„IanMd7*rÔ kLG‡D˜É”»5²å\T2#ŸeJÖEŠ‚ yî–\bfõ©>b ¦¼JKŠÀ ØåÖN$B_—ðÝܾ‹÷O{mÂ<3êËîGvëÁ<ÉG¢ÞÝ8z:ì<òaè(Ðñ‘¨eåÚ¨Â<ÃtØ*—M¸NF•±X9s—Ò¦ ” &Ûør&»\-Å”{EµYgšðïä£ÕmžyFR1ÇG4•§\Öwt£KSG›Þpa@…Ä€QZ{ä F«ƒj`,í4Q…Ô:Ò9­Ü*@È%ùÝCá' Zg¥xº v€ÄÔ€»©\ PNÝ—¥&Kð)Œ"EúPÑkM;Å"鯶%i™-ª9“¨ÈÖ*5ªióñ“fJCÎÜ®åPžÜˆ Wš'Âuìï9›Sl°2hrÖ›L‰•Ê ˆBÚp– 3HŸ¡a¶ Yô㫨2U™¢Œè²‘èpÉEf‡ÅžºÚCEŠUôÜ‚f-óõ¶€ÚÂdÁ‡VÐv [Ùo‰³C¬Úƒü;AR£Í¯þñÛ˜û:[Õ9«Oey`Öšh ¯0l`·Âˆ¹®W`—6"41Úž$F¬QÒСr£¼ß¦qµæi‰þTlín«k’Jƒ¡þIÅëâúQž,°1ÕAm™¡ŽZŒ,÷€·Ñ]™³@¨á 3nó^Ûcë‚K™jSêzøÉ&«ÂkÌöÓÙà™”N[4%¿·t7+9•ÖíÕðšY|T{f^Ž®Oƒ(?AŒþc¸ü ø9UêÎ]ý3«3ص'3§U$¦‡;oj#Ñ•^Ò‰¯Ýk€ß H⚣+DæYù 3ÓaAø½~\<‚b¢H$ñQ4$¨”:´ÒKÅ¡’IUP ô âá4ªÓ`“—¢©˜\ELúPÁü±È1mƒ!)ì'”}?%‘Ï%,«é”;ÛŒ“9$ð )º§M¤ÓÙ®'´^³dÛ°!¢;ZÖ„³=É)œ½‘>\ èÕ`õÚÓ¾K¢Ê u¹Ëòƒ a,vôxê©ÓïwG£ã““áùÙ©ðD¡!ï°}4ëw‰ËÕ“Z‡eJJÆrÍs ²\a‘IŠ˜4ÉV´ŠÇOCÉI×TŸœZt΋ÜÐL¥j$h|ä Ñ¨ÌÑÃ'xEA÷‚¬€þ|JnÙG1k4ŠT¬é‹xkp–JGà€ªI/]ÓBqÔA! JQ°h„qÁði-«NøüB¶:ú~3[!‹ùBt:€Ýðg4ÂÎÎÎÎÏ…çƒA?*eJª*ئÌãh妰õGsÀ¿¤IVQ#ÿuDø#u“MIª½ioá™H‡BÆ»ôÓ´ìtUF"Jk¹ìU:U#&! ET‘†D¸N’Ç´äxБÙæ aX›Å’ïOð¤®ÏxáõÄQìÕO8ʪ ;oõ¨ÑXØøôý5âþñ Ç÷Q”R‹·yØŠb‚É'ÁƒÄM“^Ür\sU§¤œ\/f x¨Äo¼{9ÝÆèÌù0¦U¨‚lv‘¢èfÉGÓ– ßÜÆ Ûü\Â|ê/Ó¬6t —.X2CŠã§¹/«þQ®Ɩɧž<¥•¾E§,,ª²D#Ѝ‰t‘edúª‰¡%³‚¥ªP£Õ$ö/Ý~On1Ý(Î*± è*THHQL ±…¢‡Ü€iö™xºhˆþ0¨Ò MpaР·]@댌)Ù½mÀ–1W`mpŠpKDÁ8¾J#P¢Y³]¼´—1ÀœhJ‹ —†š¥*dª fÈPsuD Ì/O~(ÁÊ ê Ö ðZëÈ‚MÔT NE¨˜æ–‘ $‰—òcš`Êx™’fn%6´Ã…£ d0ˆ„'”D/­oAªÀ:R4ÊÖÞTc%j"n¿ »ŸÈ2y£ŠÄ Œ*‰392`‹J•îçCƒìIÚr±šMç|J~2y|”ß6×é_žú!‘…Sõ¤¶w¯Ú¤9Íí¨>ïK(WQŸþááÑÅðqÚlP ”ë†ÕOŒº\¬TÁÔ-ÍV»Óo£Õ:*"³é'Fçç§ÂÓ“Ñññ±,¸XËÂàˆ”X8ÕTÖæîƒ!'l$©»k5\ç›þ<ò#ZùlA&Md¤.JƒRt‡3² 2¢5¦Ó”HªR½!%²MˆáÖ€°‰irt„‡%J°J]«ÁÁÏU+HÒסl舰&m$½–ry“ÕŽ‹tÎiM—£ >¸{ ÔhÒ@_¯·sÓ‘ß6YÌçjê@ËËx§×ïÙiœ]œŸéü@Ê¡ÆÐIèqD?N² TîČߖü –’EÛ(¼„lÂp¸I Á¡teZ*Fߨ{ãWìU6<· Y-eÍp[^ð±=É àJÅ=ì>‡c©7¨„æ 6Ç—¢7²6ó%/˜åõ*˧µœŒV€9…©S0ƒ>@&¾›¯Êzñ1bžìÅoSÉoó}â¡3‰‰ß†BN^FN·YÖg]²Ä9®Êf3 <!ÂoÃqÃ*áX"¶×‹Õ¸¡ ]mŸ·ëœ6^·„»F@îZ\-•~â•(ìK•mÃèP+dˆå~@Þ0¡tˆºK®2'Éy‡qØØÒX÷$j cÈ`®EV׬T ·p*[Oä´½£~WÌ™OÙù;Šr%d’Å  / d^É¥‹ ˜,xï‚Ò-*hPZ0Qe%®U•%*ú€Áì܆QSŒ ™Wˆh…$ú,$i!ΈA ]+`¡Ñd{Ü"‰.ýF– D0'F[4Má`¥¬ZðS* Ȥ¸ŽÐYvMd[RFú¨èÄÈfÐdºÂMîO•rÙKÇ–úvF–s‘ ÁvÁ¹{’´£Êc¤în.­DV‚çšÍÔ®»ÍZ¥2Y¹E¶ü ˆb) ¥–(˜u¾Ç®ex\;å±€‚™Ž)á W~é.wòð0‚Œ £[ÜÔ õ)æÉ/©ðÂQ½À »G:¿t½ž<¥cî5ãmÐíèØïvz\O†Wgäñ…üt —Õ5nȨã![«ÿÔM´5F¼äb¸éÈ&‰ŒŒí¶Ïº¹éHÆI™h# k|°=ˆòtį¬J“ú¤ÿè8%–naº4K{í`¢V~++úÂøjŽh0÷`( Žš!rutš’Z” 1˜„Ÿˆ ^F= aU°¦¨¶pl¬÷—€T¥Ée]§¼qwªXUŸ@o©dÕŽ‚å‚ ˆ<w£*ºÞŠJ JKÎ!Ž\c¤(((i 5o=sv-ž³–x܉;CUÌ;H¢ày¶v­“c^´´‘óªt¹N¡:ÏýÀPHÕJH”™I1<‡BØÐ "x®‰%"ìæÊö57E@ŠÕ+ÿß­ÊÂ)¥×h*`ìTÍïÁ^Å îÓת©Þ¢ =(%ŽB¨b$:ú0ФÕéfg‘á`öBª ÓÊ"íp ¨Æ˜@qK ¸?ZâR9ý”™û­ÞhZ¥ÒC¨BÐNÔ*|Ì,À£õ¯ÿ &’c>jd8¬4fWI/BÕjÔ©•W¤„8fFʃˆXA"P8htÔPT@çC5KÇšûÊìdÔH‘\š w@É4Á­±wË¿{*„í-üè*×f¦šw6{ÑñS>6S©Zò­ÚØ®½HgdúÊÈF.¦RÍZ¯ž‹õtº¸½}x¸¼½½¿½¹¸Ïg3«:9lò†Ž‡Ççç§ggÆÓ“³ÓÑéÉÉééèäDáÉp¤àÙÙåÕÕÙÙÙpt<< G¼HÍwsöÈ™B ÏÉu6.©x%½_¹`¡lÚ™:9£I4Šb}CPŒG×ÈV†%Q4N ”„£¨1äV6 µ0‡Ì”Z–#1XqtAšF¸ à{Q#L=d þWV圲P´]+!j³èIi;ƒßÿ‹ãË‹v³åÓj3¹/¦óéãd|÷ ÓÄÙx›m¸ùôͰ‹µ‹T»ò0ž©J…»G\¦ô+ôè…£#•T…ª™#“Ö†Àâ+N§H`Îèl]~eèŽ#üé,°? í²Õän0#•ELN4cï0Z{°Ym·Œ£Õäa²™¯îïfã©pü€Nf“YÞ·Æ•èМ9ˆ¹Û“SAár–‹rtJ 0ý4ƒ 6†‡Ï@Ý«R…\75­Û9ÖÉøq¿wÜ?;?•?=?=¹8œôeÏ}ÁKNiÛ.3¢¢6×,BdB*'8Þ>Zr”AŒ¥DŽ´¨« íÜ ÌËØ‰‰ôdæbW%£¨8K¨V+ØÁå…TÒCYEFšé)BoP¦ÊœÉFna‰Blç{¼¹x(à`ÁÌpV;àLJÚÉÔTÔZ =h‚Â9±ÿ"h*ýw è Õ~µ±à«à9%=l(¥’}­8×´â?´¸ˆ»ía•_yy™2¨bƒK]é+§ôhòY…ظ?<òk³»\ !¥bW–³ßéô;‡àáa× …ŽÝƒ¡mßKôªõW]a¢îÀO:DñÐ7º…1Á"Á× Ž†f¼ü 0ÓHm(j¼±C±›%ØÍ­+bMÏ_ÿ4É%hR /¢; ¥™º0QzªÂ„Ú e%nGÛémTçµwÐÕ$Ù~ž°ökM)úy~ ;i{[Á«À^©"•‚æ& ƒÏ@ ¦Gž2DÄ·ÒK`ü­qQoe(laQ£ª ÀŠÆlŒª3ËD UÔ‚%+™êƒ›¬Àví¥uí”bã«°“•Lpš2EP˜Dn¢³ 4â%k uê¨ðC›FávÔꌤ¨Ê¸Gôgbû<§™-)Âm€¨‡ZèAgÇá®™ÆKÑv©&FùŒeM„õ/f-pj-ôi€‚!­<…>Å»]¡É5ÔÀ?ü°üYêÔ±*0Â{Ñ }@;,xAüsš×Öô_ !I[žv8áðÿùÿù¿é|(3ÕÍ•°ßæŠ%‹8fP™r5¿µqTLŠ«†¢üKx5¹VšôÑçK¦m—¢…6ª¨ìj2 Îe:kJmÕ|®v ÄXŠÜxÓ‹éï·¨,ç‹ÉÃd»Xÿð»ïǷㇷÿô~3[Þ|ø¸Y­¤ )KzngÌI$®e¬r_ƒˆº‡Ý~•zóž·ç '£S™(v žŸ—‹åøq¼Puã±8?{?L pp³›Ú,!UXLd5Õm½£îq÷êí›Þ¨÷æ««‹wççï.¿üö«ÁÙðìêôhЕ|²oÜþ¯#­ä¥å —§C®&pnJ‡bÂÜWj¾´#-l×ÛC)a¶Tòl:_Mùúó‡?}ØÎW?üé‡éÃdö8?ºzwuõæòx48¿¼Ð:®“õ¹NI…”À]©¬Y³ô]´µký„¦˜s,ž¤a{–é(A‘šez®¢Óˆ¢ÒÏ€ªˆ€(#Gó°´.Í}¦ö=ÐJÏ*”È`…Û`Æ¥¶ÐDÞØÔ$§ ”fiuTÜK3¿²íLnÀH1vA¹ð %G5%EEöÒÛ|^%€•þŸØG,0]Åâ(è÷‰2ŒT‚þ-‘Q‡O_U":rQO»lSý™•üô{“BÂx[ÛðÓb¡ãfãÁ$ÛØ=ìzÃáàôltyy~õæB.Ñ»/Þ¾ûBÇ+ß ¿ß}õæÝ——Wo/*^¾¹¸¸º¸¼:?»8=½8=9 e]O†2ýã~·/¡9ûôÜy’Ýèù›Tò±°ÞÜC©þu{$$HPš¦ qM6ø¹¿­;ŒoÅ‹PÅÍÁºô{9uþˆíSsuœ C!Æ]+o ÒEI‰I_£‘²-)MÁèTwp ïEK8GDphõZ‹-XRXÙvS„TZÂ6â&kEk®Ï¯÷‹7Q²RõHhCíâ Œ¼ÜW³…’ê¬RŸ´•º²ÉF¢;E©=Ó)Xˆwõ™)Nä®cv%Ç äX!›f0ÀX:xæQvÍŸÑԺ˞qþ£ µÕ ƒÎ\†Çƒáðx88Ž×ó«E96,^*<꺭zí Z«£»ƒtˆôMw8À¨A¶Rœ‘?Â;2*´£nçV°‚?IÝý° &™ê±Ú˜ÝÆF3Uu1O²<Ð–Ž¹áv…lÙ|‡œK{+Ðö fV“[†OB¦îBæíÂgÒ?Ñ€2„j´Á£õßþ—à ¯ 0ãú®z”²U¬¦PRGS öH€ƒŽ™^`7–U pPê<åxBQ ذ_¯!øðµ—ü l+„Ð$™Ã'ÀY.MÀ¿âÂXJ*BJ¬üì®Å´ÕPð¯£@6 ³œ·PÈÙÇÅ^­¶óùr2™ß\ß><Œïïî'“ÉzÅ[Õún·sz:º¸<»ººøêë/¯Þ^½y{‰+v~zz~rv~&ŸLÈ#œ—gg¤œžËK;;9»PÖ™àâüüät¤tO伟)wt:Ңǹ²ü·~_ÞÖ`0ˆ»&ô/X~ƒÝPâäœÁ¡Ôty>k=“„g§¿ù«_Ÿœ åJžžžªïÄ ZÔŽÚ¤+±ðŽRê eÌÉ(t:D%ª0ÿ¬Xÿù(êB討f F`/šèÖ“˜õîÜã“a(‹mÉWšH<M‹"éÆHOá‚RÊfMñXO8@à°`¤dxÒËÐLÍ}£l€£×®šn²&ΊhhQb«ÊêÇG ŒØ*yÒŒàþ¶Ùlñpÿ0™LÇ“Ùt¶^éLt«Éóî훋óÓ/Þ½ùî»_Œ†Ç§'#ÛÂúÐôµª³á}òœ#HHbÂ!¤œõ ˆIk@ô®GnDÍÈ. 2 DŒH$hi–¸Dî½)llœ* ÏôÜ()k€ƒf7e1[lWÛ‡Ûûùx6›ÌfãÉVªžÍåͨ0÷Þ¹c„šì:ÂÈ‚k¬X؈.k#nT¿§³´Áññp${2TŠìœú‘÷…ó@É ‡›Ý(öR<•Xša&ÆòBU…]VæáhxÔ;ŽOŽ…§çg½AOÆ*nêbç»PšÅ<äclrè»+µh6Æ-‘Jeh +Òßÿëÿûïù›qÌ7lZ!šò¸Ó•‡Ò"ºŒeÍJ9ˆ»B™nxä £”%Tã&°SZÓ5ëÁHT@©ú±P”àš¨˜£#)¡šœüCªÙf€(l&.Ue¥þbfRFQ²ôoÛO™ã´øh…mXhbÿ#Mh@§Øj)ÍT{uä¥O}×+Iq¸Ù¬—ÛÉdy{óøñãíßþ›¿ÿþû÷øýîïnŸ•·ÝÈ$ʯz÷îí—_}ùÅ_üú7¿¹¸¼89;‘­T·Hrš²ÓÞWEò -ß Zø]ósnö^®W¼·i±’§8™Œ'ãDZ–F>ó²ÚðReȈÍŠú8î5ÉÊ®íêu56že?û})áéÝ»óãA÷«¯ÞýâÛ¯Þ}qõ¿þÏÿW21¿üî»ó‹³P‹„³ÿ&r!ƒË7’PR£PåfG¸û@/2ÕXâIæô—E^•ª>ëJrù·ò)ÑäY(™ò´0 %I5ª¿Vùf vØø­(‡­clé;ªêÇ`DÐÿ:2›˜+þ 7#ÀHQ2â³°¾æ£6Ù{‹´Ÿ&Íñm°2‚©Ç££ÊSÀ|³>r8 l‹~$rÝ£Õ›íÓòé‰×ׯדéÍÍýííÝþð‡ÛëÛÛë»ñýxµZñ„ƒçÿÉßüË/¿|÷ë_ÿò?ùŸþGÃAoÈ['Ô,éMøÜ;äê[(‡Æ2U>ÁsŠ jwJQC™¼¢‚Ž‚PŠJ A[ÑjèÜK€¢2dwDgè_õAÙR¥c:”XvÇhÒ»¿…\æT¦#‘+ÎlU ž–óÅ|6“vs·šmþðw¿»ÿpÿxóp÷ñæi¹ß?ˆZKŸOA×ò”Ÿæ”ËkdŠhÚûåd| 7«×Çaãû°:eÔ¯êU}óùB}7•Ãýp'h½Xn×\‡õ~€ŒT¶.®“v}–Kx6×Iß~ýÆ×I/¾üöëáÙèê««ÞqßU…07®QpËÇó“ÄÑòÖCpL´jcMñV"WKå›lžïŸÖÏw·÷Óûñìaöþ_/6¾¿x”ffóÉ TQ qóR\FÑ-Ò‹¹‘í#cëëtäÑÙ±Ò*€Ñ ¢¤4? ÂÊ‹výèhçÈï8>Ècžõí—:÷¾z{yñæ|0ê GÇZ ™W\'ÍA!/®²ÒvÔ½BÅx 5ê É¥}æ‚ r—õ!ì=¢&DÁ˜5¬nΆG…¶¢„Ì”Œ:ˆ”T¢Ô£hX~Ñ«WIuºëEÌ è‡B°$¨ª#Í…U0ä*?%e ˆ£áN:ܨ”u—º¢Æ`%údäây"Á<вH«ñ¬hˆeM=œÕÕ€‹h7VK³ïk`vrIy$–Î’Œ™(þñ£Œ bj ~¸W*˜e›@`ä×hÆÚa—¨»2YQë§À ‚@íHuX¸X*,…†]ï EIîK¬|© pöM€DóOÀ :)iHÈ ªê¼¦× dÃÁ†<¶Ò6 4¯X„ŽçÞS·ûÔí= {½ƒ‚JW´I ‚ndiú}!žVÐ è{²œÂ;ó‡=¶,žT·×š¢C…‰‚’;S­<9ìO±æA(Â¥• )¡£æ‰÷W|] óÊÄaå^Å„Jý˜B3.´ y¯ÅØÀ9F4ªˆÜB£‚žâ5׉¶h2YÂPJ2â©&вhŽ.qˆ‚Hžq¥ÌË¢ˆpЭ)•¥u€¥ÀáÊá%>?Ž"ŽöºŠ/Úˆ5$Œp “˜•[1ÏE÷6•x²€CõÌ­KÊõ1¦„Ê'_å‹g?u½Òéjé“6à “`åñ¦NÑI`¢<„i!IPZ!›!G†Kn¢éÁv8¢{è*Gt‡ -V9£eŸ&ÛIÏNa„Jwj#ëªç›Ôeòhú…J+ºÉ? –F•©§b ìcUwJXRÉ)ŽfZJw•ï@’†ÛT댰,%„2³ãë ¹2~@+6 Š`üö!RS5 ’æ`B¤'´"YqMˆ,P~îöÙŸdp¶Ö8ËCVèßvy ±—Û„KJ»Q …ÆjÃæ[»¡`Êze97h¡!«äz*$A€ª8ZÚ’ü31‹Ta[Ю<ˆ_§Ò_‡ÐÉgà3U”ÐUAHÌÞÓáÿûÿ÷ÿà¶Mï·)O>°P,q/µØæÑLìÏx‰$b¿¨Œ£KEŹ“–‹Y”¿ÞP •Î Âו“)ÆN7ŸØo Ÿ4à¾K®,…U5©<Ï0DC^:X ‘¬qJ0r#Ë-2Œ¡ÔlÔ©˜šè(D²Ì/Ì!•²Œ‘â5™âœ@N•­€Ë«Y pf§V¦W®”gï¹+§Q]‡o.²ÿ¼^©Üáb¾ÏV÷÷Ón?~¸ùÛ¿ýí‡÷øÓ÷“Ç{¹‚݃§Ë‹““Óáwß}÷Ë_~÷Í7_ÿÕ¿ø«ó«ËÓ³³þ §nÑé0Œ-#Õ¨Œ„³ Ö4â©IäæÒ-_;]q ¾ZmV«U¼†~2ž><Œo®oïîÆ¼éw2/f‹Å„W‡o–ëíÚßÓãTàÉ·[ö{““Þagû«ï¾ô¿ýî«_ÿúÛ·o¯þ³ÿìÑôß^½ œã¨©¨VŒa'‰Týz½å† % zŸÙ%0Œ­¨ìþ¬ç„Ì6j§ÙΰÂéz@ Ö±¥ˆ£xh‹Qê°‡Rò—<1(D5‰ŠJG.Æ^9Á‡(Ù>P òˆ”‚ú·] PjÒþˆL(ze±Œµ ¨ O‚ Èb?ö(_F,òNU›]U'£0M×Ð+ú³2*Y¨]Ú™6R­,’Ò¸a`£Õéày¹ZÏ‹»û‡?ýðþúúúïÿþï¯?|ß?,çK1< »ÝÃÿä?þ¿ýæ›ï¾ûæoþæoŽ{:Õ ®1v¸q}Õ••"K³’Òý!yžfÓ3n”„)ÍÒxq‘B#ÈŒ’ÐaF‚žN‡|ÒÉ(mJtP@¢# Aøê3nÕfI P!Ë]7_<ñ¤c͵õvû<ãÅÅÀ퇛åxù»¿ý‡›nÆwãñÍýÓz³˜Î5-™‘jµØ„ó'°Xê~›Ž±ßÖå}°G½ÞÑ <:ñk‰¸Mct2Ú$Tn‚ïEƒIEüÈ’ÒfD´IàcÙ"hK]󈪓2F Ô4: +DJg.ƒÐ‰·ºBЪùk°¢ ¥P™­"Q üj¡¦ ï]jd“ˆ^pžåÄâ$õýÃÁ slT`Ðï#ÌFšŒ‘.Œ9»ZòNF=9[''ý³Óðüôøült~>:;auÏŽG§ÃcžZöû½A/n‰õ_²/±‚¿E« ²õr¾uV0àQÐ/†ã`¨ÅÔgùÌŸu¬j6߆î*zÑm•¸ yFI Aá)é"j‚äÊá•haaÃ' Öæ°MR¢`Êo9K0eM8¥Ë¨†¦˜Ô(ØLUì¸R׫ Ó2X\ÂÄà}UÖ ü Ò–2‡h8ý˜­³ßwoú„¯ÅG‡"¶Ì#c\‰±§ÌÒ ñQ"ÆÔóâyó¼ÝèG¦s£_'\ã¸GÜžƒÑU ¥PHƒÖên"•ñ\6úŒ‰KsÛa°¥ÏlK«+F‹T¤®èèJ™|vºmK ÚÍË0°´‚ŒÂ‡ÂgAr©RÕ“KºédÇäÁùi>Û™'΢ëðСe%XCˆbÒp/3Õ6PW¸?ðŸ‚F$¶e¯ÀkÉJñø ˜ILc»µX“*~œ«#¤n¬ÚŽõ [Y[^±»ñ“ÌÖƒZF+³­ŒpŠÃÁ¼#û+€ƒêl{½Ö?ÛÅΤPqF@’`YC³î9® Ê¯sžo…c”T'-±%»‘ÝiÑì›ÞJaÈ5[~ ›pz¡“DnfFV;*.¦Tý»"íC! NŸÁZ›Ô²Óy»ekzaã nCàφaª ¨ÏC3;Ü­; „ Ñùrú=¾˜Ýw N·0„L@’‚ÐÜãè@ \&Á…¨(±B+Ü0ÉHFS0©K®þʀȄÊ<3 ¶£­°K ^S@BFƒÎ:T¿®P#ú ј_vbº,*¸2 ¸1ÜOŠ(ÕpP9̈ï6›Íæ‚Õj)ƒ¢y¤³¯þ‘ÎfäAŸ /ÎFÃË‹ÑÉÉñÉh0<>:梧/Œê$­+ú磣§£Ã-Ìq§D·ûİ:OG­¿ƒ~¯3tO†ýÓÑàôt žWoξxwõõWï¾ýöë_ÿæWÿâ_þõ¿ü—ý/þæ¯ÿê_üÕoþê7¿úͯ¾ùö›/¿þêò͛ӳSL³ZJn£­Û?ñöß‹³ó«Ë«óóócÞé-1 6iS–ÇgÊÅŠðÒ¹Xռؤ‚M“èÙÔÂB£p+6‰tNItÿÔ¨» +n× tŸ1s eði¢2lض2÷3\¢…¬xÊo‡“¼5¾Œ Q`£ñ Ì\¡‰³™¶!Y¼…@»H‹O›[PWšHÉpa¡•XÕO›aân·FT`ÐÇ0ðÅ_åê\˜·äh^lWËu||ˆæå u;£‘Î7F~ÕôðX§,b˲¥u—tñŒÕœa–®‹@.ùµ³˜ƒ°JÛ’ù"ÜiÂuït°Mƒ$xxM ¹…Xá°í"5œS'Aìð~]5%¥H‰fÁaÏ&ËvÃ݃+ö–ø6€Ÿ$Õ‰¢è`(b>zg5sºkòoèWaY€~¿?àëVå#W}êqaÇÄÐye“$aYbe‘.ɨ“½ØÞ RvÎ*„»f¿ 9(/~>ó §¬¦á®É¢ªÉ«å*6ã¦^ý(:ŸÉäò·Üê„Ùˆk$ ›lˆ[ ÚØÃIåéδóX}ší­3Æ ³k¥…G4º‰dgYA±0hœw{Gý¾tkÔ¹pŸw¤³dˆ:„iJîcìß%˜c I1MCe‰ÀÛà>¦›õKr͉p–.)"+ø0NÝÈh©é¨¡ŠH»`y÷pÛ…¶°•†žB=ñ ´hâ6B÷õ+¢&S·$¸\2ˆ”¦”ïQk†«!Ǧ!ŠèH}†I¶Ý[BVV¦[4s ±9ÝØ°vZB!u@9mÃŽílŽÀŽR:O½Î³öûãã.{o£ÞÙÙñÅùÉÕÕÙ»wo¾ùêËo¿ûæ×¿ùµ¼7Žõë_þêW¯¿ùú‹/¿¼zsuzv64æÜô£€Ì‰›’G£ó³³Ë‹‹ó³SžJU5Ò;BÍN3‚Æ¥8ÅEŽŸïÓÚ¶¬Rî(Ž/íÒ.Màg£>Ñ ´¯À¨§ï¢ûr€ÄÁcˆaC–¢r+gwz“D4#†I¢xÚÑÜe÷¡E)Kµ`4w!ÍçU¨||ŒâH(@n¢FúeOŒ–ÎQ Cœ7X}æ8ïEÚZœ¾{z:ØnžýÍric±’mTIY¼áh íäDCn¨qV:ÉõæfÎÖ€ô ®—÷ækR¨%R8â½+ J9"UÊX4S°i`ÚÁ”|S­5Ú Ôð'1´Ñ($°EФ#ZöÜ¡ëò1L5°ÙÌß>ñæ‹ÕJŽÌÖ~ŠHNQE–ssH°=t®#˜:¾ šïo“Ç؉Q–L÷O!·ÍÛØYL/u!K‚Ö?­… HH1‚]ô¶»]I¶Ó©Ñ;/sƒ‘Zº^Øo㾸5d2›LS¾NÊ{@ØxÃ…RW ^¶À ¦ :Z|ÕÐ>¯>Q›qÚHͳóÚ•Ñï$¨@ YÈ›#I×q ·×=’Ÿæoú›òT!MËÙˆi§2nm•É ò •"9RåN ‚Ø»SZ»7Š'­Ó}`D#¼ 1ÄBŽ™U€ýÓ\(ƒ8óJÌ9¬)!a'è7ÓÄÃáˆÖ@‚8¸ËèÂV…A–”Á.L׎‹¬€Â¤–…8²*D–hb 2̈‚‚ Ø+u£ð\È.hÕž“§ QS r¸FKˆ”hPùÄÖk )ôIU†þ,h “M,qÿÄœsŸ9Qa¥…ISfI`3² 3pmü Æl£8%w¡¦ïRk?«¤Ò¶æ³ @RTõmü%ï+ÈgÓ¥3?Y+y]ÝîÁ Ûô†ÇÆþÑq_Í_‡ß<ƒ‡ÆŽñðyýü´~zZn7ËÍf±Ý>Ø®¹Ì$Üv6òäŽ:ÏâÃ>œ¼Ã¾<¹Áé鈗‰\û}oWoÞ¾\.ÏOÏN†¾rʘóÀÖ˜Âuó–¥–e9ô‡lµõ}6¡†s¢«†Dãc3ÀêTQ†­4e-Ó3‘a¡5˜•Äe&Ð4¶ƒîçš,Š) dÀÑèņUd©œ Bâ!,e"3«&J/ù¬ýQp.ÿF±žÖ‘*¨¥q¸ÁW£¶pU¤=¬­ùSHc;ú’’ÛP£mš}Ì&”°]°Í<ºÆ){uA+ Ý&·Hœ¡geIkÞzÚ$è\Vç5œÊ*KO~Û1ïl“À)ƒ¢Œ•3ÒAìr…¶¶Ç¦Ó;jl¶…ðtD³ñfdí¬s]Gãs H¼ÀŒê`±UáAVèˆZeÁ®eákkäô¨µ¡qUJóË1˜P¢M‚•è'F¿ç­€Ší´ìðn¿ï‰[ÙTÄ`NR(¤b‘ž *Ù&± KLó}RÌ t –2©UævÙ¥œQOþPfpˆÁ†ÒÂæ`«ÖÀì Šâ4W(OU~›,¬7o×|-¯‘2¼ø°Ž]q–:RÄDñÔ@Ýn±–|šìó¼“ÄëˆOö¡7¦MAø—g :<•á:»¢¿8DÃØ%މªü2MzÜ*s”ÐÌRÊMwß+—dR ;äpäŒ 4’E2̽öEŠAÐz²6XnDwšYµr"mÄ€âÊ,A™ /ÁÌGœTa7𳍅 HÞHqÕ{a2gMûD[¼òí¥ïA˜oÔÔ$*ê²2ÁÆÎݵDÂÑÿáÿú_[OTüR}0Ѹ'âM›à´œ¦ˆ)ÓL©1âÉZê1„’ÏÄ TªÐ;"1¤>â) aÀi˜ bc’S%YÀÕñcVŸÀh2œ¬\ B,Š0: bë^µ(Ͼ8¥üSS”Ÿª˜„CY ~íöÊ5_ožuÒ{÷øð0ùøáæ‡>Üß?Þ\ßʸ<­WÝÎÁɰwvÒÿêËËwï®~ñ‹¯¾ùúË·o¯Î/φòŸ˜WÃH—Šå3ö‰oïq‰i»•#8[¯–²\Ü×òüĹšŠ‚ês9mGÁp ·ìììòòêRnÚå…ŽçgçWWouþ|zz¦²òê×ÅlªêâãxZ<ÏÏFòù~óë_^^œ}÷Ý/~ùËïÎÏyÉœtÁ~ñÓVÍ×)9z [¤±©% ñé„&A«Túʰ˜‡±L1 öèê8P.âî/“íÙ§8 2+ ì²94sˆhS°¤ùÇC¾ ‘)ˆÌTŸ¸ÿDâ†-íE~7)Ú/)´ÎT‰ÑÀ„”5ÉK< 6`~Ük¤8‘‘´2ˆ‘Ì‹>áªåüKTlŸ×›­Î\¦³Ùd:c.ÜÞÝß?ÜÜ\?>>Èí’Çv~:úî»o¯®Î¿ûÅ/Þ]]N‡ƒ>Œë”¤]0$ö [רå:i¶Ú˜mÀz dI‚—@IÚàd@¡ˆº€y™i2ÔP-K¶© ™7i>¨BTÍxš‡¸0ðà° OаIÁ.’Ý¥xæeG^t1M'ÓÛ›Ûùdþp{¿˜ÊƒYó‚ ¹~¼,t„¹â™&Õ<1 ðWÍI ['wåØvãdxr* !kq¦ß“ÑH%žxýÞf<žêTt1Ÿó.!ñz—€P5ÊV**céT×Õíð‘Ó^'^Þ6âMã=þøH®¡2óÛ †rËáôþÙr>[-–“lj’Zýý˜Of7oîçÓùìq"K)ŽöªÅXÇ„a )ݶæé@©á½QŽG¼^| ³¿d\Å¥=5óy£–òXð‰dlÐh‘% ì0Ï%h¢hýòúa§·ÓëôŽ{ýãÞðôXgÑà—o.ý®M麯\·Ò+Œï=ñjŸaZ R pXåÊRÐÄT¡F•õOœ‰«Õ‚ )ÅÊôÎ,A§%JÆÁXD¡J..c*¸nX8+sÈhy&BzÄ5Q¤Ûp;É"Á¼ü[Sö!*☴®ÏGE¢5C¿dH¶†¨Béá (%¤£‡D$G†ëÑiªBª B+‰’a!ÖŸè§€v9˜l? 6¼žúO !뎸Ÿ£Rq;¼^ml Hõ°z5XÄ1!ºXë O!æLos°]q+ÏzÉ[1enžeqØqUÇ=ó"‡|­ÏotÐTueÁr_@µle,Áùl¹˜­–s¾ÀÀmsËç§5»t<ÜãêYíðùRnŽªÔ\éñ:͸½;ÅPBWÇíHÒ¾”:àÝ›ýþ@çžEAVmh¤v‰âÎéGÁ]­¶ñ‚ÿ?"´e«¢¶{é¯â§Zý_ÂËܽèÔÜŠmØËjc…vø%¼¤ÿ$hP0ÙŠ9âůnØbÀÙ§íqÉ+~i”ˬ!iߣ©Ôko’br~[P²Úá AóOŠ5P¡Iy™§Æx3§Ý,~›hüè(=òh‡NïØ oQ%ưËXÂË => C5gl¼–Fºó$Cá* h¿ îªOCã'0¨`NEj/c‰K¥:ÝÊC[ËÀÊFZÑ”¤æPÂûœ€È‹%œky^#e9_×é+ÀúÅödßcÏÚŸ ´R¨£‹†Y|¡ËÏA»ªÀ?öÁJÛ„ % l§ÿùà¶ü hч!Íkðߟ[Ý.åØå¶ŸÁ#ÿgTœ†ÑÌ@1&[õÉ&x ÛX¶Â½ŒS^Õ³{dç‘‚†Â‹òÍxœ_ 5º§ ÆV Mö#ØâßÈ „â\{G¹ ˨µT «–GÒytøöñåЯ¬wŸ¶Iý^ox<8=s¯¥ÆãhÐï‰ùº.æ<—¬%°ñæÑU¶@#þGÚ°—FÛÛ¸—Ø&®Ø&HDW»4ͬ‘Ö4Ïí¯B)‰-ÊÃ4±o¦Áî †ÑJúä²°¿]¯7kN⸹Múf›M@nr1ÕÓ²ƒ1Zè&÷”êîpkWÜZÝ•èöÝþ Ÿ¶‹›Ü”X¯a„ÁU9ÏýÌ£PàAH|,‚1bpJýa…£á µ„*íôsøÐ¥¹¸±Ñ‰°ÚºÐÙëRfv:ž g^<¾e£qs°y>تFéVvß'1dłʰ²rF9ê<¡tvù¶ ·ó±ß6ä›Ñ#™e7UÝDQ5!´VPfý‰V{… nÒ^¤,°»œ^×@Öù‰o¡;òý<—ÀW®B£~Ñt¤åÁT ˆSteŒáQÂ[­T^÷vT§JhD¹JÄÃΧU€Ô[ FDBF²k0”ƒ·#•‰¤Ã“âk#4Ï‚Szƒ VÈe~x5o ôaÔLYĬ|Œ˜pÑß"•A&ôÐ1µjd¥t¢Ô%ë’}÷7†?aÔá‘ ´äêlƒjEd”ml«ÂÒ¤2;lR«,¢Ð—BÚh €¹Ž‘O…lLiOS•ÑŠ›ƒOþdA2|€ŽÐƒ 7s0ifŒàŠ¥ì~z‹»Áâºa»F™ bH]mÅN^ÀUdQÕh³¸±ç|4(õÛáñ›žä´Åí5ÔäëiÁ %¬>9NËåv>[OçãÇÙÃÝwíq2Ï–³ÅvÉ–suxSÒ€×|ôއ}nãÞÔž»p‡]°Ó{>è=?÷6OÝíSw³9”¿7Ÿnn?>Ü^ßß|¸»yw÷áîñúar÷¸žÉO\ë\S¾Þïäd/ϨªÜfžçм°Wõ²]?貃ƾí—r·ÎÓÑÑóoúí G}9sgçr×FÃÓ~oØëk,K¶èi×EíÊ£ÉÄôCh1»e6˺}‰*µ‡ž{ 0l¡ü½°Q]ò©þ#°Og~TÆ0 ÇcQGF>Öº!…¤I4q;w?úóÁ h]i,#5'IIñ:Ø)÷­ìBC£¾hºàeŠzÊô`´¾îÓèK³PW©´x5ÑZC3ÐcnˆZÏ7,·xl:½Y®â]\2BZ¹ºò 于õËE²ŽîJ0ijT»õJD±nS9¹!ý{TÐb¡gI“ÄÈ1ZEÉÆ—ÑJ)Œ‚¤—”àilJ¤ %Dª–j¤´vÎ*€Èf²8$t:G?kMf·I›O¼sh÷OÞ˜.ê>à’iUͱá‡bQäêK× å·uûÇ=öÝm+¼r5'ÿ@ÊGÑ"˜Gß“âÑIjxÙŠJ*.8úåËxŽÚ@å .,ZADØ–EVH…xëØV~ÿzµY/Ö«Åz=_­æk> ³ÜlWrQ(Ê% /ÚLÖ)ƒ^]¤Šò¾Z9m]Vè<¿Ç—âË€]™fy¬þh¨Ô“2¢gàfM6ÑV 1S.‹…Ó†uçìƒJ¥G;`Y³è _Xg 2üÄ0F.×[&‚eÀvIÝÙ!hV鈟 ”ò‚ Vˆâ6pÐÐ4#F(‹aܶŠÑóé/º›sX$–yL•Œ:0ÎÇ*Æl¾ŒQ<=&Ô.&JK)´Û£†¹=ÿ(É9G#ÝÕŠ[ÌþjlŒHÎh5#OµÄ\ m¤°ôfÈ/J˜4•3L%˜¬ *ÉõëùƒÀââQ ö/ŸuäW£PŽ| Þ‚h©Ã>âT¶'ÔÆÄ„0¡:—nÍ\×¾‡.Ûˆ­F+j]~!Q4‰æ@iC©.ï*¢–(­Ti}š¿ö߆>ƒ&8˜§ÈÅ!Îk­Ì¨“ÃèXY0:9‡’!l æÅ/]­¶Óéòþ~ò§?¾ÿÓÞÿñ÷ßÿ‡÷7oåºÉo“m::à]ðý£N¿Ûé÷ü⃳‘Ü#xIeêÅ­Æ>ŽÑàYxp,\oŽ–ëÃélóø¸x¸›¾ÿáöý÷7úÝû?þöOú‡ÞÿþÇ?½ŸÜãÅóú¹{À׊G¼ë÷<æw%-ž³O–ÑæCöL–ÇÏÖ‹ÕF8dž>qé¶w0Ÿ¸¡íÍ›««7ÇÇ'ØFº„L­IWO<*!¿•özº¡Šõ€:‘! ‰£`D…Ùå*Q“[¹³`ÑÎÑ66ÄIý“ )TŠÕ‚uÊþ¹àá Ï6´£Qc…ˆîÖÝh ¥ífE® (åÛŸÁÂ0ÆT¶ób(è=ÜÄšXEE*Ï ŸÎ)íÒ|\.ýY¦/~%¾AŸû©„£cî,’Ýò”lÆŒ‰ã*í®Y 2c«ÁúoQ «ýSbé8±J¢V¥Œ AÚ`¶#ã6Ir5¼( ֺǎ£Öä-wÓ®¹,ñ%uMlMnÙ¿Úæ:GboÁ¯$K›ƒ¹Ã¢²ñK†Ü•ÞàèxÔŽG'Ç2PǼÿG¹"Ķ‹œM›I WN±0Ê´+,T]«ÂÈÃ6÷‘p™šgÀ 7E †ÜˆŽbOÃ:‘EÇA¥áàr¶^Ζ‹éRKnœùÄ×Û-•¬“]ßTyÜÒe‘ÍE Äþ`xÜw;:‘[–\wò: —÷ Ä ´=rQª]4a„Q•rYCuùÝÊå4~ -2+ÑÑn:ÅfÖ‹1à(ÇsAF„,br9wb´U o„±T±F‡x÷i¾åJ^,b Iê”5Oc,¡Mø ¼þù‰«Ö>uP'ˆ¬PB/d¦BojYÆžzÂ'½ž4/ix'Ž|\ß‚•ë² !9ê¬Ü¶ÁT¹N(bdP"[ˆcd²…ŠB9n,íUñLF ®1tW+×ÐŽÑ"yM” }nÀSý$" ÏŒöÝ Ð:Š™«lmZí^£(SÏÄ.še+%-lÚæd¥ƒÁµ¡Ó…ÈùC‰Ñl¡‡†˜ëH ~å^D©5k@ª n ÔQY:2Éã+~-6ãˆÒ h8òiÒÿžÌŸÆTÀ' —&ì¶Cˆ©ÜN&‹»»Çïo~û÷¿ÿ‡¿ÿÃoÿîw¿ÿÝ>üðáñþ»þ¹ýß~[÷pà3ºÓ³ãóóÓ““aONŸ»ˆ“‚NÛóñÓA{Ð_­µÀÇ«û»ÙÍõøøøÇß¿ÿ‡¿ÿãoÿî÷¿ÿûßÿñ·|ÿ‡÷·óñìi½µRÿq¦ØÕi÷¬%º÷íñ®P¬¤w·<ëÊsXZIuºêý¶m·ËžÜ`ؽ¼<»¼<ÿâ‹·oß~!˃Úóq¿¬š¿áÝ©>Ÿ3[ú”ÚèLFŠÑ„„ìà4ñ˜OêQF€sô–Ù<˨Œì:‚öa/±‰–Ȱ1üh™j¤fÚaÁ§¢QïOƒ— ù ¸ŽPsÔó†ù“Ù? ²ÂF?Ú¦;Jo¶0æ§ÐµCkzö1ožã"—rØ‘ÕÔl1O§¿Òp«±ÞëqMJ#l8<5¬iÞŽÁàÕ™<¬\cd©ÆP©2™™yêÕÈ_[!šB’¤0QA—ª hæv Yú !wrtMVoõ¦rÀ!:œèVAYQÛr½š¯W³Õr¶šM³ñl1Y,§‹ÍÂ_G߯»ÒXD²|5W†6öØG:Çíçå`¾ì>ô©Ãp88Vj7ÌŒ >ŠG‡±ÙV»}>F¯j –&”Ò;‡±*BΩ²]ü“ž¯8óu†Xåðf,ÀÖžFÓq0T_4º3tcÐG¥AN׸sÌ$Á¼ÈÜ%Ro¥‚>+‡V ;DûŒ"c P8>bK_¢jŒ(Æ1F)WïµÜ2ñEãu©Y6áF?{µ@59ž‰QÉÍ: {?’w+¨i\ÒŘ0QÜúlKëQât²jfF[íO’3Qܼ¶³Ó«®õRPv 8¯/×há1oÖ·øEMBsn% ¨í«1"Då~1ˆ¥6µSÚ-2ÜF fEF<î3 {@™R©E+û³¨4Ž^!o4O ¡$ŠNé‹•boÇß\ÛAøM\<:ƈ\Äž­-ˆ‚nfâÚ)!s@¤¿r„ÑüÐ"ŽßÕñzcCé-ünG×ó‘ÄåT›'ßǶ^òìùr6[ÜÞÞ__ßøpýþ‡›ïïï&™,)ï’ŹS±ƒ§XtøÞ(–³ Æ«Fª†‹Î?dQž»ÛƒÞÖWH…2A«õáry ï œm³Íj±Ý,ž¶+œ±çŠÉáäéR)(6BêÚ–m´P³&¯çäÕ$¼Zn¹Òy:Oª>¬7£m§Ë¥Òn_ç£241·Ã¸ $34x:ðù¢ž‡È:\!ÉöZÍEZ¥^€ç˜qqJ©Œ>ÔhÜ+•R¼„vâÍý§¢Qª¢ å(Ñ&P•aÚ1 R@I,z«˜?DYè¹è¡¹ ©àœÌÚÃ6P³«N°hîÇŽÆçL~•ý†£lÝD¡æ—»òr@\™7CÔÅ´Çô”°#Ï–Ull-B3>ÚQAp¾„½ôª`·,×DôuäTÝQË\ V¨<‹É ŒÚZ ˜‚Å: `(€ýK«²\SàÅx,—,@TP*/ܽĥ„l¹É¾kiçäN Ä"Sîœ\0<¾kCk(W®<ò­F3_ªµ9GJÂ)1ë°—$Y£ ==”ïI³„Ø/! Är ´li±—£Æ.·«NÛr¾Â[],Ÿ–›§µl¶”ÎixôDˆ!þqæm{®º¹µCK®×J& ¸ðädyµ0€÷ Æ‹tØíJz6´ D²|Ê]„eÑ-«¯Nk·² (;8Ž_4•§~I}àõpç4; –Ûha@XC®£z7zÁUèô îiw¶ÎÓQ"s«[)Õ.pƒi3ÿÑ8Ú½ªUscü¦CÆì,“&Ó¥,%]X!Æ Ðã_±¸ˆëÖÅF˜[œT-bï?È)Ôò©ET~ÑseXì=ÚùL`˜†wÚÌ®WmqoÃ̲±M¨^öQúf‘g±´2½nD).ÅþðHTë3I¸"žÊ¦±Öa¬¡(«ˆJF×”.š%̬JO±_ƒà©Aås0\ …3ïgB°¢-†L} ,/ Ù[â•ôücAÔâß0ô@K<§dgz-ð°>Ñl°ÉXÌyì`òððøððð»ßýþ~ûÿæ¿ÿ·ÿÝ÷ßÿíßþÝïÿÇï¿w{?~œ,fs^,´’o´†ã³Îl:ÃãÁÅÙ ïN;ñEˆA_ÞÝÌŽGó×Le]äì-WÛÙ|9™,Ƴ{Uv??L&c`.d·ådjâ"¡Àfñ¥–KäWúõ|>‹Çý½¸MÆ‹ÅTçé>|Ò`ÓÉÀ`ÐåAx.Za¾Ô —6dJ»ƒªÿ¨>ê]é?Ô# cà¿ßð3zÓÞ…è+&h2ÉâødË£ó…ÎfV|ªOÖïðPîÚÙééåÅو}-ce)z /åùLGüûÙ;¬œÏO~9¤ŸEX¬8œ³u.ÕjåQ»esÙmn¬ʳ=ÆI ×­Ë ù2ï=6.0ùœIú¯ÞàXØÓ$W+Ðbõ³§ytE»£(F>@£×(ܳ@. Û§Ír³˜Êb-fÓ‰,áýäñáQ°äÍm2†¢…=óhWç*° ¿J©Zd}‰ÎúÇ2ÍCý°»hEW×m¢¸ƒ£„Bë²®=6ÚX[qÛÐ*þNm°g^=÷ °¼¦¿Öó²â,=ý/Tf«¿q¹$&•jQƒ¦ZK‰;‹HxÒ¤è8·ºl£Òe ÛáÍ,–Å,Ê'D/ ˆ½ÚòÞèÁ~–»†ËØK!T÷ó3ï'´2BÁF’¡ 5kP­:¢ïÅ0> ;’DÄÌñ<ì½QÌÉ»¤ ¯¥•Ôê?t{É'`œ¶€ ,ŽtP‚†§¼tƒºÄ'Q4NgHª€#z3ëÑ $_A «`{ ·£b)™_öéKh[ÚAÏ‘t¿ÕDÏÎÊ5fÁh;l(&ƒ Ûž):Ñ” º WsÊ¡«þÔ’£Eg:™M&8mwww7·w?^¼¾¾½½½»‘÷8Ÿûë~>mR%•×ðãK Çýáç•báÈI5­TO¹ÒÃQ=³ÝÄ3ªb8NçrߨÃ[ò)lðˆà ;ÙbµÒ`Ñ;•Lÿ’'9Ôé+¡Îç“él2›Ž' ²‚nùò´,‰$’\''#>%}q[úìÓyjºwdˆ½‘Ó—Ã8­¤Vªd N³DÄœŠÆ‹õÝ÷D£ïL%€²ꪳC2=!èkñ€=&´£{”¯F#\ :*»ëß'Üm&}¼G&|˜Û‡‰Šö’[‘6|\cOÃw¹XoVOÏ|Þ Ça é x7Ÿ‰˜<¢¢f¸ùGXepnô{Y†&}"±oÚY{”ýéhëJ{\a΄If€ÂETc ÎÇBŠ¡Œ‰ x¨t½òc¤X¥5)œ²À³¡¹•ŒášL+M&ƒì»?lÉ¥ˆË¥òál[H÷j‹bv.r;–Ü DœÜ° @ˆK3¦±çâbÄ‚¹¸Æ­`ÉbCq«¡ã{$ù:Âd2—UœÎ„[ó8‚š—ž ‚¹2/jÉe(D6Fß[_j§šÌ䉄ûmÒ†(ê gÒyþ…š‹5Pk H¢ºÁ†©NP„Ë|Pú¢>†ªÚìž·¸âÈ] 1†¼ÂzޱÜEš×ÙƒvúBŸÐ)гE%Ó¼áN49A:ó7ú¦C6›8nŸ:OÛoæ‹MɧC%òIy½0›•q™ÑÏó< ýömÙÜónL ùèâÛSC1D²ÈÊ* XÊBs)>)îQKidƒ'|•]PIºŠ±GYîdÙ±/| K%Z.°)¿Q{É$jö’2‚w€ûÇ#]ò­|WêÑéÎH>fm b¥`AIõþ¼äk&·À“Âû%Cg­µ3‚­…žcî530:ÉdLžŒ’åûèhS¤BFM&h×èDD{ƒQŸt¢ èqɆè­Z)¿;5ßî7ÞˆÒÃzlž󵼨ñx|/GíÇï |üx#7îñăÂrÕTZ'%:Ãò*u<<ŽNyý†—«~lj¹Än w M&3SªR¹n³Ùl¹ZÊB‹*.³r¯„|.8h\ ¦Ú1G·MWÙ½åZÛD¼tž*s6+UÄý_µ:=¹à‰„Ë««KÞ_¬:®Ãu;õ_rÊ$(•D4S÷RR 2Éu•»­®’(Áð `T)ÿ© -*̘"…äÏGµ(X½¦‡6Ühæ  IúNVhæ¬ûT£‹Ïi Ï¿sM¡Õâi»‘A×ÖéK|Þj¨³Í®‰„zY)C©«ad­ô¶³T‹à²ØÞ-H fìup| i!++fô‰#àÉ\Là*/CÛ¾§KB1Jb"Áªi$ÄTrG öß…wvóò9p:sóDX<¼ô­m*-êKÈZ 4 ´áÚõ/KÄba«ƒ‹ˆ©—*J3Êh¯eV»¸BºYΗK¹jãÉøq2yäýéxªÓQiDt±ÌÚJ@Eö‚¾3[Ž)MV[Üßç—\®÷B«MBò†;íÊ2ÀÖïXº©)\6¬u ¨ÝšTI¯5M,B‡ÍŒj«Æ¸RãÐñ½r¾P§D/ý:Š±Î 9Ÿ–2·~ƒ{ܽðàR!û8rè@<6ü3¿‰ªñÒÒiëÈ«ÛÚ“ógˆBã{Æì½u;=ïÆùf+;1)±%| =zœ‡‹i?ÿî†Ç‚ìgøž<<ŒÇì±qmõ ž± ‚•JÔ Ý10d(òët"³ˆº¢#ò6´éTŽ–ìgÖë¥Ä‘ G½#ïê›Óñ@VÀmÆ6R^˜½hŽ~ÕË­.–˜¼ùmã‰\ÌÙ{÷ü¬%SëæééÉùùÙååÅÛ·o„“‡­¸©˜nŽÓÕ.–®ÊêJEòKŠÁQ×j¬åŒRí²¯bœäòØ#0´Ã‚ÏD#ü£Ñv¢ FkÖ_‚{‰ÿŽ0'¶q/kHiuYJÒhÔ0æåbËùB¸ÐªË©‚f”–­~Ÿ7·ÉghÖØ?Ðð fXºdˆ‚ˆ¶ðñZð‰RÀM6¾…^M‰ U£…IF‘ˆB¹{ÑP¥š@ƶÀG'ˆ½tº±“&‹pôå5nøñU”¦ˆƒTºD¾«“’þq(ü^n92®\_ÑóªZ–Sƒ­f¢zS ƒŒ#¦ÆHo@j U ”náÈ÷ S%Zþ "aYâ5ujðZç¬\kŸÏ&2‡“éd:çnsîìÛlÄÍÙ(ÁX4†Ø¸k¸ú©~ª6™?›fµW¾œÈ±¿ÜædEô ~Ù/nµÑ`Z„@QáìzÈ}6¶0 „/,B5º°wnƒ•R0r@ 4•1Ó#A¥Þ!ó‡J¸•‹Ã“§È¸‰L¸Ú~z^?mW›íŠoll—ß,>kž‚ˆ£ðp½=\?nä·±Qw¸Ù‰Ú·Ãç;zæå ~)•œÈØf ±»ŒÏ@6†8= … ØÕu@zaÌáØ†ÏÖM¹ÕÑt¾-°»‘³õÊôè zhQ !ŠË½f:6þ´l’›\ìaów@«$À¥UF·µ€‡©SÁÑRÄŽc†ÄéwÕ"jrq†=Á¸±id…¨E“ ËÍ‘Íâ–Ž±o/ª)^õį‹4DzíRÄGmöÙFáP9‡2¢Q„²M¡Ù$&DJp™…•Îme/d-Æc_- ð†«–ÏZ{./xŸ-_ÿ¼º¸wMóÓÒè¼C'\6†Ç|©ÀÏÎhN‡˜^l>UFWäë%1Sru ·I“ŸÏ°œ ÏÎÏ„|ˆ›çòæF„…§Ò3vr²È²­æ+v<Æ39m²z³ñt5_èÜKz“ÕÒÙ¦ü¶‹óóôÛÞ¼Q"öE~›(¸ÐÉ€ð ÑÐjvgj.´[Aã² ™»èIèô 0 ýÇÐ"0;جlC;º—ûJÁËh`…ˆJª8~ ƒìG± ‘RÄ?/†ØWØÉjÉ\:"ÃH^{GƒÐ'Å,¸yÖr±^-•¤\o¶q]žÑ×4Ñ<Á(¸¬} * °u ‘Y{ÒšIüÙÝ„vJTTÂMÔáŒ6ØÒÀ¡O´2ñˆ€¦3!êMôäÉi%ÈFé—ùâ‰eÕ(+õR¹oqC66ª3Z®°†™ÒŒ 6KÏG4¬`ÿ Àu“MÑôçeÛl>?l ÈjBê¡_ «ÒVàÚÈzò6<†|QØþÿr>*¼^`™Å]6N5aÊ­¨¨4@Üô/áe!Ëâ>¾hd¸l<Ó7®°¹¨%Aüx9ÜŠŒÂÈ\Áòx…aèz€éB–ŸÕf­ ¾Hj ¡‚¢ ±†‡þ]þ…˜-_Žt#“d™¶C–øŒgÆ7Ã'«ÇøÀõƯ¸Û.כțŠ5)g‹Õ|¾ž-WÓÅz8ßÌÁ-¸ÜÎWÛùBø´X=/ׇ+9pO9pxr›ŽPëˆÂ:>·ràž;›Ø·Ã¥ _Í~[¸|$í=?MÌÔ§ƒðÛ2̪ŒfD¯†'MÞKÇuEéÙ?M—@?üÄvcúLÇTZ!  ˜¸ yª6_ I"Ýc›˜½–"³=#Hu1¿U ½–ë0Ù¤G?²1™•1Š<»<ÅÔr,F€¤Ï™µD‘OcÀ·EZ€’”«R£9TŸà)ŸU Ñ‘«Èl¦rëÎ뾋9Ûe£&ºJù)Tq­úQËD\y#îÚjÇÀ­œ¶¸ÎWÂõBj\à·Í‹élÉ]Ô yoéÀ7nÛÂçÅR®ÛÁÊ/;Xm…|§Çƒp÷ÉqQ58Þùbí/?ò¬¬ï”) "\–¥E‡òÞ¸7ÎÏÛ2h¤1ÉÔ `iº 0 èƒ…ÀuQ Z má\g÷%I ’¡ Ý1†dfÚLi(aˆéé/õûSÅh"IÕ@+Þer”úÌKÛGþ5¼BJ šR/ ³ZÜvàSé‚Èjç*ìÞ¢…­(aÏÀ@u9»†2.”jåÌhÄ}û]eVÃÐpwËÚÛ¦ÈN°Q €–­5óÙüq<¾½¿¿¹»»þxç-6yk÷‹Å¾á_Œºzóå—_}ýÍ7_~ñÕÅùåÙÙ™f§ÕŠÚø©Ðaž… §M¦ÆŽ‰PbÙ9B$æšIÜÒ&˜,³PN ON†§g'gçç§§§˜_iuÑ Á³~Zpyt:¾?€ÂÉd“}k‚Q'æºßç:Ï;pkB&Õ[—ÉŸE·Y@Ñ 3ë5hg}*ü?|Ø“VÑŸ‹Ÿ‚½¬ÏD÷øüô‚¯€@\Á¶bíÐ ·FaSkfy«Z+ë\£—.´jvõ:‡r ü %_öx —Ê1htrœ¹ï‘$4”{Ä/èö²>Eö>O [/I[1êz‰ c¸n•uŠiÚ<­yÑŠûÚÖk™*,'Æ-olJh >+Ç3Zè€ÍÜ™¸œU3½ –×ùR’ŸV[ÜôhTjD~·7cÓ„·@ù€ò䨭Ÿí®qƒÇr:ãù¬±Îa¹Ác1çQ}.n(¤.ê j"W$½j«ÉejZ¿ëžð –Î{uÊíw>óº7Q©r4¯T©oS6Ç—Ú¬Î.`-GBXÇè—ûö½îÖân®E³R Õ*oÕ«S\à´;"ÅÍ€â!¡<"yfKPÞØj¶ʵmP ˆp<_Œg³‡Éâq¦ðôar£…íöþãÍý‡Ûû÷·w?\ß½ÿx÷áúîƒSœø`|üp#¼_ßOïÆñj<®Ç³Ít¶™Í7³%ûs‹Õ“&þzõÌKü6Aö ýð©›ÏGÈ%Ú®yêfý¬Îƙ㭠A@A&&ÙÒÆÂ}(Y~¬${.Twˆ¡nµPܬ˜8ñö%Z„V¿+ÈHm¥TLÝAILލ@Æ.ã•¡‡”͸÷þ"äÁqhLœT eÐÛ/‘÷g`€T aº.N"Ü•–p~Øn[#íí½baÍ£x2It4´xíaTÔ®N@4dµ¸þ¨[ÝD³“¢ºÓ´Œ*ìÍ)®S®ùb6™NÙi{xxÄc{Ðïãã|¹[YÓ3yPç|Èóí»««+ùR²:oã*¨(|5m° ¢ç~Ø#ÞŒÓXç‡xä9H£æÑ]˜æ ›¾ÅM«žѪþ°?’¹9‡£‘Îé$õ+ñóÅšâœUƒy½Ú.t*5ÑDjÒNÇš²39¤ÜÜÆÙϳ8ˆ ¯ŸŒ7×ëôó¸ü¼ r{x¸á¦VQ £ð—Ñ#E•Ye:ZÈbZöAR)Ûo…¥èg±w*BOÿC=i÷%ÿ °W<´‰ÿäÈPÑ!!èºìt:+‹1¶³­UË ‚a1ߺf¿ /Ã/ÄÑèh•ä}§ì;çÝ ÔeèjlDÇøªáØš2"’$d'¸ˆáÀȵ$¥E@²2m©?ÑpC»l†c ר±@ÔnÝê¿Øwdÿ ó’e` 8ê߯¡°–z¸$Â†Š¿Ž°ÚÈ¿aÁs Ò!öÝúÔM;°õiñ#-ie•ÈÊ 6*_a9R‰j¶YÕzÊa€S^­÷P0DŒU@½‰J]E§å1Ý‘ç-<+*¿Ío”»6™-&ÜÞƒ7÷ŽÞïî'w÷cŒÓÛÇÙÝ£<¶Ù½œ6¹k3áz2[MfëYxl‹-N››•Är“œwàü8*öÚo{æ:´úHZÖH¶Ó&ŒašMSsI€HKbè«­}E«®P[“Ù¤;ä3Qa•¢öÕÙì` à=çdeˆPã51R §4†È"1çM—A£VÄ⌗žöf Âa:ãG‚ª°Ù4à ½ôŠBICFÈ uTPÉ&«8R‘¯ÿH”ˆ‘Õ ‚!ÞdŠè.l°(2X8'_5÷…s†µå·Ø[<Éàù¬Y…=°–t1ÜuÔE ƒ °‡+ùLlØY{àºèÇ·7×|%þa¥s±í¦ßï¿}óöÝ»wr×——l³é4ŽÆÊ[â"§ DƒÄ=÷·Ù°¶fµ}ø[ó€ÙlÊsx ÍÂ%Òw‡ƒÑ™¶|y‚††ÎWƒ1¢q˨Û$9%ìB¶n<}¸{|Ð<|xœ=NýIS&ÆNu[3²áÒ0H ©¸Ç•±ÅX¡#i;RѽMô~+§A÷û,†`„Ý—:VŒ™KBÒ´Ðé‰%18ÿe”PMüX…ùËÑ ¸Ø¹ÝQ‘ÐËâ^b;ZÃ/£¤HªÅU´µí™k`ò,:~i= ³,€‘Ì•¦5ûl¾G“7€xâ(S'0òÛ¸Óó˜OAÊu³Ád‚2 ”Aµ«ž2f]܃dPÅÞÅlN©ä“è‘î¹õz¥¯a˜'T…;.øÝŠO4"”ÿ¨Ts0jfb† *SzÍ](vÁ]ƒÜ)ê~Es22˜ÐÙþqc°vM™;(ûQÀã4ü{˜`£TÁ sÍ 5%Ç)A–ÀPŽÙÆ Ù•A- ¼xã´¥K鿯ÕnM•¯,„"_+‚åø °‹„-‡ùdâ§Àº@wvL<,am=*Û’ ƒê1âhw·3f=ôY_ˆç|°Å-£2@ÀÜÈ.‰â(ÛAu˜ÃЖm¢ý6¾… ÅF~ÛýýýÝ­·kd9¦Ó‰T)F£““/¿úêË/¿–Û&ÿíôìl08–ÝO±¨ÆT•i¦Êb{G<¥Õïwz}YGÙ’ÖhQ[éîâ–µâ!‚)~_±áš¦Hä· ä·†:âÿõ»ZãéÀJã¬îÙý´µs©TM%ùœ÷Óñt>™êLH‚¹V<ÇPKu,,½Â3HØûm±Åâ* æAìPiø… ’ÛXwsÃÐWþÑqa–2=¯a›Ï?üܪ /ñeîË”E©™nMý€Òa*ʈúÁLüL4 ÒƒU̽¸KÚ ê¬ ÊFÿý:‚NÈwyøm땆¤L©Î ä·ñÁ7ž^d{èÇ-ÁƒËã þ¥.G÷z/ú*¾ð¶|Ùÿùs04Fí)¿ÛRÐíŠxÒ§"_ÍÖ¤ö&ûðønFö1µæÙ”•~†:À+0Jü§’ñiðÕðÛtf©¾ŽÒE£"vŠ\¨@ÃÖ¿NÈô ΦB,x0ð/­Àäo03B›âzÃ: ÑßJ£g½â•‹Ål>÷û&åøAøÇÅt&Ÿ€;Ûâ%deI*2| (!W:°þ8OX`¾Fê'ñO†#næâ‚ r'¿÷ªq+`iØ¨Ýæé“°Û½ÛJ"°d»µ”p.c¹l¼Õ³ØLÒØs1°3*•vÑVÓÜz»ÕxÐl›ÎæãÉô~<¹}ß<„ßv'LwíúúÃõ­ðýMzoï?^ÿðQÎþÙræ®o¿¿6*€‡w«,Ñüé‡ë?ü€÷ñ‡[ùmo¯ïoîÆwÓûÇùãDŽãzº|Z®ŸVrÎì´q4®]z—Bm×Ú¥¾“sýq¸n,Lì„Å6,'´Â/˜*‚^Ü#«)t•ý€Îu0Ò%AU /(3…*LT´¹MÔ€ø¸¦x“G'2Ò5¤#, †\'mÀ‰áÉs ÌE¼ømLLš8®²”§úGű‚ãê!e¢ ^`hÇèNªúrn-žàI *1Ê‚ŒB E“è@&Öh»i6nFí†`•Y¢jêQÁÕvÎód/´ØL&ãG¾-pÏMa^{–²krÑÎÎÎß¼yÇSgrÚúË©ÙPÞ‚é[†Uc´Ã+F}§³Ý^O®[‡—åú&Z÷%íñÙð[«n-wœk²àáÊ*Ë’v»áPGçˆÇGý£N¯ÃN´DWH­¨â¦Æ³õ,V«­¯/,§BG•þ“¢¡Æ¼FÕb<YKr‰ÙL¹f’Ý—,€°™õHÉ0êäÞ>wûš<²Èl»ÀzfÅh—Nžµ^a…”³HU1W¶”Ob›ìu,mTx¯Ô§£!u¾à 6 2·1MbB 7·0ýc­¬V948køm‹5ÉL}ökB!SðTnˆ(å²¶Ië:Øcsgà´uqÚ¼1‚ HC‰ zÆRÒ’= éÒ +gPChN˜<XP²X.Œ0×FW²]óŸÕ çLçœ|‡tº‘Ó¶`8±x±öG…TP¢qÜ¡‹³$¹8©QÖõC ~!WH9æ‹5²Î*Áú¦úåúÄù¼à'Ü3T1[ïͪùùŽq­ åfË n: =¹t ¢@(SW±Mµ]É×á"éózó¤ugÁåÑå”ÊÙãtv?a¿íöñ×í^x/îúîîã8Ø$»¿÷íÛ ß+zs?¼ÕQ>ŸŽwÂÇw×÷Æ»Ç7q'œ|¾û·âs-¼„þa|û0¹{œ=LæSIÂ…Úùj³\ûÊ©EErzßcˆÉsï»]xŒdåjAÕê"3Cbª*)‰Z(¨ €Œ’ÂØD‘4‰ÂfÍAŸ$ëH‚eK¢f§=!Ìk@à@®²2èÑóùßÅ…‚“3»èãDÕv *Šfq7Û˜‰ªŒ©hdLÀ|ÿÇ÷ßÿñ‡>Þ^ßÇc-¨R…šÃkÏN†‡‡OW—ǃþhtüöÍ• g0ˆ{øŒâÒ)!ßfÊÍ{ªžžÔ€ØWµ<€ŒÑÇ»(ˆ@R–(Ö‹îDA›ÄV˜ÊA „àà„Ë„ ˆü$vXðj4Âmx™[ *ÐFåêé{”AVa/*ˆøxÂ8I:hyJ6Ö謄šÐŽ:¼Ýá#¬¬ªR{B‘âP]¨è2EÑ»VkÌ‹Çñä^CùþîúúúqÌS̲¸~ïÂñ—_¼»ºäÉåËË3ÞºÛë1~ÝkúÕ A•K€«A,Ã¥oÃê IÊ`ŽDÆ^Q`HѺŸæ fâøq,o˜;´XLdaŽVmkÝ2¼^i }\NcÑ­£¾ôÌGúÇ'C©T–Íœ ûCÞ3cC\½Py5*¬@‘j+] {3 |J.Oɯåmùð[Ýðgs„×Êõè½IYzï&¼ÑB"Gr}U#‰oNÌ&\Œ^L—«Ùj5çÞAí¯Kù[ ¬âÝ‹Ü!7÷}rÜ7yœÌxéñl.q:g;€ÏÉÅFßÚÃÍ>y’3u'{½^ µÔÒŠ-›j#®¥¹¶œ†3áÐ4Qo³¡lбߢˆ– +†Àé §‚ÓO(ÄQ©õgwÂÅÂ-‘qÜNqí¢¤¬È]†Ê‚QëVQê6‰·rSí@¤S°†[@÷»¢×‹aékb²¤­ Q£•CHoI€/¿®¢-RÒÁi‡Czr—”z+ùZ ¹FƒçEιV#©ô%‰v y0‡/_^ä³ñ3¾1Uî0³}:ñ½ƒÓ€““n­ætMÅé9™7öè|Q‘ìjù5X^kÙíc s8ôºâpùåʸ¼ÑWºèy î Ë#ŸÃc™?yl2žö[÷"ÀV ÆüéLL®›æÍ:ßÜÆ7aæ«Å\R©MA…¨aÜÉ YHMx›þ%(+аkïðº/KíWÖ?¢.áŸUúuY^e¸—X)kúA…=2Á^¸} m‚Ïü¹ÑŸ Ÿ)’Y>f$s­‰K¥NKß›¢QÁ.íQ÷°ë—w»ž u(&‡WPPÂ/¡f½Äxÿ%P‹Û ŸVP"£]&:f^)YɉcBX|-x¼‹kqyÔ»íÜȯ9‡é¶ñVmaÙ‚‡;€!ò‡¾ûÊçòrìs•^I­ÒáTþH²˜ä» ‘™eþØåçáBGجt -óÅ»*|ýAæPC‰Ý¸çµoú<”QEsŽ:¼V@.bïHk—çb¸_E6™{ÎLjnô HÁbÿ(Ô6U’ÙgóÖ_Tà.JØWq…a)…Ja °· ú³šcrŒ„ì¿ú½K>ä:Ÿs—ÛT8g«’ Ëá™QŽO',§Kx%¶ß²–÷†Î×ëÙf-¿KžÜlµž®óõ+“ùüq6{˜NuÂÀSnÓÙýtø0“2Ÿ>ÌfTAÊDNv©ˆ÷í©ûÊó ŒÏ]MÄ…ÁÈò‰*#Üè¹½wxŸ—K©È{‘»¢ÐŒ]À}Èâü¼€šnÊ}PjdTÊ£ÿýÿùë”,ö²ûcŒÈ¿S’FÏ`0A ‘³|Â`MqÒ s’zŒB%PD0”,˜ìP5 êC¶ % /^àƒ5Sa+±J’˜•å%²èDå‘Ã;†¥å·ŸÎù‡ˆŽ^f¶»‚%ìäz“Rè¹Hi±~kÊE-¥`D+Ÿ&j.DƒIdEÔ”ÉGPKUˆ¦ÜéÁäãnr’7 Eîg¶{çsN¼|{èÃýãíݽN–‹…D9 OOF_ò(Ï™FšÂÜåÆû5 }K *-Y&­ r’!$dk/±¥«‚0¢EN¡Õ?Íj"KÐâœaAÈ£[ E£RúA3Š,ïKŠ5.ˆcS.“MÊB©åB¶ ´ ãå^ €:8¦O)Up¯€ º÷É=³á› Y…Ù¹¤ÙF¬³—b? !ŠÇ8fþ@vÏÄÈŒHŽÑ¨CÉŠú¤ÊŠOaKøŒÂ }IU +m tdyH(lÅ0 ìðW$à.ˆ^ãÎÍ6£¤Ò? QGg³SÅ#ÉÙìyŽ~OïòÑ$—Ñ9;?»ºº8ä,i5¡œ/¶Ø9Wt"âŠuçðéèˆý6Y(?mÊG¨‚‹¤€f%›m¾C`ãžkk(•àC?»n·»&bÎ×®š×6øpoï2™3·'|K~¹˜?ù ¨FÅ¡6½¥×‘/¬.—¤Ú0ã„1«@!J~\Ÿ~kb„E½‹` hgídF;4¥$†} ZE>GüS 0|Ô.y1\uäm&/°Õ¦¤)9ª­CcèçÕh4Ê#ÚBZ**QW³­K¶³jT®|Œ@¡)๠ôQ0hª´1Öi!ÃJƒ’õ×ÞS—ETVcŸ‰ÐÅoð @b Î!ET¨׋ê2°5‰ý–&´e®"QÒé:Øii@”­Å?•U=F fÕh„…@t}ÌDÜ5t« 9(S¬Æ™œ˜0ÏÏ8Yh5Qu´¡ñ]üì^xŸÀ3¦ÅUbØqæ'ÊôËo+÷{aB8²Û¦Þr™P1ëÚ,¬:…½tò¼˜ ú'ÈZëIÜì Òb«@G™J•óY«¶oÎÝpËÊfÃß³…Û±ÂÚñ B(Ïæ±ñŒÊ¼¸ÑlÛu¬»ü¿O˜›Û4ìy„y/®,•¨í¨ÕÌXÕ²aÁ¼nDG¹’W½ÔLõë‰EAŠ²îÆ½mÖ-jR!ßKõщ- v¯Mˆä/*¬ -F±¯ÆÖ£·!y_î\Ž¦Ì»QŽšïl+{lKœ¶™<àÕ|¥RV)ºå-cFÞ’ÆsœR{,jáуwsðïV±|-Ñ”(®Ûr»Y=mæ›õ|½˜ú!Ö‡éä~"ÇñþöñþæáþãýÝõýÇ»û›»)®äØò,p¾¹×öð*,F<Ï(ÔV;ÀE:0\÷¯ç„ýi‰jº&Vv”Ê)  *W½Y¡]Ð5‚¥ßw:=êuqèmé×y€Æ¦f¸†¼f ÷ ôŽãÃåÄÌq‡I,¢Á­röˆR„´Lõ¨-Zdܺ "0‹ƒ-’£ŠÙ â‚JÎÉ¿=öö0ÒÅÕǘ%¥R C€î.õϯÿ ¶JO7&]˜S …ç9‹=ö‚s+vDràPN‰ë6;g$J¤0ÄDµpQ¦DjГsÃÓôgä,‡,È-&0æ9ÐìPEÔ<eT¼hŠdg $êl™{=_ìñÈ]/ñæ:ÍäÆ)öЏ±Ý××XéÍ’“f?xªÕ6‡4üÎC ȉï¢ã·~oà­ÄáˆwÈŠªVãVºõ™ÿ’O­?«Î­¶ß€-ÇËPú’ƒ¢¢P¦UòõϦŸ«ØÄ7DAA¤‡rrÑÜ0ÀAG%ÆÝ›q·™ïKò†”ñ_öÁ ØïÇ÷ì´é\g+)“-£<-ÞÍßæaã{y´Låª{¯–ËîWy_,//xÞàÕA¹•r`n»Yð‰¼·õl½š­—ÓÕ|¼˜?ÎåÃïÆñ~¸ûë»ëx^Õw+ÞŽïîgò,§Óõb¹eÃoÃ˦žäcò}*/,¬-`xK ”]Æ9ª„ÌÓˆ.ÁÖB&û¤‚ AžH™m·Ôস(AX"”1°¥}ýÃÐX0 Q\4(Ê@y­–`¿Íùª$ÍEH‰ Á3Bæ+P× ‚•rbÌêÔQÀä:¹ò@ôÈ;œb¦Jƒ:g‹@ª8¬ AMû¢Á4QªTÔu‡ŽØƒÍUʤE'1â|’€ÐûÿÐNÒY¡ÈˆC”a%†Â A;ªLý‰CgµÚÌf³û»ûï?¾ÿá{¹=šG½ÎååùÛwo¾üêÝW_}uzzÊŽ÷Rû]þÞ¨ª–ßÃöþŒy«=øj¼››s<:¿ø€—=Ç*{ħKy­­¤Q?ª_Š!Óä“)7yŽ5#Õ¶Ó“ÑÙééÙwËÙ £`ó õ·—ª«dÕ9 ã>Gù}rÚ®?\xÿþ‡?þðpÿ ÆctÜ?;ùÉwœ¶«ËË7WWgrEOÏ´ÖÞÜ\ÔßõõG¹zòYçsÉ&C$E!uPèœÎÓ¿»…°Õ`Q<=ÙB÷¸›.£ëÁÔ€û¨ ]ç^H©úgr¹‹=µT#ÅlŽeH¸ñK¶Ì/3;VPZ ¡¡“)M«,sæ.ÓÉì±ãˆ.Óªy÷L PøqÀ¤7ðĨŽj›/Èž«&¹ËùjöÈ«‹&:‡ž.g<ŠøìOmj±P ì6z±É@Ã,ÔMm^–´j—&:ÙÉ‘LèÅÅÙù9÷%÷û*ÏÀ“ÎÙ¶H¾)ÝÒ?Özã}½Ù(mô?Ø·žoVÓÕb²œ<ÌÆvÝîoî>Üp»Îïÿðþßüþý͇ã;eÜ/f¼ÕEòøoÝ¿I°: (š³Ö¤õœòêCK3+n È9G‡pyœ²•‰ [L;ïRâ™hÜÒ‰”=-Å% ƒîˆ¸œLqW¥Œåš#EõšÈ<IÖŒ—zÆék üÄ/@Ô³.4ø<æwIw! ¤µ=ˆ¬z|L˜¹~ "ß³ ”ˆÐ.Å*ì%6-4쵺v7„¼MdªýÀ×Iq€¸¼¸X„ò5­üä8Wï˜7k 4mœ™J U"šb® ,•F– ‰þé1#n ã §Íb!dLWŸŒú ‰Îç…Q£÷é|­!Æ&s ˜›wC<—°ZóPŸóÖÙÐúÙ¯Îòn‡š#sÖé÷xo8Nœ\Ïto£±µíÒúëýy¦)`(@½"NB=5Ú*»kÓ«L“¼J×ôùlnéscRdfBÐTÈAÊþÈ? ^c‹TJªY5w—ì/…=ÎmlÃ'£{¤»tÄ‚ ÓwBX¦Ð’ ò4®Idf ûG¢ûÂDFƒ->«Œì ³†±4c‡:0´G‡²Êìé`ž™Ü_åÀ •ð.„»Ï¨PMšy̹l$PãÆ6™~ZÉI¸pÿYÌÅê³þÔpbüú ' X@"—V”Ú”Fõ)¡b©Úqe [˜¨4 X¦ŠÝ)߳Џ±ÿf®‹h"ˆ„Ë@hP8ðÖ"À-ˆ&0.I–³3¤%’ÛC¸ÕXÞ†üT;mñâ [€ÕÞ®…zÙò7•l!Y¸Ý´pªäÉ{ݸy‰â)6.5¬DÕàÖ´€ª²TäZŠº‚KɪÀꈈ£åÛët„pŠ4nPý+Œe¥ÙçÀkxädÊ÷]ÈÆÇ}oZº¸ê7ëDÉž®¿˜%qq‡Ìàqw2xT¯d“Ö„GܬˆŸÄ.FìÕȯÓäWèhå>%>ù«ñìÏ•AM€ ¹çÍK«Ë§õb»^¬yE4Ýâ}¼þ„Ë _˜•ã¾ÂjÐý[q<àƒØžèhÓ[Õmg ‰:îB(;;j¤T ú—nv ÍÍC+«Ãæe4ÂI¡‹ Óøwökµó2špÿ=Dªpê 6\-ß'AÝ· ¹ú",ȼƒz?'s[˜€JAÔ]Ò]>J“@ö.›+ ŸWÅ‹Ä* 0/Ì-ñíj¾žMç“Çéx!ÉÿˆáSÒÓ;Àu)¬©ÑvËgãè_<ˆzAÀ`1u’η¹©\#˜Îæó¥&šFÇ`0<==½º¼|÷îÍ»·Woß¾9áCmɆì¸ÐígÔ¹1¹öp^O݃Ïyøí³ÏŒ²×ÒCÔ€v ûf=NÉ”¯uñ‰ îjâVt_~^òÍ€¥Nò8ß3`ë½ZÛÔ‘ˆRi/L¦øWµ š³ÝƒN¯Óí ÇÇc‚ W)÷u ×`¤f*J ±]¨‰ú…QsÃCno™-fS¾'øp÷x{sw+#Œ¾¹¿»›úýû3Þ1±àÆùpÜ1ѵ´’í=ÉE°‰8:?=9åN¦vû=Ÿ*@¯uAîV[Ž'«¾HÊþ€¸PÕvö R½ W 0ëÖÒa‘G½úÝÁq·7PB¼”¤=J\‚Ò(ØÚ·5#‡l9_-xƒ׋g~süðx‹~®ß_ øá‡ënîfžîÔÑ“XÎyÁf©†A`§ ½_­ í¨SÊàFãÀW¤‡®†‹˜ùûjhÈJ±2úÝÃÁÑá s¨õñHœd2–‹íb¶RßMxæt6›ð*¾ûë»›ëë?¼ÿýoÿ»ßþîÿðû?þî÷~øp{}÷ ¾6àÏI ˜InóÃø !¬ZCóª r´BÐ2^SZ%„C§-PJ$¦•´†]4«€…[=ò©É4œS'ooeû(RË“;cË›Içà`]ϰ,—ЃÁÁ3’]³=t”ÂKà㢉?mPñèÉߨfXp*÷ž‰Fþ³ªg¶Ç‡uʳ¡rK»¹zOGåá†Ãç5—Sµþðn¨MÇOB°™*áù*ÏÁåõ%e¥_Þ Â[!Hî5;5VÁzš1ñcPU˜!Ѥ•£Fq¥ör"35Èœª¶œà˜i[.æœÏÊ„nC+Vƒ– ¶«Í®Q<³1çõâÏÌ#L”,;?ž|n%glì½Ñ‰<×Cs‚Fôž’`°bRªÑªÍ„X1==f<àXÂÙµT%¼ÈIÿôIDAT¨€ŠÆ4%D -T¥IÌ„f[ÏO€¯×pͧó©N '÷ãñØï ܇ó³³7o®¾øâí›7oNNø,¨ŠJ{Ïeì¼Qƒ3a¿ÄœˆNÚ¼b©V-MZ¢|K›ß7Êm:½M‘,³ŽlÝ©”N£'㱑×þ*] › ]œ_€ÅŸ@•©RìÒEר;\®u®²Þ5üÿ³÷'J¶,Kš&±æyˆiOg¸™•@u5ïÐH- -HH‰-tƒ4ð*<ïÁ{Ј4Õ9ÜÊÌsÎÞ;¦5Ïkÿ÷«¹/±÷îͼYÙhhø23·AMMMMÍÜÜüáöóíçOŸïoï4,•K"£ÞÔì³Úéuúƒþ›·o¾ûÝ÷ÂáÅÅ`8TkñŠÒrË1ì«Íœy5eÉÃ.ã«Ø†‡ÑE3§@É'ÔMk%÷…c»=C†õ¢£’Ô›4káÜ¡3!sK]¨lgeÑf +džct¸“ÀŸGgènA‰ó'éDz[€æ%è²îŸê «©>~æ7VìÎ7)@î$ÆÒÆ’Ž œó óÆé%4š#4u#ó?*@ú)# ‰ˆÍŠ`EãÆ^†ÀØ“$dCæ~†)Ÿ .ór‹?2UØ%{ÀŠj¾Ä Ì­,§ŸCsŽ‚A=^ܧ:¾U€¼I M!®ŠR,,êÇ +¸Ås1…ó ѪFzW%;XdsÏ*^Ü΀n,UÈ.,v€ÕÐ u¶KðÖæ´S¼B•ëF)‘¿Üæf¨*'«yª'4¥î”u¿F‚m´+ñ®SìÜ(ÿ‚ƒN–ŠáÕ·IFš9õˆÊ¨NÇj²]ÙvUŠ·ÕhuÚÝ~¯Ýí6;íz«Q­Ç7½·ø¸ÙŽ%hožì›ƒÚó6ú2Dea…IðÈÚ[Õ{  Vb€;ƒ´«ÊãÙšÒí‹¥ä4ÝfGÚÖçßòÞ诋ú#­âÌxüÈù:c¾.5šÁ¨ùbÎQ;lMØl ±KùXí‘hƒKVã¢.¯Y ÑÂ3¡¬´RùIƒ•áÞWbz UrÕZã·ŠÚì,Âñ€[â*Æj¼Åy›b½©õ±,ËÙj6žïÇ÷Ÿîn?Ý~þøùöãçûO÷#Õåq¼T‹K¶×ØpÒôÖ ,ª¶¬-71:ô‘˜‰ •ñ©$e)Ñ}?ui²±U ÜŒa‰EΖNZ„…ä§Ä¡›ÈÉ‹ÎÞft˜Ac$]Bº›Ymªñ¤ãE3òVIÍfõR·Ê!»—'?EV¡¸ÎHÕ ÊéÃy×M‰”a2M ¥D'‰Ú˜=pB§T\s²¾†€sÉÙYHz?"hÑ´ ™hJˆCÿ†,Ñ¡Þ#ûdîXùKPKÙ@ ¯Õj­V«Óíôú½n¯Ã7Ÿ—*nà,ÛÂŽ Þ¨z!R2…°Û’r¬k´ªUØ g¨…"àV†æ©TGèåõr)¥,!(—Ê*³Ýj%l¶¤XóS2øGuÓaÖ+ž8̦‹Éx:MFêÛž“J-¨ÆÕz¥Ú(ëÚlÕ•×àbpóæFÀFÝNGÔðAýØo ¬Ò.7m”cš…â*,…éâ?ã8œ c%T{ácú4d-™Ðý‡›ú^ÀTX!Ÿùb<‰Þ_މº„ÿÐTþÁUöŸ9¢»àÊàY¥3Ñp$Õ7èÌVe’d6·ÉÎ@kBÍìL)$úÃlh )ÎË“#IL†)[D*+Bš0 ¿û,ÂI QN›×èä qH»DÞÆ¸U(4ù…§bf¥™üêÌë4º³D_¸JïWú°+kPj%d9倒¢\qô£.òþ ”_6ˆ†A;¦å/s &cl+äLQá‚Ò“"Ew™7ýšÀP Ö]žÍÛ0õËøËk¤Æ…4òf»bÿ‡V0_Kù!:QQzé\ÚÞ#ˆ¼ ”Ä¢®Ž·ñ¥Æ›í–f ò*P•WjQ"åægR\@ñ–بR\àWrS_H”A›ˆ¼AqXyŠî+GÀЦBuñ\ƒ€Ca]j¹Á€“ÉΔh‘ÎÑåx6 ZËÍÁÝõä…ƒ\ÜrË#Riý´Éëz^Ý‹A²ô„­–cÑb;WÞ KçþÒ¸uv®fÙÉtãÑ7}ßü¨’nõ¬uoz;l—ÛõÜŸÌŽWMý&¬Ìt¾Á0›Ë‚·lÇ '6w>™×!äAéÕ r]ä4n`@æx6쀖Ք>¢éÂcsBdØvéî &û/Pb÷ ©ÿCŽ¿ IÊòþ| )ZF¹TLô< k¨qûgáe´Ä xÍ =‰ÿ,Ä÷O¡XAT)ª‰ñ(•´7ÐŒB™PŠ n&+ÍûÉ4m¨·;1FÛ˺+IÌ¢ÂGÛ›ý*ŠúJ)^0²R¤pwkhK™ØxW¯ó„˜H#«—+¾4M«ÙjÔV«Ué$Ñ,ŠäPlšîh~¥t²÷–‹Í‚¯#0)gkÑŽ¯à[b÷ꉪG³]ïöš½A»ÝijžíQ¬ÖdX6E//Æ*]V‘—3*1Wƒ‡Y-N%ä×i‹‰¿×i0sœ,$\™Ô!îþf C0æÿœÁ K³Jü¡@"Ô±!.Y—¨xÚ)ÅÍCvϹ5¦ay/³×fSNyÓD&E¢ØBãFª[Iãî×!Ï.2!…f͚Бäz!¥#ìKà¬ü+ÈÊÊŠHÓLgqÒ]GK5r¨:ƒ‡À]0éõå?L„ÝÒCâµµY²µRN hÃ0lˆúË^”ÕŸ“·í†¡ƒa¡Œ"Y<›BMÑò€QÌ;‡T‘BíNÁë>EÔŽ‚Ì+–¯L“xjƃ3vÜïXÀa€T|T)G‚2ˆ0±Mµów*¼ÒÏÂ[]39TM"P)SZÔ ²V<È4´+¯Èɑᗠ݂“Ǻšû.ÕW±!v¦ÁnyÛlNÔX¤Ñ@ö 3[¾@Å–@ Xi<·2Å!\­š¯€š“›…A‘::[y`K• «ˆp¦kåü©R:TÎ÷e !mOåÒ¡| ;‹!Ç’Ažº’£QÒvþÄ #˜à9U£v ¸»µ?D»äC´ëk±9OÓ>AYo,¹3˜zyÐ̵zq,,*äÍì; ^xáe¸€Ó8§€d&¤O9Á3Œ¾–»á9l?GfÂÁû°>\Rw‰àÕHšÒM“ÚˆeÞ¢ÄÌPÔIÂ%í¼j,ŽLc„!Ÿ¼·p±HkPN‰-‰‚ÌnK÷ƒ†‚÷—€b óZ¼‹{`ú!4+Hdº—0ˆWxªŒA᪱„ 㥞9j*Ã*ôt6ŸÍ·Û­†—V»uuÅÁ×××ÃÁ°ÓîÐáa…+ Ë! ´éVHJ£Ë;[Õlç|N¾^ãȃV‹ï“v:-]õšH²LAÁ›Æõ?*˜²e¸Qæäìÿ @Æqý0ê=ë,´»ûQå¤ÊÔð›Ý^þ%GòeIä—ïÃqˆÄ»\®6­ËÖýŽ7ˆ+ßP Î#vDѯƒ¸i~<¢Ìõ³…¼€ Ki~^¼R¾Öî¹Ã ;•k!²K&rΉA'ާû­Wó½Ì&`3ÇŠ-êÞägÿ‚$Êgî™_~¾…ÅÊ7žÛt±yf -ÂeÐð Ñhµ9Ç¿Ýa1¿Ñl*ÜûÀ0à@ÇN‰ òª{G8èͦþ£‹d˜} ¤<±‘dÓoö›Õv­ ÍùÓt<?ŒãŽþŸOf²QMYRXh TQÒá [ §-á ªœfR­KµøÌj¯ÛözÃþàú¢w1èô»­N»Þlˆ#¬1ߨÇ"æŠG2xÜÀäÃ-æÊ—ÙùËïü 0=J c‘Wõ›|–»Z“!Y–%säKa¨±k:ü„t³åÝN}¢æøîarÿðøŽÆóñlá“>²%måDIôUyB›Í’‚3”ø0¿Í}&[ÍÇ TjÍZ½Õ¨·êõNSXmkܪWšµR£ZªWÏkBÞ=xª–Ÿª•§Jõ©R9TJ2æ|—"[¢W-ƒj Ú(}ЮšÞÈGŸÊØ£›Ãvµ[Í4æ-'Óñ§„Ü}¼»åÉéçûÏòg“¹^¶»,kÍ!,Õ¶£é†fZ²œX»´°¦JÝ)ìÃd—¤ÑÀèƒz BŽ£k% ä$äQ£Ÿ†oYÚ<¨ÉüζZ‚-cŽM‡¬ qoÒÊܵÿ?ü"pÛçMi%Slýb»:¤õØÀ¯A1ÛTÐίB+iøc)"M™{ å'7Ä+50míTV ˜9kJ^®01ÇBò=ÓBJ~ÞNî(0/åUxy÷XÞ?<üc–õ Ž2òÏŠä¾._€£Er®x^·ý^ ûg/d4øºôÆÝ×RçÞ°6~¾ y‚”KV„F^]Ë£¥Ÿ‚ãUøúÝŸH¬k(«œ HK! Á£q"ÔPpg¿ Œ¹vÏ#<×j…ì]ôóè¯Kë |)ŠÂãtçƒÈ×Ái‚¦œ²Ìmkßl õw]F^T¿¤¬²‘FÈ2g}<½À³*׫Âó=gî²iíÀ Á\FÉ¡èyÉEfãÈëâ¦ÄÞ——Õ©¸ï,äN“'ô5ÏêOQ‘Lh…‰¼f±~D¥HuÖakªºÕ¬†ÎV|@&ÌóF“Åb¡9S¯× úß}÷íÅŰÛïÔ›µó2OS•q̯T8Þo¹\ïwgwŸGÊa:YÜ~¾“¾Y/ËOMQšJ·[¿¸èöÁE¿ÕiUêõóz¦ôyišO¬—kÍŸ4¯úôÓOwš}Læ³™,úË Jøðáý»÷oûýÞåÕ©eC“¦Šj C¼X«‰÷l:i2v÷àÞþéöîNÓ²Ñt:U]…½~÷Í»ëß¼ûðÍÛ«ëáÍ››^\^·;ÝÕr[®T?}¾ÆÛý^ó£Z½ru}Q­•|"oWl®pÀ[Ùë’9ÖÐÍ|q{ªíÌ{]º#–ócHÍTD%J7‰JuÄÌ“8 ÜN»Žn‹")ArÈ^¡3ÙÉ®Ö3)ü×a/&&:~1 ’;Ú¯â±8|¯C‘°/F:s0‡`h€ò1§E§¤@‘¿Ú7“8:iJÙ<`›ãZ³gVÚ6Óéb6]~þ|÷ø8žL&‹ù¼\.Õëõá°w}}qssõææêòr¨Î%Ù®Vk¨ò B´^Ài`Ô<àÕA#¿¾ËŽ/DÎàE¾IÔS:]‹ÈEU´Âf…(šxkq“€,«ºpÄë‡=óyž‘±ëuÆqE3qÔGªîךúK AŸPMÃ`êå°lm‚e3”¹Ô}…7¢Î}ºjµVmvR&½ËN«Ûê ûÝA·Ö¬6ÛM4”3r þawX-Ù¬&^ÌVÛÍnüèSŠv[µ}éi¾G$TˆnŽjâñ¨°LéÏ 1¬øÔY!«5ªª©*¸X,%-“ñlô8’”C•Ý,V>‡,=7” Š|r¥rÔ‹‚„Œ\H.DznT¯6ª~§Ùiµ:íΠÛéwûWÃF«Á»|&AD”â½®õŠO¾ÎUúh«iÓùj±Ümökwòh7¢©íêŠr…†X~ó›ΪjµF«IÑlŒîzot—¥¬FMUfáÈÏ{© 98º×9ŸØr:®‡Í~>™¬—«Ùx·Bä·^m×+-Y{•’F¤º®UÙÊ¥Zc®Rr÷– ö6WÃAÃÍÑÙãã0ͽOf48_iDK•õ#Hå@Â\âúH?³)çFŽ! dk4yÜ`(ÞÃ1°Ø¼­PWž„úÝß~µÑ¶Úìe¥-k܂ݖ•’¡!¤âšm$+ýzV÷ ¤¦ªªnºæ"‘×7b)ÙsˆÒEU1¦s’ßàX¢Ÿ×®ç%ó,ÌÍÖð¦T.Y@¸½É®2 @?›Ö,åÀD6¾FÊ7¥æ³éLWªY9ív»«iGSãŒ&&±50Å`cþ;g©†)ªHDaY)À™àU+„É.µoÞù0ɨ¦¢2«:ív¯#[ s«ÕhZ¿Jë`-fµã“Õz3Ÿi¶:¦÷ãÉxª©9ïÃîØŸ¡|d±5Zõj½\×4´× {ƒ‹Þ`Øo4j"œ7©X§”mWoµ;•J}©YõRÖ,s$fæX¶r™jÜ&È„=ÑÖ"rHÌÓ¸n Á?"½q„”G‚'+ä¬ió_·5%Åë_)Oÿ,X"~5¦Äø Uü"¼¬È³Ü®Äsß5¢™âß^IƒEÀÍî¯ô2 0ójõÓ™­j:‚”`2Šjh£óâ£8 ¶ñHÆ+@ª_‘sÊ_E‚üUð,ß"À…Ü…ì‡×;¦ÊQÿn§ð%!îrŒhT…®rÓ-óžä!œ¸èìZ¬#½ f«"¶A±áÉ/%xÐ=÷è+-¦~ö…‚,0•ý$¡~!3h÷‚ªÏçÞ¢9¿\šPº Ä&3hƒÆcN"!~]5•c¼&Ÿ’3¥ä +My›õV³Ñjzjo$”ѶúDŽGá\s«L½™šS–.Úµ‡©"JöOýà-¦ÿ+lô•s˜«ÉåVƒ!A±ª²nÛ,ð·øv¢M™5;÷¥–ýº†îFÓ§¡X¥’y¢_b9–BBÕê¤Q‹V,ª5; a»ßvíî°Óv{ÆË~_x5è_ ‡ýë‹ ‡Ã›ËÁÍeïú¢w9l÷»n»Þbò/£P¹e¥Ì쌕×YõµÝ&<;ßk¦¯aÕÏødºñàˆ—™¶«mØmÂó…—!륃‘©ÈMUšÁµNõRå3ÀO¨+ ¾Mp„h~!OÈíà}g†iÑל}Í[½Flù´ÿl>žÎÇÞš™“ÙÈøht¸Y­¦ÑËS„d¸µ¢^'5 #ݸ’©ªˆ8"Á4Áø;3H9dc¶Ð-+ŠS°þ8&¤rÚú9&ÀT€2ðŒgtv€Ï²Ê!qÁ`û#·–8êb>_M±xø:€0ì¶F½ÑëõƒßqoÔ5SRU‘¡"ñªžxg5tìürÑàº/Déö+D\ÇÚcñ&S>]ÊK‰L­R•Úéu»ƒ^Ðc­]6\ì(õ6AóíUΦŸN¦£û»Ñí§»ûûÑdâ/úíÒÌÍFƒÔ]ÞImu›2×.¯..®†—Cs¢}³ÝBÊÓ¡Zo´Ú=Í¿8p{¹’KÝmk…kG´k4U&y;‹‚å©5û_Ç$xN¥ö³(?kuæîæV¬×›ûU€¾ç’öO ŠLx ¾t+gÕ\52ˆÜò¬ä $ÊÖÕmŽÈ»áh9ë úÂŽ Ñgžë­—ì˜Öø#q9³Ñ¦ž¤yP¶âÆ€Æü#SanÙ49<’Dd‚Z$ä(Þ¿ÁïÁI5Q¿IAžm•³ ûÀT9Nž@>åÙN{ ¾}Œ“%y‰Pþ1D=K%I*‚«hžÂðb!¼*OïT‡tƒD;0'R§€ÈM ¼¡_5ÃȉWhªwöKÑŸXärã*çk€¼H„œ#rEaºFÑá@³$ÝKuÐ]ë%(¿9! <¥ÇùG!þñø›ÂЩö7Ôè ´cºØg—ýÁÕ`x=¼¼¾¸zs ¾½¼|wuÞ\¾»¹z}õþæêݵ¼×ïßÞ|óîZ޷׃«‹Î°Ûè´« Õ»_Œ•†‘µóÙ-~è„+ oùþËŠ2Ýüu//¹ÉnÛ?íüž ’€ ä“ü&Ó)o Ê”£âˆ=v›¸’Ðu¦Æ€jðä.ÎMc¨Ä*RÑ 9Ð,5£/ª„º›_ â½Ë<œKé·§³ÉÄ(Çtü8=ŒF÷£Ñ݃p|÷¨ë£ðöa¨‡Gäà‚J—$¨ù]ªaê_…8FOÿ)¿SPx`ÄÑ5¿‘‡¼Šù-A\¦9íšÈæ(bwa_i5ꢎ‘ L CeGˆ"°Í3÷Wp¬'ah%”*QR÷8¶(¨÷§ÁE`p¶¸‰Šê‰_~ˆ&‰Èj-P€ ©Ie‹÷RÍ,Õi• ϳ“®DD]*({!H!ÎÌiUŽè·TùG3ÆYY¸¶&;ÅQ™¨ ¾FÊ7¼;]ž“6RÕ»{Q ªTGh:/KYùróƒ&œMŽϋ݈ê(ð+ø"ÊÑKÅÞÁ”]ç%$* òœ'8‰ÞÿQ@Ω 3|Ü¡žµ¯S™«þ/Bá>Óe6±¤®Do°ùS±¼ÃÓ"ÞDv ùð ¸/iË)æ9þ"xÛ§è!ÞIõ ãŽà ÇqK×H^ˆ™âd€ò;É­x[p’À_q‘A%c¬¨`n\3PÊh¨ ¤| ¥ dÇÄ „¢¬Ò¯â=#¬q; ÅI…<+?mA²‚ÁĪמ5Äøü¹t¶¾ó8HÉ<‚p ÙÊg >c<É*³²LÀc L9zÑ‚0¸j’`%†$ƒHº®'õH„;óæ ÜEƒ—×203"©MµTLäÔ€ÕÍ_O¤á1<‡6y\)¤}âÁdd,HÆmCüˆFU7·¸Ák-†5N™ª6Zµôx´%äiiµ€ºUÕ]ÅiÕë@:Íf·Ùê¶êݦ°!l5kÍz¥ÁSé2Ëš,jˆ3-wºP2ÑrðôÓM¢«Ä€‘y ë÷<…D4Ò2³ªÈ éÉ+¾Øn+ÂiÔç@ƒdCºd’ÖdP°ˆà9Ï«hÄõÚ/w3Oò:ýÖ¸Yv/7óUù¿ø¯þjĤ€Œ?÷„faDH³“ˆ£®’f¤_µR½(Š®°ÂÜžeŒpÐOD°­CX ä×ÅáÆ‹Ë™‚–A‡è¦Zö™zÒàVž¦<Z©ä¨Ku_…É“šR²’å/©P;`áˆóËõ”g‹÷óÉl1_jÒi·®o®ß½wy5”¡ã—dˆñŽupNùiPb—îR3´ýh4]¯¶Ÿ>Þ?ÞO43x¸»“–U Í]õJ»]ïv½ï% [ÝN©V=¯V‘ÏݳˆÅz9[ˆ€Åd.k}9_Èmi¾Øhÿ»ïûýîÍÛë‹‹&IaMIæ%c"MM×ëÍx4™Œ¦üøãŸn?=üðwW^çP­5D6Zõž¦SÝo¿{ÿ»ß}£ëõ›«^¿[«WÅ«§'YcÕáôø8;ìÏo?ßO&“Ë%kiÀwïoÊ`Ðnöœ’¨%ÎÙ!fûaIì;¿ihâ|l{#’s°7‡#ý,òIðj¢<ç€ï¯'˜<¿ ¾Túóp¤6A Ž]!æ9< w)9꟫¢±¬ иnYÞO¶‚¥•­%èYv1wÚïKóÅz1FÓñüö󭿢RyR‰Ýv{0à£#——ƒþ ×æ«# ?(•oE%ÓYð§ ¹8kŒŸ‡<‰ÉÑ!)ô$‡tGQ|- ‚2Õó¤àˆœ9¹&Všc@T5‹I¶¹7फVX¹\LÇÓéx6~˜LGœþ0ŸÎ7ë ÊûˆY9ÊQ3O6àf9 Pôº!Иª[œ}\«4ÛÞ WoׯÞ\¶;-Èèµ9”[zFšA4S) Ã9§6Î6+ ûõr·˜¯43œŒÆ¢DßÙ~kíÈ–\˵’‚È+c¢3TÍü&¤ˆc_&Š•%Ê’;Uج’CõžÏ"1‡džr‰*B”‘+ aÒ¦Òfç2„V£×ï˶¸¸¾P¥:ýžªÙEÒ¨J*šÈR¹{Ž(ß°'x6—âcNê_.U»•jD¹jqÖª¨@©*Šày¯â²’W!ö¢Jk7›­VK²ÞiÕ¥Í[ "Ä:_ì&ëdËP 5YE`-J,f Ùj÷·÷‹År<â 2 æ³¹Í[L˰iW#ÌÏyä¦sƒ#³4†ˆ¬±ÎVo4DQ]sø^§ÙnöÕ+5Æ ºƒËA»×ê_ x=¥×ëõ{ŠÐîõÚ½n»Û¶ºíN¯Øíñ¦Å`8à­‹ž,¸V‹íD ¦eÕŠj“ÔÒ,@<±“NÓ6–!ª¨MÖÕdŽdCD&)"u“UO 'è8†Šj;œš1ø¸Îúá…Ô—<³Põ çI¸~Ñ îèÂꊮÞ$$”mÆÚ‰JôR«¯¬ó8‹•¶9 œ6Ñ(?—üûKâ<¤›Ù¡î9MdE¢:O8VŒ…Cyù’ÜÊ„Þu·Uð"Ü $Ùj9Ìܼ•탅6˜—ò '!3 ò¹EÖÇh ãÒ9?%1yî y,nâØ¦pdF5U†V'šÚI¤s¤O‰ÉÓOÒ8߆Àó€|XúUc3°rõÒ]˜ê‚Ä+²SêØy-©«Èž”®ŠJi>ÁûÎÄÓ÷G[ø’ ‘©RÕ\¬¯W¢ÝT‰ôN¢)9ÙÓvsàí–­ßjÙ‚Š(ͯ¢¤+Z‡çMÞ jÖëÎ^XíÁ<f*½B¸ÊÒ 1ÀæíaFäÝÆ<d {"-×päè4K0º™ÃðžÀ1Ú—ñ9däüƒ€!tË̺¯dœ×4¿ _2ÿk˜5 ìüNNâ½C–€.êSš³÷ŠIÈ1ÉtOR_-1Áç9±èX3>4ä‰å¿&ˆFHÈ€mé‚’"3ÏÅH‚t#‹bŒûÉ‘7^”–òy†,α®à&?Ï$‡¢;A±.üzÂýÑE<µªñJAÒŠ”Ð #qÐ n§z ÐFfž´Š¬8Ô[õyRÝôrWêï$bž¦@9ÑFªŠ¯Ño“€-œ×zø—DDdóÐÎ‡î² ?mªÅ–Q4ew¬Œ³Ÿ×Ø"Ô„@8ï6ú#¤T‚wf¥Ák•JM×j¨a·+ž5±$¥ÿÙpBP>= FF½¾ rfzb8é{ÎÛ‰¢d!¸s`xr+ 9ò cN¼è½}wu}}qyÑg¯Ÿ´ê6šÍjMY—b¬…Kçg ÐjÖjU·ŠOðcµ g9ú¤FäHÒ»^n¾ 5S:&[my³5¬{Ræi×< 5tȼt¾#ºíebªJj‡h8{}’õ3oÄÉå˜U~×îðFæ6:ÿa!z„!D.«éKüDÚ<¹ê–Äꀆ;F. umÇ`…M’¥±\}o½ÞΗë¹r¹^J¤¥ñÔ Êg8ëͪ¦ 펴z,  ¿”z­Âi2h1.:£ÀN7„o% R³˜4„5‚ ³´Ò3YKeͪ|ˆFDî;«”°4QD, ;ÐåfE‚ˆyTž9ˆs­dæpðÙ˜êó§¡‚œ­G5Íü5+ E±f 3j Û1ÍÓ ©3÷>ê ¡:F(”`iµý’ñ›!\¹Îç­Â…¸ŒÑ×Ã*eFfnž¼aß…!D/V™ÁdÉEÒÅ9Æèt "ÞklìÖbûùl1›Îç3>‡¼ZZ ®ýÝUéeÖú¼b@,iWÕŽšâ°DœkrÓj²'dIÈžhòÅU$Û¨4êœ]É$X)We j°VeTˆ©<ßuÏ7À^Xú €P%ŒºRrš˜ˆ¥ìâ4o±x¬:™ÿÂD®2æ4ƒ‰­oô#‹‡<+=<ÉYÇU‹™”;Ïà6Kñ„ÑJUá¯yµIM]´\¢–ê¨ê!´!ÍmËçžõN½Ñ­ó¬sÐn;A·Íj+‹jÍn«ÑiÉöª·õv-Ãú; °]÷; ­V¯Ý»è¯†Wo®®ßݼ}÷æúæúòúº1T†vK¬x*ŸoQ/É®Àèá{M¶¬ ,Ë ûu³äÅRv’ññ+ñB¶jE¯´î™æ¸øž†Ú!êo1T º†ã°æ'Œ.æ‘xIÔlÌ…Aã«hÕP¬âx$>,¶\I>ãÃb¢g<›¦óÇÉüœãÙãD኶šùdc$FT=Õ’C-,9®Kˆ#¦ÉÎo ¨H~Ë‘O%²Iƒ2ŒK˜SzŠV„ˆ•'JìÌüˆºó|~ ΂©(RåaÂÐIÎ&AÊ”€"¬,Å[¨)©â©S(¶â¹$_³—ÍöÀÇB˜ÐHGbõ©>µjµY?V ¼Õ¨îØX{»-ë[êD ,$º–_uáQ7ºfã” ü ›2û;;¯Ÿ×Á§Zœ`ø´÷ǵ¶ê¨lÎeÛ£ŒwHÙ©®ÕF¹Ö,7Z¥zKšèì¼z8+‹ê´ä&I—)¿\nç‹Íd<ç“ ‡f-eõ«Vû½´“&œ>:®1¶¯¯mýNW=³Ùª7ÈTýX O<ÁÈ$ËÁ*ŸÐ[b/¹%n)"&ªŒâ.æ&O mŒib•DªLR ˜´|ˆŠ­µŠRxD7;B™0O¼9C#ð4fæMÒK×-x‰C½Y’¯ Uþ‡ 9 ¨=Ác53Ì!˜cÙ˜{‹IÊɆÃ×8†P¨û™sAÀ‘qmŒœDÈtt½g橱‡eèƒâ•«ç’µFKS‚Z“©¸æáÕïžiNéáJºüÈvç|‚¹}™µ—hQ¸;·ÛŽ8vŸ6â1‰­²mU‡B)ª£kMr‘w]ZÜÉcú–c>+4aÏÙ:Y´H\s§ãsW¤2ŒyažÇÒ<šŽ±áI‚‘#F‘”ˆ,UÚÆ•'»BÌ}Fvùɳ•+RUŸ”!#ŽŽîe+1GCÃÓ÷±Fâ„ ¹Õð X$®º Æ,¼„x¢§Q’7ПËã™®|)Ÿé°Øöqô¼çÊ1G2g׌öðc%"­$[®•°D›Õ†ì’v ¶UyÒKÕh„V c­ÅR•(K ‡®WšÁÔ# Ñ4ñ+°ÐR É‚ :mD Ë5K3;Mªe*kgq fºhnFK±þ6<ñ«”¬AzÉ ÂˆŸ™žeå €¥­ÏeΪ8Ìôêy0‡Ã>Ú՚̯n³Ùk [ý¶P¶Z³Ûæ˜ö·iú.¬²ðV'U$ ,sµ%ª¬d·êÍNSÖ[Û/7 /‡i—ÃÞ°ßô!pPÏ*Madºm5Ï÷hƒЖXo>©yù•ØÓ.ØOXos «Õ€Ë« €¢˜¤ uO!“yaHŒÇas%ÝÖáÈÐå**¦‡zÖ{Žó ãk°ë v›M7 ¯Ô‰l²Åjb”cJøzºÜÌÖ›©ÆãÕvîu8>ªëÛdÿÙ$« ÝŸÒ3Ið®ÖŰ Ô5ú_ó]­EirZÝrJ°†m[g8ŽIyÞÁÇ4|7J"‡îÔL‹üÌWCV‚ÝFÒ oQhºa)uU¸ËÇ\R‘,©Ÿ(±÷t¶ ë5Z,* .eÅ2†=J{ÙmëýbÁnÂ5;EvjQEdZÂ#u2•ÊÔÍ‘l…“–‘¹Æž Ÿd™ 9ÓÖ´ìëõb±]¯÷»MŒN® èù~¾ÅF|ÚlÏ·›Òn§@Xuõ³5‡f§°£­V¯tz­Þ°Õ4º}ÍrJ¥ú¡TÃtó÷Ï´Íþi±ÚN§«ÏŸ…wãéX³×µj¨Üµ²º¡úÎåEçbØ:ý~[F[«© Çnž±Î!ÖpBœÔ6 AÝDuXÌ4®×+õF­!”ùJ£›k|Yš‡ŒÍ³§]ŒEº¥ŠÒ0œ-£Mãqœäƒ÷%D<¸ †ŠŠz¹Gô4f0…X^¼žY)Ä"Ä­p‹>K£0‰[x% v).z‚Ó:r.Éö¦ÀÈ!ÉꯥÊñ$ãÉe°ØÓÚÝ þR]Ü9r (} Ð ½À¢¶æÑÏ%Áh¤a¶-:•„6JS3)*…˜„'MÇÀ$ ›[á~xw&ÑÜJÛý“(òÄØŸÎʇrõ©Z;«ÕÏkõ¶*‹ŽöØb4{­̇pÐŘqÁ¦¼úÐçä·úæ^\´£Ån8¢eù弉“®]$Ì1“c~+„ y Ó'z§Z•ÏÔ)øÖcÈ?|ÌÚ]?ÊElÇͷݲ[˜ÝI‡`·É€ÓU£ŸF5Hå£I³Æ~9KuIiCeJ!*ªü”ãYõ¬£xXRÞLÑøÙ¢JÜãÑiô/>(©«”­•…lnt0í‚ÝvÑ"8¤ñdýÛ ™Œ¨š Ë<ӀȦŸÙj.ݺ’ÚóQ#¶Ê!—~ÔéÆ3³rÓe´¢Ô!™õЬ"¤ûLÓƒZ«ÚèÖ»ÃNgØÁé6ª XQÒeÌdCÉŠ9çÛ†(ç°Û8XXÊM_Ìð¤BµUà#Šjl=üÃþn$ûI¹ˆÁœêyɧ£•5gW'‹®ÆD‰,l¡±Ê¤ÄÊ(2Æn“ñ d£-^5Ãb£¿Àg•‹3zè“Ôæèò§:P_µ)(4qR+õR­)£­Öà™f£Ñk ›½v³×iô:6×åF9­q¤ºQ1ú%1KN%¡¬ä’*…õï‚üŠÛø:­v¿Ûô;}öÆ5{ÝJ£Q®×$J1Ë×øÁù%²‹‘[ö8ÂiÕÁ´Bïxü¤w¨fÒ »ýz±Öh§ Ë’S(ÄæÔגЋã4 fšE69kxÖWÁ[³ kNŠŸÁR [r»·@ü4S’éO¦nd­e2b¢eæÚd¹ž,wsY›§åîl½?[íK"I"´áƒWOÛý¹³¥×ÈZñŠ‘ âé”öÊÿ›ÿË¿ölBÕ"® @îÒjØ`‰Ú™vux?¼ŠŒf ÎYXa‚Ç(Ýñ‹n*ƒ&±$d£H%Q”¼‘BB¬Ä$Gwbú«Bœ›òÓŸõ‹ˆá޵U¦ÿ(Ýßôd6n¿¼°Y1âD*‡iƒf‰J!Ér7¦9ê#N!·—%-óR›ÍžmÔ³Õèq{ e¾ÑÏÏ.‡ý~·ßïuºQ¯¤óö/¶²e½ñ,¶ÅœEþõÃÝh1_Ü~˜ŽÇ>ÎcA1^™öABõ†ä¹Óãüìn¯ÖhacVê¬yo÷Ê„íÆ£ÑíçÛÙd*ÛI<tÞófxÑý³ñ]w¨ùP½Ú¨¨ÿl[±IsÍE±ØnG£ÇÙ¿ÿ÷¿ÿüÓÝçŸnG÷#Ùògû}³ž¾Ðp}3|ÿîê›ïnÞ}¸¾ºº ûíNWºW&#]‡Y«ZDFÛù§OŸ7›íç?ƇÃFsïF£ò?ùóïúÝÖ[É»²õ¤çÕï¤ä4n¨á5Ww׳±fÓŒ²Ê²"O¾ÜÈîZvBC „Ï’coæøYTÌWQee÷,š½ÜI€ÛƒòqŒ–0Èó5¼)¡®NŽª„'·ža¤}‘Có^d+$Øòø`¸1»#%Ȉc âÍÞgèn˜•™× UuƒÜò9ˆjf3ÒCJ¦l#Y>ü\Ju6ßhþòéóíb¹MÇÒÒ^2×ÃÖõõðò¢§©¸úUM#m‰õF3壼_«~ /Þ=ñÒpÂcrw"T=Ë~_À€á…¶xÀ(Dþ+FŠÖ5©4XMé亇_£0k,WjR·ÚóÞÒ|5yœÎ§‹Ùh¦é>«kÍ0Éò°’¼RåP› öNO;Ï5¾Šå<íjVÛ½vÿjPoÕ†œÔ”ºk¶ZLa Fš•ÕA†OA;µ9}\ùÉÖXñ ƒÝøq´[±¡çi³c f:éq7U‚w°Ä×OèaìðĪ›4êÂÛƒøéNƒ´rÓ8‡nÑÅð¢Ê, `PWÍ͆— «5¿À(T üúÞEïÝ·ï[ƒöðúBWÆ&sñªZSƒ†’ciž.e>_ó Ö#q2%5ëg¸ÅVYP©òlˆzȆáÌ2úÑ~Ša[½Öà½Ëf­Ž4n¿Í V£"¯ÜÅ/¡šWÝ)²R¶ëÕV7Øa°Ú/¦‹»Û{qæööNÌa×òŽï7ˆ„Ì+VJ+wˆc+„ˆ†BžØÔBÅc§æZ§Á‡1.úM]¯z­^«;ìw†ýZ[ÖmWï\𺠚=òÚ"ž`4(bjE­‰¬ÈF`ù†3Gå­Öjâ…L%ѲÞlD¯„Z€l³"Oˆàލ"l°]š»J’$ê¸ÝnŸc4 rš×‹xÅoÄ<1ÑPn¶*Ä*1M&Èïf¤XV+uå¡›{ˆø/çnÏÐì=òž!ÌÓ ¾â ©’.¦t: KYl~fÊ#T™ëÝÓf¾=œÉPcs¤æ;rS¹"‚Ê –U¢O›ód¡â¿ 0ßòÿ*ä,¢ˆoï)ÀÇgwŽ)ü–Ù.òá}xn#Íçûº f`áã‘Lj ·ã7U<Æ3™z(AÈ$Ô§™(‰;#æ5[<ùä+Fˆ,zF$ÝÖ´!>U¢¤ûÝv½^ò&ÏXfÕèáîþþóíg JÂÛûÛÛGYo^òš.Ù‚ÀbOR•—ŤÀe¦ù…äX®¬éÆfs`kÚuì/ðùmv,îv’¼j= õü¶¦H2c•‘Y£ g«õj:÷öñl4^L§ËÅBÓ²ÍVb$›Nƒaå¼Õ¨uZõ^§Î›U­J«Qa“¨ºl3ãx&ÀK` š @îW”Àø#NYsÃ2Ïa§-éT 4w‰ì쨾ËxâžÛ ¢"Nr_1´ýrÌr=æð¼Œóoîί'Þ|8¡áëPŒœã‰÷_ÂËÀ<²äP[?†õ¤]5ŽKA!ýŠ';ï|Ÿ×êgºÊ®/³Ú–e“02Ì¡è~ ùÝbªpCŠp^ô†ûëÞ¾î-‚ÂÕ0mY<€{êÕЂ/žæ¢$šYI—ð½õ)¨t»ßýá@ù ýFø¯ΛU¥ìdÖ€R¨gõnè$ݹ`¦@åç ³\¿_¼Tp[Õ`0³"¶¡&©À\^¤Ï*ͬ^ú m¤˜A±ªSapE6œìÑòÊ•FµTØ¢“Jç<[ö At ,e è »‚ƒ60¦<šyI!/šÊ‡#x‘92w¢‡%ÊX×vP´¿£RI8–—3zŒòžÔùh'Y´2‘EDB- Ú%RéTºÛ •.O"# £Ù`¯Ã¶Ü™EXíõG¸ÉP£æ{jä²0Ò‚E”¡ÝN/3Rΰö°«e?•®±³°©A¨"‹°Yç³ôŒ Qd+Tƒ®|Ê£Ê4SÕŒë!yk¨Y¼²csœÁðF’[¢:+¬·”¹—zbÃû†Ç£~ )[m½ž­VÓÅZ8_pÇr½[òé*>+·9ÖÅg²$5¥‘˜ò¨O×ðúÍ—üV^–%Õ<€f5‰ZCçh)ˆ…:ÌŠÄO¢œaÊØ¹>ݳ(ò‹0²J¸’¨ê´Ø%§ GX±3‚ “À“Í÷,ͬ“a@0`uPh­^÷†VÛl3'”`®¹ª³ÈÍoëÄäWV®½‘’Nâ~¢Ì§äuZuà35Óv»çc l,ãÀ3Ù¢¥!Y®ñIÉÈjµšÏç··Ÿøá‡¿ýÛ¿ýýïÿWùWù—õ×ýûßÿÍøáïºÿ|/ NVL»å|¶Y­vþڽؓà¨,¶èµ²“¶M W3^žð¾Çñ˜¢Ž Ùr|$”#Û^¿ßîõjuõ³ªªoY©öO¥òt¾zOFŸ?ÝÝ~2+§Ó«ê›íVS:Æ`о¼ê]]õûƒn»Ý”)¨y tµšE$I®,®èˆØ*)±ÌØ+¼¦À?E¨ÅbšWb¤¦ô“‹ƒ{:MäIL³ÑæÇ§å#ÒÓ_ ú-0S,H8+¤+Ë3ÜBlÁÜ+9Œ˜Á^»_C¤HŽH•‡çÞ”<ÃPW'!EïKÌ¡èü*oQ¹èÖ o) )WxÐ4‡# š;Ã/P ¡"ÈÑÈR)…€IËu8e·ÝjóN™M! ufyÖP)E‡¶cŠ ¦—<üÃøøîVrâƒ~PNqÅ€VdD»rð¢Wœ‹Wa£ 8…êdߨ¡JÙ"?*{àx0žé°íšH¬·Ôâùˆ ·Y[È5µ¼´2¤(ç ™•95ø¹w­^ipÊn“ƒˆ5ôÚíaF©K2b ;'_”µ‡l±— + +’ªƒB×H$«d÷TÚŸWÎØ¤Äã` ],+6Zj‰VS­ÐëĦòŠ‚RU¦[ÉB½‚hûIq =\Ø k,ZH/Œé÷¢6ñQv~P VS€î ¦à¤8”–؇4ÎH€6ˆJÞ‚Ÿá õenvÛÕŽ}P<›^Íg²3ihf€žñ|vÎæËùj3_m«l8öÄóª¯L½x0ʧ®d P¶É „›Wȶ˜—ÿ¸! ¶xí¦µt ät$wçh6.±æ™¢XDqO@®Xç—Ô„¯ÏÀÅ t+Ðàò(R¥‚ yäVˆ|„,³—@F€œJÄr‰L0ô˜ìH Ôv²Ÿ4¼ð¹7Ÿ‘­—ɧq%R+d¡æSÃy±m4z|´uÆ—'^G`ÂZÒ$™Sƒ„"c+•l¯dI~Ã0³Ùr<™*2âܗ鄃yfÓÉ|1ûýV&Ô¨TNìAè”ʵR©zxò+ ûs Àv{‰öøÈ÷¬îÆ2àxCBý\}›•¶’ ´n—/Y]^öe´éÚë©Õ¥˜E—Wôám´š¤Þ¢…Й ‡`»ú-‹Þixá–7t‚ÄZñT¨lAUINBEseЊ+ÜG/C£š¢YÂó¬¾î•#s•Ý o~Kà»ß§TÿçhÈR'o‚b´tË®bÔgw¿àÍ!9¹{‚O¦@x Ç×1£êÓÝœ RŒRá1Nâž¹­n2uó¦œ-ï8󆵫nª+I|$22Ø[™õnç‰eã¬rˆð<¤è¼ôDxñî«ÞÜñ³Þ€¢7w¿Š{€½ÀH+-Á׬ßé ·”1˜kÈa¸â]„ÃN]\#D á,Ü(¥[Â]‰ì^ŠŒHÑKñ†Æ•£vQ×öglN×jRž‘ˆKÌ‘œ,t'JÚ©}%”œƒì CáÆ,4¢X’²g|òÅ &ü°"9™(Ó#„‚—>"’(q•°V£ÅWäe4Hƒòýå˜oF|œr7„‡ÝeØ‹ˆ/›u™Óàh¦#¹\uªkÍ S–ÆMwUt\±€ ))¿DÈíêÑdˆê8›µ'>œÑ¿å›úšë«¹ÝÊô;C4éÈŒ€ 3¦[® xJÌ1òþÎ5ÉéJ§”ƒ)y0¶êc’™™BdäC¯N&ʈx2Ï%£”æ‘"Æ»4‚×Ê.©.ë­ÙiÉ@äòަn5¾¬Å¶%ø™ØkG@ÑQ@¢+Ð÷™Í,1( >…Zz€Ìd3$–À“Ä™ÈÏq¼Ö‡å/£È$Ïå†w™eºÍ–~ýs¶œò&/Lý‚b3Z©bša²2é-”N·5RJ"lcM+›!Ͷ-ÌHmÉÕB‚wá0Æê1‹œv€é–8k‡ïæ!ÊÄFšÅÌH„åÕ: OØàn 3ÑœÃͲ“‹‹Ò€Û\rÛZ‡Œ€ˆ‰þ!ÏA÷D_Ÿk¤ ŠíÅGS™›*ŒGs áݦYWhyÙSCÍá°ñ^ï­Jûiš£æšLÆãÇ)' a®ÉSÿ†3ղƠN—CÞè­z»-•Ñìö:½A¯?ìõû=¹-NèVd5°Ú› §²´îîîe·Ér»xx”é†EH  †,Fõ—º°tV/=5v›òv]Þ­Ï·ëÒzõ4¬&ãÕýíøöóãÝÝèážÀõ†§œâ˜,>)¯Á°{qÙ¿¾¾¸¾¹¸¼y¡å·B¤–>íNm‡ê.nðá7¥T÷Å;?:AµsJ¯z½Û‡&§APþr0d –snçRàž‘ŠÞ$/ùÝháÌ¢MD3©É›ƒåÌÄ»‹(!Uq¶d!¯yO0¿•GûY/T1ГљÇùº7Ü/½_<ΫxRJ€¼EÌ#ã¾õÍÜj£$&0xÅRfó`¦ÂXm›µ—Ÿy§Q¢Ã³+Ûmõ¦ì6:§²2UKEV¥HõÜ›»ÿ¯Ü'ÞÜýª÷$$Ǹ•îÂYƒ¥6>+"µO 7Ltó\ã’F ñwËê Ó}é/À”Òn^«RúNjT¡ÊJÝÊÊ1¤åøPlC£x¬»èªéÍ(ÕKYt}í¤ )6#WU;정ݲ¸nð‚Q{ÝÜA¹É# Îc<âN*“Ä/lV|: ïËw»·U’ÝÆúŽ¢Pe%»u¼s¥b¯¸ÉP,€Ùr· E) LÉrðMGÐ%ÝTŒ”¬ãJw²ˆY·õf€…¦<Ť2A—7 $Zhf‹ +A³qž¦®DJÜ Ía39Ï®wßñJÄÚ²òKr~U¶^Vcרíæ'—Õ§rõPª>•ü’è¹Æ¿Êá¼ò”BÊ /•*SÖ`£óó–A›I˜9LL?µQ¥^®7kÍvSFØnòfû xTêêú¬Û v4l ^ʼn;^k¡©Ânc±MWõŒh/ÅJöoâ“Æp¥…ÃÁoƒ¢‰:_”ŸšÛ^ÅdYÉ6Ú–2Ôb¥-Œ6NÕ’y6´W6,!ð•µYÔ*¬õ6’`·á–ÊŠF¡˜G¶ðŸ!2RC°¢I 8škxŽáä÷ãÞsð}ëXyR¢¼¯‡¦ä¬õ]Ü&/@š‹ˆ`zËÝ~»Þ/;›hËÇÇÅãý|ô¸OV÷óþþîÇî>þx÷éÇ»»Ï“±mÉü›1²ªyf·ß‘Ñvq9е?ìJ¥•6ÖË$=¨dÝ… <—+ðr뵤Xâ¬;œUögeðÉxVâèž'!vÛwIÝÙÇ€VØâŒ!5.KŽM”M!±q¯1Vr©ŠËV«ú› ²Ià1ÖI<›ÏÇ6ÎDfœWƒ Çâ˜g0˜´rQod]ä@#ÀäÇùëß2`V3#Š“Õ°ÏæþŒ•Ì5,¶¹‚ÜÝ ‹‰/…E¶G…±0J˜?TíF’  ™U±šÑijŠCü2½âG4C’ÊÒ„Ï!îc¦E4!Ö´ ÝÝÅ™Ÿ‘Ó’Æ)ü°’;¦s_ù'b EîH•ð%(8vFL ©s Ä4‹®n7´óv̘D0ùB&ûß¡./YM.Ú«­˜K ×Rɬ_­–ÓÙd¬?Î2ØζõzEæ×p8¸¾¾¾yóæÃ7ï¿ýþ›o¿ýæ›o>¤ÿo¾‘ ÷Ý÷ß~~«€oÞÞ\]_É~êöÚfMhû´ž¯f“Éd4=Ä3ÎÉÄVÛŠ×#$l¹Û¯×ûÕr7›®§“õd´”õ6‘c²~­~úáNøñ§ûOŸîîî9:n2—*ú5¯kµ½^k8ì /{Ë^¯ß‘ÝÆµº‹j½þž†I'²ü-‹k‰©BÔîE³6C¡Eú/w=¢!c„üePpZECÖ…LŒ ÇïjÉhÈ)qöV¿Öó ŽPôôk‚g ‰ÚMΊœWRW¥t€ œ NeÑCÿK1©h MJHã[©d¹uZ^‡OjvXØ•2”)ÊøÑérž‹¯ Ÿls›ì^+Eúž¢äI#Å×Àl€+„¤na«A&œL?n¤TÃ@ub½-“âÀKˆ¶Â½ Ã‹úb†g®GBs|JmÄzSw•¢2ž6½ðl'ƒÌÖØá¬*NøtVb®90ŠV.ž„Þ×5ðkh”‘¨`0ÂQz*×K!jºV2nª´rH|uíÀ×É7¤:0+Á8 Û-AìöÇnÁP!Çã_*L}Šñ6–+ëÍbÍáº3Þ]Îë8¾Þ/©œ ýêô<‹¨;‚Í&Íû,o% °6õ8aêË¡på&bZKà”.¸¥îÕ­`„œ‚÷äîso@îýY|§¤N“yMÉ yEï³´/¼Ô¿oo…Cì GŽ9œ„$·9“C1ÂKÈ•(H” 0eE„° H{>Hú´Ûž§óåzww7z|œ,æËñx,íÄ!‚½ÖÕåàæZRÙ¹›5ÆS쎠’>’ S—§û:Oçý3pR…“4¿Ù+÷Kï—‹îðž@~ N&TÑÀ4,‡­T àžCÍ^ PÌ¥ž8ös¹ž«{ަ‹Ùb|7ZyDÙoüÕsa ìlS*0É[*Qÿ¼×ÏÐËâ}«Ó*UËþ"x»Ûï.‡ÕZµÛëj(ŠWV?ÙàaÎóQcýf;›Î4Þל^´9l4€ÆW¡¾’.jÀ fv´¸Ã´¢@2È’UW«(xê,—­FµYéô»Ã‹ i¹÷ß¾WÕ—ƒN¿í}ñ ^ QÎU\e7”F}MÄQñ«ÕlÉ×¾ùà÷l9Ÿ¯‹íjsØmd@sf[RdÁ” ÚÏô+oÖPÄ7Ìa¹«šæ6ëµVÝ›ñ›½a¿Ýk³»«ÕàpÚŠwùKÈÑc3­&[1=°›Ž¦‡í~tÿ¸œ,·jçé\\ݬPÈtÓÂÀæ«{ ôÜqô§Ì±! ¸!ÙT‹Ç‚\-ÉɹQ¼ØèÇ_DäXÿµÜëXÖeý`«²“á"òd QqžÎ#o”°á¢pÏ4Áà¸K£ÿ(íI£‹n,æóF«ýn»\)“sE#& ˆiàÜéñ ¿®é=¶lWd6µf½Óii^(F©x7¹©4e&‰c¨ãÔ 8ðôÄ›=puÅ … @í>}ϧHÂb6óÓU¬j+-ù=ñÚ*XšÂT̹ZˆMî 1õG«NÑå°(²&—/ÅÁ!“çÂÔ5»äe¶ÍL8:7ªÿ¸•AÜ͘ w0þó»È” XBQC‡rñÀm[Ôø A´@W Œ8Ñø`”âûŠ%dhÓL…›“ˆP'j¼)2…8Rj ¿¬»Ý²@°ó¾®¸³Þn—k5åb¹Zl¶«Ý~£™“ ²Á°%ËíÍÕõÍ•Ì"ö] eÉá½¹ºº¹¼¹¹|ûöúÝû7ï¿yûÍw¾ùö÷ßêúNÞwÞ¼y{­$>£U««K‰ð˜Ö[P1úeÝ{Óãa-kq)³rq?¾»{üôñîãO¬± ?ýx÷ùãÃçÏ2Úf3 K¾‰…º¤’Õ*/{7Û &~Í[f"ÛÚPײK«j©`>?¨ÅÍ9”Ûjµ”W±¤÷øˆi¯§ä2Ù”Ž–d8ñÙCFXl Øq²¶trƒþ#€D5¹Ž²øÇ‹!„4jZ”Ö,NºõÂðŠ÷Y†ÑD™÷ ˜ƒõçëÕýR’€WïâvÑ8݈ÙSæ¶Bµ2Ú›v—Gýúm~Áünõa'å)¬×jÞ ÜÄøg‡¶:&ù#H¨9õK*êRrÉUèOþØð¼REM—oÆíp[Q2H‹û ‹á~vf³)-1x³LRÆ ¥ ¨NhV ÝEÁp !¸úQU%ÖÛ4ÜÕª Ó&%e‚7QL‘¡2±!«È.Ë7n'GÔA©HHvÊäYǰ}Ä×Ù¤ø º*d…»<„•:ß?Šët[²A{=æÆ2ÝØr߬ûÉ‹¤tÊB…#ªhzJùðù0‡´°Ç˜C¡(È!U  ‡âˆw”Ä£ ±¸Z©Uk N1ƒ¿ð-j2\ß ŸJëÙnµçó…Ré¼}â‡€ÒÆ4np/+Ì¿°Ò-dwÌÆm–™^ßp‡Õø­Ìd§Æ!šìg2§“éãtú0YŒ§«Él5¯góÍl±™-·³_X 7ûÕö°ÚmögÛߨËc).ܲВ´Øj‚a&0FjV 8d„ÃD¼Z*ÂÄ*EÂ2†DʳØIÓ ÷É€¡½ìW‹½ë£‚m™° M­ ;{TˆíœÈÅÍJö€Æ^ñ€íÎÛ£³_ŒñØu(T#±ý5L·õO|›sj@—î1Á…’Œ*.øÃ¿Y Öb¼Ñ›8¼ÍjŠå6µÉTó†6Œ¶ùb#‹m½¡:ô2Ö3‹4Ù°;À7b Ô•CKÏŸ*gz¨ WUášì3 ê•F½Úà`†#6JMõÈê@=•+£O€äõ½ünJ“y G·8¥X¬ÝМâc ”¤$_\d";£#w8+g`a| Œj’½û „™™ægô Óg W°Ò÷œŠì'e¦ÉÖý^ –÷F–÷BöËr>ŸÏd¿©ëˆ¤V»Ùï÷elݼ¹–)&Óm0àÝLÖÌ4Yå¤qµ‹wˆ¸]âEônnp¡„Ãë›Ë7oe½½yûîÍ›w7×o®/®e ÃA¿ßk6›LÄü–¶4ŽŒ¿Á`ÐíõÚn½Ùd¾TÚíX®^.×|SkºÜ¬Õb‹ôÞÍçï‘PIÏ+¼fÇ×ÕXÈóD’¹¬H¶¬9s&^H‚5½˜ÏSÍ>¶›•rkÖN»m€ÝVöLÑ-¯D¤Efùx yk±Å ÿi‹‚ RE÷k^Úð·3+ÂË_Ï)úƒ*–IøWð‹rù¤j¤°òÊ@‡ eä<=๠Ÿ-dÊÉ™‚²ÖÔ³ø—jTZMI¤¬ÚÀ‰éƆ#D5º­29*¤’ìõÿ››ìŸ8x-$¹¿ºüŽñôæq¶µmÕ7 ™­)\£W ÑÙ‹Ra/Á\AôCÝ•#Á¹xï­ñ¶Û„h-]dUÄ(’’« KÁÆT÷r µ‰¡h˜;yEœ€ð”m.`Pîˆîꎟa…GæÆÇòc‘ÝÆñì3áSv»}¾mÅ)¯í¦Œ6žCI¢œÞ 9E‰øcJ¼fãI¼´#¶’Û¬Dºf®["°é"Fá°žf2Ê<™lÞdçUæ Mb5ƒc®6- ‡­ö±=TF›—ÜbÕ-æß…ÑïQn€³(ÓTi%Ýû„ùÍz·^næ³å»m:º=Ü=Þ}º½ûx{ûÓçÏ?|üôÃOŸÔõãç?ÝþøY÷FŸeÃMÆÓ‡Ñ nº˜ÈŒ“ ·Ú,ÖÛßM߯·¥žv¶Ûø°lm¡|˜H¬:ùk[4T[‰¤J¸J¾ÀL¡«51¦š«^ª™jÅ„†9M˜n|æ›À)_rsú)ÖçÜ¡xÁ@³ –mÖËÕr.\¬l·yûFèþÀ|4ºOÂg²@Ö1è…­†"Ä>eEQF[™-nçêllé«Úb«sìx»UG¶p´šÑZˆxdûÞ"«¨­P|B–åÐ]?)wSéN§”P#šp»Ú¾…7+ ùƒyôm3éá°-b "¥õ3œöIÙº¹X©1s¹G±DôPNŠ™Ê=r¦<7FüzƯ‡óë" ŽªÉ¯éð™„è1Ñ À~óz¦œº‹ê(&;¬ÓéôúÝþ ßëõänµ[¼©$í€ÝÉ^ȘC€ñö·ìéf]¤ÍA!2À¤VÚýa×çƒôûƒžrëÈ0ë°Q»ÑhЧ«¼v×hÔY±£ "4eʬòEd5žXÃâqÖÎhNÎä¬8o¿µ '¬\MŠVFÙ¨²M%±žvÀ µ?Öйâ#Y«…<²V%r2Cã@U=Â’õa&³<$Ÿ¡Ð-J†ÌzAÜÍ[Cn»¸Ä-7Yò&—A'L ÷‰÷$fÑ GÜ:IXôþfx™m±ÜŸõæpâ•ûän€?‹¿è1ÉYº’e%çn²B¶v”ƒÝÌ|ÿƒ=£¼OãG 9CÉ”ÎjÕ’f›M—\bJ’DÀ¡œuùäûr”Òà Bû+\NÌTé–Áú6;;aYÏd› y:ÑéÈ)÷0Ú¢‡C=Îók@]¤/ØÆ+½!Ý!GlÏ¢¹+ÊÒÊÝà0 u“QÄmˆÒQBåM¨ˆ<ü"¦ÜÄ÷ø’åéx$Æé(‘q”é7ˆá÷8®äÐv›Ì!GVoñ1¥z›³Á8Œ¯Z#WAx®¹Ú&ƒ39 %¶¥øÀt˨.Õ¦´hS¨ 6'ŠÈÒ´˜a©úˆ33éx£”%pÈRÏÖ+Å ­è¬àƒjj¿ƒ¬œ¥€m´A— Hb§Ê¤1ëICyꂌôÍ’º¤hSe#[–ly,ì%72^o7ËÍr¾ä+·“ÙôQ8?ŒÇ÷£ñÝh| ʤ“{r?™ÞÉP›LùfÀìÑ«n|w¹/–ãùjºÜÈn›¯Yx[ðYo±ÓQ¦Ë„±ßQWÌ ö±ªaüe5¨fØÕØ»fDp0ªe BHáBÚ…†£á”•Úú&bY9C7\bnNá+Vޤ䟭HÛÊØ¹ž®æ])h3 YHäòüa^Ð°Ýæ·J+•d¥ÊtÓ®I«Æz¾!ÑÖÁfùßý_ÿsWdEq±¨=­€ÑÌ-~Ù­«‡ûp;a˜wØYŽ+ŠRªrL… 9.H ?[`S€#ç9¤°HHqbÀRŒ=úÙ8ÃcÃÌ?¦u ~}Ç™§”«â q¤h/î»åT•Ú›s†Þf<ö·+4‹¸»ŸN8“c¿ÝœíÏK±¡R9—M¬9ÜåõÅ›·7×o¯¿ûî»ËË¡ì-™VÒª—§;J°úË'kDò é½a›Êî’ä5sYfR-´ÔªCí·Þ¨ñÚíÎpxñý÷ßøðáýûwoÞ¾¹¼º”UƒÏIädeÛêà‘E(ÓO.Y€XZ¼¦ÙJ•|²ŽÆ¤bÉãz[mO"VÀ:1žLƳÙ|þùóíçÏŸ'“él2ј{u}9ôßÜ\ÿùŸÿ™Ÿ9°/ºMðZ©ÍØà­šSWã\Yló-Tv4€ÛH˜_üc—þ“7…™¸ì¾C…Έ'Þ€ˆ™Ã«Þ/åóu(æs'ùcÊý³Þb¯àÕlDæ_‡!c=×Ô£õ{ìôö2°à¥õz?Jƶ?}ü<-FÓÙÌÃÎVR))¾¾ºxsò`®ZC¹ 1–„G2"—òÏ T¥@ØKá'È¢Ybé1,×Õíú0Cæt1OG£ùl>~óᣠ_ÔaaÎa‘Ìœ¤…À…JR©d-ûµ>6„]^«õÚÍÛ›^¿×êtºýn¹Æ¼S‘ƒ”DP¢(šAS *Ðìv:™éúx÷À^þ%Ÿ–—†=ÃȈ:€1U¹r&—Ü!-$E%DDÊÀ¡,¤Ý˜âÖÚ½VµY½¸¾h÷Úëu£Õ ,ÙúÍþt¦ŽJ,v*ë‰ö2~7Ta1ŸÏ§³éxÆ×g~ÛCö÷ÔkP²F3‘Ní¾9Ðëp • ^b²Ç\,`Íó»|?ªÕi/‡¬ö:õf½Â*SÕ¡ls`fYç{öÈ?mùй”õúáóÝn¹Þ7³%Ÿ_œ¯”B{t¢©‘…¹eNúz¤VÿÑj– þÊ>TìuÎ ßòg>ïNš $k¼¢1ŸM4* ¦“ñx6žÚ£‹¼Š6÷ 3™}й˜Ëþã”Z^ì˜-V3N³Ò˜ÃáÊßeß,×ÓÑXWÝ•¤éÝf¶q |ñQŸc,Í’"óÅ¡¡Óó>º ¨5›M¾º-éÅlÕè†äÃ⨷›Ÿgbµl5õ©ÙXh=yó9„ÙL´í!uyØÊJÆÖd>*^»mMi3It.u]yè­VgמˆQÓ‹‰Öj5Ž¥¶Úµ~£Óï¶{ݶ£×nu»’u: ‰³Žz)OËRò»@º%&Û•;"J6oš–J¨»ò)µ¯Y& RBÓ.g}Á}Îg^ ! œ 󿀑#~ŸAʈ³üRa¶h´ðÅlð+òN—Ö«Ñœê™,c söýòMN4/ðƒKöz=Nßæ+QLNÅ #fÙë_í|…µrè9W,¦ÉXkTëM¿sß¨ËøkÔ: ”¥òmòêCs0ì]\ô/.8ÂcàSNg£ÙL“2ÖÞ¦óG.³Åd¾œ,Ø÷6Y¬Y~[²ü¶ØÈôÜ‚rðZƒÓF¶‡ÒþŒã|eø„"àáÔÃc˘Q• ²TÆÇær@µá~V¥°BÕ)è~ýSVÍ1„Üt¶oYÑÔÊçw~*®qoǦu®ƒ’{iSŠ Êëfçþ‚p±‘ùñÀ/òêin£g 6àØÁÇ2Xij\¯V[õª†þv½ÖiÔ[,¶5Ú yËÿîÿÆ9 €„[yFõŒÔŠ]{üÑ­0Û]/ƒèâ¿NG,Ð"×áÇ‘º_„›äX•“ £ Š„QQ²|¹ºêE"{D2®Fè$ŧ p;ñ/¼¾¦<íÍbºHß%¦š,Šgš¬6|ž`2Ó´áñáqÆ)m£³§}­Vj4ØdÖhÖ/.Ãaÿòúêææz ÷Å@áXE Z©ƒ¨¹ÜŒ.ëìLM¯n!—˜ )ðƒ ¼Ê¡pº#W‰ ›ë–‹…ÊÕäf$Ûj6“u×j³Ÿìw¿ûþÝ»7—Ãþ Ç6[fl-^zèw˜½u; ouZWW———C]‡CM2{Äïuýn·Ë·”e¿7huKrf.ÙSˆýӣ̺ùâîþáþáaéÏáK†ÞÞÜ }åùáý{”¤Ì|q«m¯ßÞXZ×,–½å“Ù›™_|Kíšrå^ÿ$WÁë„E· èÍÝ¿Ê{3½¹ûñ½¹û·á/€c,INIòCoŽCêŸa"úW´2@ögêOã‰f?üýÇù\³…©æð’öó§=G3¼»¾º€Ãa­Â÷­èöV… £ddÊùyÓÿÓ¤`~ 8ú!UŽú…Àdµ‘îeÀ¬ÆkÙ6«ÍèqœÖ?Äd’ã‰m8öªÇ6kŸÀÉ8182—‡ ²gp³Ú¼¯íòúRvôÕõU»ÓæEßNc]Žw˜¦TeôÙqÅŽä…w¯·­7ww«»¹÷«õgi툢SS×HŸ®á€Ns»ys(ª@bý£z¨‡,2¤~¼[©µêÝa¯Þ®¯‡Ín³7è .‡µFµÝm£ç|NEG&5ØÊ/ǘ­Áz½åí3NWšÎ„“I¶´±a$‚ww‚dÏäf ÒÉÞtbkˆ× ï Š”3ïFtšƒ Hjtš•zµ\ã«; L Ú×-¤ì4$©­}( ›‘î÷Ëí|<•Ås`‡òF¬‘HÀ„k¨…7+gd‰–È-@¹º{ b–Á ù#aP3vzñhV¦k<‘—p1piˆÒD^­ge¬xÃrÅ•óªü&ƒZ,ØÔ¿”|ÎySfßb/{òm¨+yËÙbÁ‚ñd3çUÖÍbµ[Åù&Œ…!®ìuJ¡Š¸Z«GäÔ@­Z©p(©ì"o[’™Œ¨ëŽF!EŽêÊòð{{{ö==ñHTL^nÆrOGãåtÆfsvx¬6~„ø ƒk‘}Šë!¿·~ò©z^M]Ì'“1_gïOþÕAd/úŠÍ¸Ùl”Z$ÖëU|:^³Ý­·:µV»¦k»[ëtëmYíz¯ß eÉunn†oß\¼{wùáÃÍ7ïod·}øðîÝÛ·×××ÃáU»Ý«TÛ»Ce±zÖ÷÷óÇLù*ÅñB†D]S¨ù\ó¦…†\ 5»'9û­ÝëIÖZ¨<æ/Q_ñÒ;Øl¢Ékvºq„¬k˘ãÇ6±žfL’;‹úì ÷+Þ,¡)é³|Eo¸¿îÍá+Þpçø+B+¤,~5œÐ™»£Så]«ŽwY_¥h´y4©Ú]~ì¶õnг[fËgI·¥ó¯#Hœ8SS’rê=lÆÒÕE’“0·¹‚¼)º¿Ä›Ã/÷†ûg½EÌ¡èÍï>ÃüÌŸê rUææ5oäeeˆõΰÓv¯‚pÑÈ”$!5Š“ ¢$çÁ”ÖÉ0Ì4)†8¬î°Ûä'rjé ,2sûï%(zDQJ$Ï;=ÙÙÊÁ94³n1Î:zŒ„Ü(LüYÕ¨Ö8w.Î\Õ ØîÆû[|ñ!T¾2Ð%P€AšƒrKÊ#,$Æ{ý°,ãmmrì –L¥²dÎ!Ø/ˆ2Á£MIW “,’É¿8¯T¤Qû`R¨*™ywŽÉ!ÅFo“Ñ=)Eä&<ƒ¸k›&ñ³•¨=àØFEÔ‡'K,ñC1ñÀë aWÌÞç©ñ‰ÝÓ~{Ø®÷›Õn³Ü®ù®Àz5[-§«åd±/£Å|4§³‡±ÌµéÃxr?šÜsUÈr4[N曹L·Ín½eˆ5È,pþ¼¦K‚xxl† ­ÔÁW Q/ CÿêßÜTxŠD…•Fì倯]!kùJ‹WÚ$pnm¸)‰8€$QÄp$V5hbO$ªÒwu¿Óâ°Ê†®Ff«i4nc½u›n“—˜oÔÊÿûÿûÿŠþ)Á ÙÊ„Y‹™U~*‡¸ï礔,ôÓ̈îAZÑÀ‰?DR \qKEKá’çÉ»±PqÈÜ¥BÐò”¾¬Jd(„$"Q È_~Q£”rDt% +ò#˜ùŽß(pð &Óná£>>~ü|ûùþáþñîî^]W\k·²œ†ƒÞ»÷o>|óáÏÿü»ï¾ûöÍÛëþ ×hÖy¯|è™$#…Rrv.(V”ccçíçÛÑèq6›.sYi¢G†¾ì¤édÊåïdìKâ.//>|óþý7ï¾ùæýpØk¶dCòá_¶Ä5ÃÍaE~Aµ5è÷YVmžr°ÜàúêBæš ßïóÆk«-=w^ªm7‡år3™ÌeI˜{]àײýR€¯$DæÿàsçWB‘ø—9 ñ°E×çŸîIåá 3k€µU¦Í‡³ñd~{{¯ùÀßýíßÏ4/˜ÍÖ›U¥\ê÷ÚÃA÷ûoß]^ö»RaZôšÚÚ•Zù >7Oë÷u¶á$æ¯ò~žÅ4…áÎCN¼¹7S¶ Teu;É5+u+O°@úMÁHx µ\=Þ?N§3ïQ3ÍÅl¡±]1‰Lbŵª–/‚ÔW•[m¼ËŠ7•*œÁÀsRÖ¥êÍúûïªõêåõ¥&¥•F½Ò¨F›8G(£ëºýg”.GŒ›íVäÉ”?Ž8d¹Ü­V²â5fªuµñH|êå–¥@éSÊ`ûÈ~Ï-ésÂ%i3†F*Òh5E“'PV·}q}Ñh×ß}ónp1ì{Ý~G5ŠKÄí°Z¨ÕÞǘñœt¹]Î9ÉlüÈv™Åt®Ù¶© °š•š¡Gå3x 4‚j S>ª¢2{E!z™gæ¼è”\/s’Ü 'k’‡Ñj­U?¯–1_¥HɈ ê_U5qçÞCtÆAë3Þü¼}8¬v³ÇÉz¾ä;ñó\öœkœÐ)iþÌФU?ÂL-k?ÁIiüèp¬ð¯G1Ýbˆ6çÙß²t~@ÝÎÎ}£Bw1Šx|/dáj»Žmþ¼ß Ae«œ$–‡¡<']pdÕ|6žÎyp6Ï8q#_a­ÙËÑ´  ²rö Àr`´Ä6q¤ÂšŒ›UœÇvoÔ90ËV{¹*¥¼”'2i*ɪXÇó-U¾´ò[´*{tÿ°ßlE$§Ð­7›åRq$‹JJVÅ#D V‹6ød~ºùT*‡ZíLØl”…š°$“²…·ê£a0÷›²ï8à´^-7ÎÎjû]e³>[.4U:Ûn˜ñ~¾’Ïor(rkÌ ;ºìÏØaƒH1¹<“X`£ ·2’>ëcSï%zdü"ä¹xœÎâþ4&{Ày¡¯"ó.öúß© ‘¦áÍâYVqäi¢^(Ô4¥û%ÀôÖ—§ìÍàµ|Ið+Kä)R:äDH¿,‘9…qO祈ûVâ&,6¯Ãk¾«1OCV†O;ðl÷䯂‡Íþl³ZíËía¹Ù-6ûåöi½îuÄœŽŒS–aj]\ºJ@]tx¿)ñ)ÄøÌ« kŒUs6d \¢¼gÙ¹¹h´Âc—ùœ·ñ Çœp`XeåµT㔥ÚùyíŒï¼jT ¾*É¿ûoÿ—ÒŽJ®¼èã²Do‰GŸKiÁœ%*¡ê7I1„¡!È\nnEH]·ó G!y¸#¹úÊòe”!oÜ G–6bRfŠDKF/ )¥“ôà<a+‰µî´ÐŒÁ퉌òòö­ôg±\=Ü?ŽÇÓ?=><òúó|.ÖÈXö»oÞ\½ÿæÝû7oÞ\¿¹¹m™Bš°²ÜÍT@¥C7²"Xeß pm¶»ûûÇûû‡»»»¿ý{+øüy:Êh3lÃF ¾ç;Ž#ÍHÔ‘5—»ºÞÜ\ñ&ée¯Ñªó¥>¢ÉS ÖàeS²ÿ$j™<‹‚Ò™&Ò¦Íìþ¨”%#UVýŸªÛí“ÇX›­ZýpØÁÇ'ÞŸˆ¬Éì¯þú¯>~ú<ÅÍl¾ýöUùÇ÷ƒþ@†kM3EN×eê+iø¨î [Äb€#Úoü¹©‹ÎÁ¤2ExOnýf(ˆâKÐ-høcC¨˜ßBµäVׯÒ| ¿*²†HÎWàä–›Ž"]ÁbBš¥ÇH£JÅÏ5Ï^ïÇŸ>Ý.çë~øQ~M$™ê7—½á óáýu¿/™b¹Dô$‰` (ăYÑüøgT™î“”µ+K¨=:E¾}§¿Õz=ŸÎ³ùO?ütwÿøø u{/Pt$F_Â5ÍÀä•¢ôÎ!|eÅ[œÖ\TãD³Í†›V§ùþ›÷šñ_Ü\5Ú­²:yMsV¨Ê)Ds¦†&XHÿç/x 6ëh“FÝ?nV«Íb¹å»“¬Å)5ª—ÜRs–D 6èíÈM)†îJ1¡ïä $£—nñx”çP"»Ñh4;Íz‡ƒÞ¾Ûîw®ß^·{f»QkT%D'ùÀMô&,âEŠx°Þ.fKÉêbºœŽ§ãDZ¸:c)hΫèg?í¤`Ë?jŸ™K6O291GwD&:×¶oE¶cù¬ÆòOµ7ô§t8ä¢R«TµóŠòCÆŸX·¢½Ä\æë¢‹SÕà{v÷ç‹éêöÓív±ZŒ§Þ&¯©=³zš’D>‰‡èPÑZái2$›t?¯™‹EÞÿg©¡eenQgQÇjÖ‡˜PZ.5¦i€eäbL‘3bÙ#¯3Ž'¼JæÍsù8+$ÛCc w E‘I "ßu€ýiQ¥@‰¢ÊgyNLäøY®Vkº8Üj·«¼­ÂîFrb¹Í {Þ¶’ÆÃz±Ù­v³Él6ž®«Ñݽš{1ñu^ÁX‹r¯Õªß(ýZÏé*¢B,¥2WË2v¥Ôh6kµjS®Ó‘xvûÝ:_WêuzÝV‡…7¢õfM]Œ\oz«èìƒGQ^D‰kl Ñm‚ÝQ¿,C·Ô&ש‹'Ó P(ÎUƒév'<e¯äQÄ‹»&£<÷80 )w Þ9¨²ªˆÂŽãž„’9ªÛ]ajI: H“î÷Ðä…áj|Ù3ŽÔ¨ù ùXEÔ£áP¶B?”€c%¢(„¥øÍŠc8øìÂåb©‰ë&}·—C7Ökvƒ*2UŸªú;(eÖü$Æ#ÇÓmW2ÊW@uÀ@%a^M§U-”'ÈÔjJµQ.ˬ=UUÑíö QVÛšeê­ßZÊ\Û¬yÞ!Ö©‘FeA¥%®‰¹I†ÂhùI ¸á ¼¥ÿ$“( w.¾§·ÜQä ˜ßÊð¥÷‚EQ„"Ø9‘wÜŠ„=÷ï†[Pô~=á‰w¦x"(ûMŽÜ{„[fâG†¨è(ÌZÚúDø£2Á(=±ß™<«h8pŸ‘ÐæDF>™ y„ûXtŸx^º_ )º¿î (zs÷¯õFHKL¦ˆ„û^€c S¤Ávìjã|( ù0ÙxeôfÝ¡tH( c¨q§á׿AHQþŒ7Þ2Ï•>é4l‰*܃ ‘X„#‘ŽiHaJm«‹LlË` ÆÀ„‰oT†XoÈPJL2ž:)z*]åª.l¯’eb„p?»:?ÓÕæG¹&ÅÆÉJ­ãWòÉÀÃc!*7*CÖ–Rì 6,@@qC•Á 0n“‡ÉŒpƒ})V€ê#€1>WðÒ€%¶`ñÏ8Â;rú²H $®OB26Ò“RH61èñ£>_±<0åÅ_DHĉÒì\C[Tÿh/feäÍGi„5õJML^Î.-˜„Ò¶ ½ÌfnËz†Ûæt>’ÇFÑ¡„þ8‚wŽ«D¢!<ŽÅ ª*£&†Ö¨Ý£¡s´ ˆB(#70yà0ªÙÉ‹!ðÁk¼ÁcÈ|ÔŠtl•ý£<â‡í6G}pÊâl¦Î¤Ê¶[ÍÁ 1pŠoMuÁn3³žšFerˆ@Ñ š<¿Rf¼ø*¼ˆ&o1¤è}yë RY…ðk¡H|ÑPôÆ]B²ö;ÁèZnâç që’e’BxÀ.M±—$¯ŸÀgF˜(¢TX½ZîðA—z“ƒ ¥¾úü”%£E€¹x”Pt NnåÞ“h¯þɲƒ½õŽSP 80+¼}Ô\SÜFê¾¶4\²JEUJéœ0mçÛˆ —õæi½Ì¸ƒGër¥^áðH5I³Yk6|ZiUfœš ‚¼L*ÌHB|µ6HàÚìÌ›0 mº•"±sñog€1)áа†—"¢ê§šgO˜˜ „šO³m¨×æc3ìõîÖZ|¶]U°`iÄ 9µÎ´zàÒ°€¡æu3†^óÒþ#`0î^–K8¤KÑL'Ñ*¸}£F¬Ãowóù|ô8z”ÝöéóÝíýb.3‘Õ,uhÅ—ixã0^á\‰ç²Ðiluª.Ÿ>ð4¡µ‰ÆÄA(Ã4AÖ’¼eûÀÙF¡²,ïË¥=v[­äw襽þÀ_8m•«õÃS9¾O?ãtè…p2™=>>ÞßßOÇcì¶§ƒ$Md ‡ƒË‹¡lÖ¦ä®RV«Ó)¬†“+j² Cèn(êŒKFÜA„ІƢûx—îðæn{S„çáù­“h¯z‹!‚—ÞÌ¡è=¹ûª7‡_â“[‚bHî.Ê…7u-±*Ývѽk Fâ9˜ÖÄ!iñ© vô®Ö¾äEu-u/Eä4ê5M‡<"Äêµ´ÆFX3©s!'/ èÍÝEŒð"üf¯Ü'Þ"ü*ï—!¸H|’D*ù© ;XRÈèd¿çÆR_Rkº£ûp0,¶'3ôœÑÔ¶æZµtfÔLŽ…7÷^]c¥­"ÓGÛßù—õVáu'5LÙ„@£dr˜.ov$„¿nD¸˜)hCÊÀ=CN;ä»j´š[1V1me²ëÓM7+XPbP.”ĺBÞ]"~.г9‘†LRÂ'ú‹@?O..xh†©«r+‚±CtijYºØm| ³Óé º½a¯wÑØê¶ÝV­Õ”éVª×ÎëÕ³Zåɦ›í6/ %Er#KXÓö–X 3R±W¾ë—šð£«QÍ`<®ä©^ ë!Ó&_ ÜbÜÅxÈm+)ƒçn‹ÍvpX <Ÿ]où\·FÁ4Ñ”·»ßÙ(çX›”©Åš0ÌÖ°,…¡³BmÁƒtGÕÅ?h“ѦaT¶2;ã%´ˆ(„rºŠjµƒî Jnãhe–ä`s1õ,Ü-ºé®~"sìaxÎ-Çãn–<’ÄÀwAgú?™žcžJê"FÚtãX’óÀT°;B~ap{ZÁ†…8ÏŽ1é·Zùœ§“L@Ù– ᯱ’¥ ¼£ÂªDù¹ç[#·D³ËQÞÈÇþ qk³âmÒ8²mã³á‡i£Q‘%L˜R |ºKó7fÔÛÕ]½s-,!.¥£¾Ìã`¹c¸Ühá§½^ŠÛzk(¦žR1 ž¡ž—Xö\ý ðsiæžkª+©&РNî)'ejZQ¨ŽÔ–ºÂzóšº?ÃÉJíÎ#"‡_‰±PƒÈr;z Ydh{¡ä ÞDgÁ›»]pFO‚‚z’FÈ Sð¯Ü'Þ_yÚp†²Ð5ždD=‹à®žë¨Ôž…úŠ31‹ð¸ˆ&–̇Vdb”+g¥U“iúÁçÝ*çUu·èä(Te¤8G}X ‘•xÒ ¹WŽÌãüSÅÑYðA”Û/œ!‹…[YïbÝÄXQ:¯HseKkåóCù ,%äÁhIho4'™qìƒÖ£¬4Åð“„3Ñ J[Ä×´ºä )5INæj ÓxœÐá$^ÀŒ<ÓçQ„î>ÒXLôEOx¥™yB*“¤zÎ.UH%â/)©HŒ9#±üƒø‚–#SãsRC¸’oƧ¬E¬—ÜÁS»ÃŒ‰k¤rFblÊæª˜ZÎPþ K¢ b °#¤Ô—KŽr•£ÛYæc¥^©4*ÙßʽëhšÞ¨u4»’»Yk7ÊÍZ¹Y-5«\¡ 8c­¤Á²V9gÈÔ ¡¬þÌ—Ôa>´e2ÆÈêAK¤@vÀ4Ü Ys t-Í®$Ÿ¸ó‡íAcÌë,$ /%é‡h”-Ÿf-nM8¡¿˜õHAÉÁchÏPÐWæ¡Ù¦Tü\ h‹°$"µ„ÃiÂ3Û{~A=Uâ¢Ã@Š‹l$ ÜRÆåÿíÿù_«‰juK@‘ÑtÜ¡“`¤¢ÈRÖŸä"ç¢6A€"ZÄ@1§¸©¶‚ˆàtÈá¾Søþ3PŒ PVjdž!Lñ E5· ŒwÄ ÌE%%B€’›ÝáR¤âä‰ jXQÈW£í«ÕJù‹ÂZ½Öï÷¯./Þ½}óÍ7ß|ÿí‡o¿yóæº×k·ÚXpb¿Ì}&e±rËg ²Úª­UMùÎ7ž?ƾì»ûÇÿáßÿåßü͸ý|w{{§2»^§­™á°×í‰u‹ùr<ßßÝÍ&cûÒ=oÞÞ¼{÷æÝû›«ë‹N·Åv=z¡*ÆbÛd2],×ãñøññqô8ú|{;~x`ë ¯;lQ¢d™hÛýÓvw¶XnG£éxìO2LƵêYUã(OEö².§ãÉt:Y®–šy^\\|øæÃ»÷oÿå¿üŸ]‡šÓª³ç,Ñ1Æ/yõ“B Ç»Ë É¥ð›à—{n»¾è=B"À7…¹&¸Eï1f¢öç È(Êü/ƒ¨TÔëÎ&²Êo¡”òÈþÏz£\¡ä28¦NµÞì¤ý>ß>L&‹û»ÇO?Ý®–ë»»;u¶V£Òë4†Ãîï¾7´ß¼¹l·~-Šé%À£"±¨®¼tƒ¼Åp "²28ñþ„ žz¢@PV‰¸a¶cÆ£j¨å^‡Ùl.7ɇr…^Éæy^¦ò .š&†æ¤T4­î³K·ªh­vSIxL¦¶i·>|û¾\¯6»ÞWÞ‡Š…(5ÍA2ó½Œn¢]Õž£Îf³Ízóxÿ¸–nòÇ=Ù·¿ã4 L¢Â¹9ÇrS®¨9Œ¢SýÄßÁHåi#g¶qZ›¿ 8¼ºñ—7—×½Ë~ÿb ðjCZ:öN&Ui&êB)3ÈVóÆæýzµY̓ф©?Ž'£13mN¯Üi|ñ¢TzeÃ@óE²‹A6[äc c´„`Óív»Þ¬“euú½'µˆ¬©gº-è+"À  »Þzµ?[óMOÍö×·÷‡í~=_îWF|€ðjŽ{L¤U8¥fªÒ4¾ °¶²vwÐ\ /®.®nÞ\½¹¾¾á@×ò_^Ý\®//ù ÐEwÐëÍN‡k»Õv[b;kæ Ÿ7Öð‹juÎCžˆM´¯Ú‘AK䘮àžŽUŽŒY¡P©ì'±H±ÉÄW.þ)1Õ0Ïuñb™WÂ_©Õ؇Ѩ÷:]^hð±3õŠ0ùBø$¨jqj‹É|»ÚNùFþz¹?<ª¹Åíø` EÌMV~nÊ6”!lj7Ë‚"6› u±v§ÕëušõÆðb N)ëL69t±eë-2¦öس9  @õ‘–äÆ •¡!!t7(±Fn¢T €[ÜMA„8¤2Ï“ÃÙFL [J™'4¬°É!%L·œ! ¨îCNšE2„W¡,V½ ‘¿swq|2Àu3¶MT«|€„FÞ ŠnHÓ9:d8µ€«¹÷ ˆ~¹ßIüHƒZú¥z p”•«Êv¥ÒkD®Å¡oÈ(3€<ƒU^âˆmn[¾mpH^@éÈP´æ>E×`º}:ßžïç»§ó8 Tsy¯€å‡ÃÁCµR’:‡ª®>!p—€W>q’JâáW 0s¶)åÊ”#·²H¤q„bä_ëõ¦Î4™O·rÂä²=yÑ$8É6Üá-¢à$ä‚9äÞüVx/½9µ¨uç¤e Ä ˆ)&{h˜ƒä4 ”y§[r Y–$Y%‘•gÚ±áñv‰”ë´Ê‚8Q: 6è¡[­îýað¬R¯yÿ11¯M8R¸5fÇ8æ€FpŸµjÖX5x‰¥&™xU¹W\½þQ-óø@¶‹ÐÏIVàb£ë"Œ‘âµÆH/([™ä(€¾iE%z²¦I~(}Š‹ u7HwÙÒÀy§M9¤¬-G‚B¶¾“¨8dÁ‹‹9àIF¿Š:œ³ ={"LQEt YéBŽqØÁiÆSqÈ»‹ô°u *'ûŸƒ \uóÀbÍ…¾©¶yYY‚äu€.¦?±+5†c ˆ“¡Ý„A à«ïYU>‰K–"©xN¦8¯–Žè#*Îë¥óú¹¯e¼] l|ðDÈJ›„ÍÏßÃadÅ÷P9ß—½ÃZb–BfáÂ]é|{~îÔX¥3"£ H„/äÀð¦v0S*Æ@šÀfÞüNÆ~'ÁÒÉ“7v†ÂSd@eD¬`VâšÐ„DW^ROɼU){jV¾¢¤‚(Ë$2c€8•h_ò·êcE±Ì‡½Ïçûßük¸X£2=”0Õ@? V&TSÿ®JÖ¦Y‘\òª”¨x. žiCLô3Õt…m0Dn7«z­Öí´ß½{sóææârØî¶D—Z v©ósq|×p÷Ÿoïf“åíçûOŸn9àa4O5‘‰ÆF½®*ªéÄÂýþLSˆÕf?_¬ÇÓÅÃÃøq4FóɈ—Ryyh»Û®WËùlÎGæ˜ÙÖ*×o®ß¿wy9|ÿîmMó/¶©Ê®*½r@Ú%c>!°ÅRMSÄ,FÅ3bf°8yj‹ÈŠGoî|Á›P)¹ç2Šø|'ƒt«H;f^]ñ:!--‚£ûfPŒY„¢÷ýçªrH;‘è—c¤ŽŸçÞÈŠs)/ÜîÑF‡ MXVV†’¥ 7âøy¦jYõêÝþi±\k~òñÓÝt²x|˜ÜÝ>lÖÉ™xØm×{ýöŰóÝ7o;ú ß©IõC:e“? ÆÞT€ÀjòžIXr‡WÑs‰Š¤ÑšIhM;N¼ÿ¸µ.¹©%ud$"P"gÝ'Tï1©ÑŠ«bÔf½+•Y6«rÜû9Ú¼ÄÔi¶›õ&§56uêÕJ=Uš$²2Á§ØzS«×JÕR£Õ”ñÇæt5O³yóöZ£l³U×pn‚r0Q‰füÑûÕ0j ¼aø U6ÎÖ+Žæœñùr3_Jµ¶^d¼@õ’9º ®ÈS9Q)¼¨R Ṇµpê.ô—D³ê"T½ê|5¨1¼¶º®ÑöšªE»á‡R<>ˆ> ÷ „“;…úàŽÛÖ“Ò峪“ñôáîqôðÈ3‡Él³Úì¤4‘nè]¶–Ë#bæ¯MLÔ*j&Ú¢ùpPS]Õ ·Ùhê&2 .1b“YÈ©ùA¦Im¹q]‚å_œa‰ 8“¼pÉ"¡!¼q‡h‘Ä©T@g‘e yuÂOSôHgBp@òFJaÊýDäbÊ \ß|‰p•p! åÈÃsvŒÖÊõf­Õª÷z]Þ¼\]]È^ûS±^q¼êfÍ5$Ö ¨˜h‚v©q®ˆ_¬[OÆ“ñx²P÷S—ÛŸñ*OWyZ­v­ÚPùbÅjµ]¯92f¿Ó ¹¬~`hÔÔ¼@œ3Ï4Nžóöôöi1_ϧ«ÇÇéííèîn|?yx˜Ì§ ™ŒÒG&0c"Ï*69îüæ©ýª«$v½X,g³¹t®èTrÕR2ǧ¥Ee³éOjH¨”%SŠ˜¹D­¿ˆ.×¢÷0‹àîùƒ/Êz†¿^ŸFø‰WP ù%ø’^z_BçN¨öËE7i úuÇJ’àöÞËö×Xçï‚øER¿ð£«êAœ¦$•® @5é•[NRú‘T8\Í——küµPLøjàŸ©iÖ ¢îIƒçË×¼Š]Ò?ê‡b ¬.é^3ôše/®yP8ùryÑ»t¼Á¼ÝïÈ”ñ‹ÍJ³^iÖ@Nf¯–5EMC)¶EÉoˆhÜ~K¤ J`!¨²#Ã$ö ˆ¬Q#uËXðI@ÚÕhÉÈÆE´12®…'ÓÇÂ|Û*….3Nî\[Úø÷‚6†XAX£ ã8¯‘nx0^–"æ«Ñ¨/3@&C¯D„†„ç£K‚ð8²ãGtyl €Š4úe•ÌÜ9à…|Úß$(;tkÞLJ¢^ú‰ñ=ãûŽrgsSëê¶}eñó­mIK»ß•×t»—½îEŸçÎWƒþÕpp=\ —®WƒÞU¯¥»ŠÓ럴²ùš½V#Ð"Ç96É5+íF¥]Ë·Ê••³zù©&,ªç{aåìàU:¶Ç±ë?mü÷â•0Ø•-Š1ü¨¢Ñ" Ih«¬²šþèŽC‚{^á FË&áñ—÷‡¯ÙëägU~,–½¢ f¾˜t€”ÌÅ­`Oÿ¬Ú€ZŸÆ[oªÚ6¼SäiÌAÈþséžTUð倇³ò¿ýoþ 2žÛ9²[Xÿ® -¦†‰RðêG I—‘ ÕÀ1ãšÅ§6æAÔQ.º>Ê •[‘‘I¤ ($Tà¬EÎÁyP$ÙÚ)⼤^Ο¨ ±ÂK=J¢|§ö‘W@\G:`J̤/Wñ}Š/WÙr’f;çMg3tŠì§ždA溅ґ`±³õIý^Í¿X¬¦“…Ư¿ý»VËõ|²lh ¬ù‹ôíÍÍÛv»­LÔ.‹Ñãx.‹i±PN½^g8èßÜ\ /ûívSjZÝLR¢˜ž—wû³µJØ>~\-w÷÷£ÑÃx³Úý¯kÂÑi«ÊÒ2¢[RµÓlx³›ËŽœ-îG‚ñh4›NÊg»Ã~Ãs¿L%™U9½^O¦åï{Ðð [Vª'Ø*ˆ‘¦&q[‚ÛxÅ”ÜÉpHvMüÏBON è|Ýû@…ŠAusM)ì=¦F í ‚r¯Ý'ÞWòICT*ò (Þœx+¨…B u“ãÔ‰Gm9D×4!îÚBMÚ?|xS¯—Ú¼"]vNÊ/4¬ûg”f• ‰!l·Àd;îs¯ÝxóÈvëJ“ý 1·+®_‘D¿³ŠU¸†ýÈàÕPå$4GRn¤×vxR—dñŒÏé ªZNúi·[R^Í–ü Éþ0b£Î[¢Õz£+m±3¬Z«)fµ^ÅÂë±ëêúR-,G©RFÃR¨ÿŽnnd艹ì$¯·±©w>×DP m»Úl¤næKv|ïöDõs×,ë/rô¿,2ÿà²Ýt˶œWºØÙ†ÁQ‘å©9¥&”í–lÖV§)ûµÙi«v¥Z‡§È¡ÎCÜ„g¨k~ÍMq–wgØç$Í©5_aš³¿m6™úKbmËYWe·CŒ…ÊEïlÅô\œ—Ø„WkTKµJ§×­5ëÝA·Ýmך2¸;±ÚÄ A”~Ó*ZUó=úX#Ì*;êáö^êyµX0ü;¦EÕ…,¢¯ªt|úqâ_„˜‰°Bçy¥¤¦¯5ÒÎE˜ ,¶úIhz·ÀÓ½K†Zpx'þ³!R9°„V-IHXìe+a˜Îu$K¦³ÑbSYC£g“O¨yÑW36¾ãÄcýzÅÅñ4_itsq~¾ÏjœWaiuØ‚ˆæÌ9ÉÜa×PQLö(·ªjuÚ2LYùSβÍà;ö²™øêþi6ší×»øú–4Õl6Wβ÷U€K…§1Ø’=bæÃ,arÀöˆ$R§Vã8qÖú*UµV¥R‘á¶“‰è?@&ôf¼ËL£#¤är8”ÿËÿÚÏImºå:¤¾0‚x …R­tÅ¡Å7|¸‰êaaê_$Á ¥fDKUÌ2dqâ7ò ÓÇ8!ϨNRÉÐd†Y‰¹åP]AÕȤCáÄa²bŸñ*"¤FGNhoñ‡#ëV»ÓéÊnéJ"<^U¶ÎÊÂ6¿{¸IW‹”5_ å2À4ucÜ’˜-ÿú/ï­¢u;ý÷ïÞkæòæíÛ6_ -m7ÛétvwwÏÇì µóÕåå»7×77×þŠ™Q&ê"íuvVÞ`®×«ý?|šO×üüéÇÏ)ÕÕ·› Ÿ4¨Ö¤´UUP#‰Y2&—ëÍ|¹M眲Îû ³Éx¿^nV‹íz)TÕþòù›7o/.ïÞ¿{ûîM·×Õp€!:°~™åÁ_3]ÿlˆê›ÜÑ/ÜsZ!íâ;Žöì÷Ü¿<ÃJžyŠÞ“»vØk²Ù ”ݤ[ÉgGê)Ï@!yÁoöÊý%@œ 1Õ4tHS›C¸S#©3¥ßãµÏB²‚Ýix9Õ…Ô”2,ö¼ ýtXm¶÷ãÕf÷ÃßæB Þ,=o6µjéê²}Õ¿¼è~÷ÍÛFCºµ*Ä pÂéDžUlÍi ·H:aûIãæw…ÖJE/û©äøÓBŠß~žÑQo®(Cé’]ùÉËL1 /c¬Õë­v»ÓívûýÁppyyuqyuu}}yy©ž;²IØ»è÷ýn¿ç§Z]f£Ò;²ð4#äÒÖ(ÞôÛþRìðê‚‘z2jF«Çhaõ¢7@Q)¢¥÷00;jºÛl'£©†ÆÍbµY®¼‹h¯Cc‡ Nc ¤82”5SBÕÆj™*Ì“5^«ç¥QV‰XZ«µ»-ôR¯+[& úÍNG&B¹ÎwüD@Ô!«&‰eäð=Y–${Ž÷2.WsîÒÈ­a{ô0šŽ§+i×Å2ÄÊ:Ó aâZåEï¸>ú‡30†µ@ý²²V–ìªý‹¾Œ$Y–>Æq£Ó–©!36ư|cdã¹)æï~›Ž®æ0Ëõèþñì6Ý£dñKc©ùâÓ_•™ÑMáà@ö ¹r^“ùÞ¬ËêåÝ D·]e–×¼Ku^ΕQ%äA'ç*ð±YfÔENæ FcÓ“,×µÕ]¼òI…Hºº}5’PñµF[‰v­Uçt½†²®VšU³I–\•\cq²Z‘ðDÓMv¹%S‰RÝÈ'â(’7AI¤d×3©ÕÚ–f'ñ¦Žx„‘Î^pZÛi½•]>¹ŸìÖ»ùd6ŸÎtk9_¨)Bp\–É£&ƨÆEÑ”®6Ý|qE(ü£ŠÈ ëe,ò©ñ'ŸˆÄj.§>È—ºÜl·ë k~~ý^ëúDOÉjFû&P–Âôó‹ Ÿ…ä^ÁIœ,B@Š#È"´WQ#Gy%äÙXYK“øo" †…;díÄ"+C.­.Y,º°÷Í)s@W™é^qå^€ÝJq ïv%YØz±t§ì$¤È¦Ö`Å\Y£ïD’‹Rcû‰t2€5iáÈ@Åú¦.•ŸžªO‡òaWÞï*‡]éì©z¶V¤äÕQ%'P‘³óô2ÃÓÙÆWÍ(·Ìé6 d›fÔWƒ õ‡È"gð‘¨B`roð9‹xóð_†Ç|~ áÄûË!êòK /70 è|Åî/yòÀ“[¿<$‡¢ûg ³ö‘‰ZP¢îÏv[ɽl>c£Ž‘I¶´Љ»·Ú†U [I˜{#Ú?t/Hž äŒgDéN¡ÇÒ b§´ ƒýj,r0¾6¼ F2mx\Õh·ša»®qºÛj rÍ¥ÈÕ8åÈã%–G±°M¿2]ZP De¾J‰Ù4³t´ˆšÇx5PŒéÈj M%“Ž1> Me™ë*C‘|t?PpxƒK0êò4¯•~R'çWÀ…`Q— €¯ä™ƒ2WßÉ;Z‚,¹-†BÕÂQ 1äƒ#Ïè\¬"ºÛbÌîe~ƒ|HƒÍ…*¢y<ùE!ŸÂ!ûÇßÐd!-ñBƒ¬’áÕ06«Ua«V1V[u_kÕvìø!§]+·„õ2üÖË2Õ®5>±.”d³éÜ-¨fWs³>ç3~=å IöNà9_Ž ð¼‡}]Ù(W˜áó¤¯%Rëa}ï0Íl.¬Ö[M|º¯Ý>]âÞ.ÁÝb½_nö«ÝùÿóÿõÿdSÛÜÐOHP¶›AÃr„¨l) 1BW¥Íñ[b%är ÂÀ´Séº$þ“}J—°CBàL7Ø x* El7&;ŠTR¶Ð/·É-:¥ºJÊØ^–Ý¢Y‰n±Te%ÈñÎåsŒí¬–³XÉtÚòþð´^oΟY$‰•2Ÿ¢ÀT‹“5áb0b¥-ZB]%HfÚÍ&ë÷5ÖŽÕ V«ÊÆ›ÍþîóÃÿi¹Úüwÿïÿ^·:í~»Ý/þìÏþ\5ÕQ¯VËéŒó8>~üÈþØí¢×iüîûöý‡›Í›»µ–äØU¥X3úÃ0ŠzÁSºÅJ’¬tGZŠqb·åœƒ=‹ lßÙñ´Z×Ír%ý'}Æz–r¦yíN»ÝV'¯¾y÷VyU¼IÌ·Ä}éöø«P."JT¬Kg†î±Ah»ŸÏ—w·w‹éü?üÍßNÆï&Ÿ–<–Ún ‰¼,WìK Åç¦U±ެs9® AR-±ØÖ`VÛ°Æ3†WÝ~çòæªÕasU­Ý8gŨ&kcm­í}\*¹ŸqF‰ô·Ä I>œo7lN_Η³ñb½ØLî'w£ÿî§ûÏwËÉr9#Vl#Þð*€bÕðége+fˆ™Ô£“®6a– «7x(‹¹;ìVÕß}hv›CSRïÔÚÃþþ|¿}ÚÉ`Re!ÁQ5‹m<¤;ÄÇÈ6|—}6ž&óÉì÷ù7»ÅîþãçÅd²ßl…*i·V¤à¤Ù(‡:Œ~¬±½ÍOˆÔ0ïW>K² zb_wÀ®µËîå w9¬wZ|/µZ>ðAl8Ky¢õ•Ÿæø,YÅÚ„¯yl!M*P"Á¸°Yo7k’¸ž¡K<¤$Ü ò •¼¿'Ÿ„ß N˜:ëåFhÚ§|‘]?Ó«+«ÏX˜€J§]Uu ä•ÕldwÝ~¿Ým]i ëõê2ë<áUK*²è‚uÅFAÿ—?웇ۇǻ{•5O”#™cD¨”TM8¡²¼^LÝaŒ² Dw*b°J¥F½^o4K[Û-B«5DtYV’Nõ.¿´¡*pʸM5tS%<‡è¾($®_Ñ ­BÚ„Eãt72 pìhW%q9niœ©3¤®à …$€@lþLë˜ù"ƒgZÈqœƒ• …3w $C&ÝÝdP¢iÂÂ<ˆSEH2Jf›Qöòb¾XÌ@i¨ùl¹Zò%ÏíZRéǧ!“ìCÜ)>>¥(w|™XmÔàC2 ¿¶86)–ôD* Z®Ôkq¶2ïø£õ4ªn™Xƒ%E”žJûùð‰uµª®,¶íÊ¡`yb¼*@§‚ €úQÝ5Hüc¥Í_V€?صÊ^f+{U ìïkh".BdËF^)xÇ>–Xœ;¨œÅxÚÛ!n ݆ѭ,Bk­ˆóÇEgô˜Æt×`¡c*<6ó^xAFçL:„˜öZì_«Qž°è%OcÀ/ñFBAÜ:Á¸›ª5-;Å„Åh‚¢W×äˆRMòT¿r;ÒO (t+UCxv$E©øO^‰C¤YpcS·gÉH„KCzÌåöók™Ñ¯+bx•í©š/½ä“¹Ãû'E‘ÜÔNÕ4Ò¿ÄÛ@s`8bø„gôbÅ=%¶Š™L5ÓäíE¶5*µFµÞ¬5ØÆ#Q¶œ÷:ÝA·ÏY\¼?(ì ú½^¿Ûíò=m­FÍo_Ñ8<™JÄM+åÒ0FÚ¥Ê}Xj)𤳈åîÑÔ“z#*6a› ³)„bnxP2™z­ óW½ÊX¯«ú¥Š’#&RØ–*HI93‹€>OÚ+”(ñå‰6.#œô>­!0MÔ/è0Ê™¨‚Dˆ»øLø†üɯãqh6¸isËC Tf\Jl>Z×è÷Èa;(Ccï£y"ºÚ`-Ì—Ë™f 9.æÓù|.§Ø /ÿÛÿúßXŽgKÉ’Ò(GW7r‚(º‘*é3ñ€òl3 7ê,‘Š’Y—D—‘@°xn¡'Ÿ,·DˆsOáIÞ q×ÑRCv+¥–C0ŽB4lÒË(òF$baŸ)–ÚO¹Ùf£Ÿ©Dv?ð³U™ü¼#'®N§ÂÅbá‡Ô%‘¹’¢ygÚß6[(!o•ß?¬×Û‡‡Gu¼Ë‹Ë pøþÃ;o ®Š`æ,éImø&F«!zuy1Jœ[Í–4©IjZ–xmkŽóØì¶g£‡Ù~wþp?æøós…ê×——ƒ¦ß•NVR?ÝGP%ŸkMˆ—›É|yÿ8&“Ñx6”žö²þXç®WÔa®®/{ƒÞ7ß¾^ ûÃ^»ÓªJ-ªˆi¾À;šÏ;,âîØú¥MìF¸‰îN`qwTùåõOÒ‘Ï/À”òçáY4{¢è_ JZLˆˆ†7~ŽuEiÚõ&z¸Ã[¼UðÒ1”™L¡Qn~åNr'ñ• wŠ”cAC—ÂO¢Á¹Kd²F„œî‰Õþ¨:užöñ&ôr¹ùt«iëÓOŸî–s¿œ³ÙH 5Ѥ÷ÍõàêB’Õz{s©é±‡0çJ¶^TQÅbªå¨gÞE¿æÿç!b‘Ô oî¼ôþIA嫺Òmâµ ?)ÅàL#&6ø¼ úŠšPŠ}:Ö£¡ÚHep ïéçä•*Ÿ¢Ï·­¼ëŸ5•J ²Ù!òÄóz˜I©0 Ÿ|J:çz@†ù­XÒØ|bfµ™Mæ³ñlô8ZLf<ÉZo¡E†˜ûd%5—§5h:"Yļү€ã?dB×k²›«µJÿ¢_“±Áwyš¾È¬?ØÓƒm…»kÂÍìY™,gsYxš¨c‘‰\-ð2,dj†a«-É$B µ&Uú9ø…¨•Ñ [MÆJÿb †‡ÝÆœZUüØ«ÅE R¯ÌÈ^c7Á‚¸–x­Çϵe·)d6›Š¥¼‰]ªÁMÕQ4g¡hL$[·ŽcÐϸyƾ)ýÉdJf«ìd„q¢)üp•§}dƒ7ÀmH?’$âÂ>q± E*­×ábi]¿!‡p…mÓ2´üÕDI ÄP3 &ŠŒ†›FF¾ÆÍk¶êdï¶yÐY—)Ö¨«¡k-ÞN­b©WØHǪ[¥TcfÙ¯Æ[5NÈ¡†ªv›Æ¯´iŠ/OŠjÖI¼¯ûö£í6VòÛ4ÓP©„kK—ä‡îŒ¨Å"TÁv×XÌMm¨¤‡=‹ç¬åiÁúÏŽi.‹AXl|ÏÞó]©NΠÑ£m%w ã„æA92A ßtË膠aS»¢©="„’ˆ ûˆîu:z´­Œ$ë'Ø“„q‚§ÂÀìÇ¿ Ð"˜À)…NÅÂn!f$L«ûYRî§4òÀ¨»âŠ‚¼FÁ´3щ-°œw.fœÖ1zœfÓñr9çýËíZ·žö›³ýö|¿=ÛÊÌ[ïç³¥L7VAg³ÕjÁ›[¡fº’Mõ™ŒgõF©Ñ¬4ÚÕV§ÑíµúÃÞ`Ø—©Ôë÷:ݶ¦Âê\Q#³W Uµ5-gçÊA…A7”ƒj#·Æ#Ù¶ªµ¤ÔH«Âµ‡?EºjÂ)dIL¦xmþ©\/©KˆHmK‘«_ÅRµrðÔÌ‘C,T +öòzrè]I\iLÑ¡ §ÑݾçvÐ…²4„xæ[t ÔrFƒöݘ¦3%|æ<7ƒ/¹©G¡Oýâ&ôÀ'fLDþªõŒÏ…¶€!ì¯øJÏHÄã' ˆŽ™]#‚“A­õ¬¾8¦bD< ¬ Ðü×¶[¾Û!Ùd¤¨ÏvꃓZõ¼V-ó^šfÉ^³29k“ ïT­m(¢–®Ü—ÛëÄ›à$äe„©Ì‚;óáM.É÷w!NUéRte³„¥Rb ŠL¤rb~)ŠúìE7¨ÿ±ßl/ä(S€…Àb’EÈÙÈŽ¿¥}9š]³¹êy©^*7ÅÍì³­†Ô©þJÿ% šä’3„< ¼â¸%éâh’êyµVnõšÝa§ÕkñާŠà*•W¢þª°¢«ÜU•¸VøÀƒªT®œ•R=¯x£:k†õø²†FÃß/Ò¨_«±7HÆihb´Ñä›×"T DÎÏ¿ìO_¥D„Ò&ÞA.Í*«ÎÚË]Jè~é’_|pZÂn­gÅ'¡PÞ*/!:“”RÂf‘ÞÇ`âQ¼Æe£Ld"A°JEœE²w°VÓIu2Sd£È—R’&§b:ã2䨳![63·ÔÔ\Mæg¢ª "C}ý~ÝÊ»ãŒa꽇=™‘øP>{*»cƒpI°3z¡ïiïæ¦p]“º£Ì,ZÆ_‘7’Q­vÁ¾*— gB#Âz¹Ù¨2úôÀf¯Ùê7[Ca«{Ùé^uº×Þu·sÕm_¶3ìt.;­Ëvó¢Õ4Án£ÖæBåˆx]ˆÞ,CéØî,é¸+ÆUu7¨éäV³Ú°H2¥\ÄŠlÂAŸ´}¡Z¦Übˆ×:b‡àN¿ lL뽸–xok#»-í¤’é&«Q6Üj±ÞÌ9¤z9[.§ËòñøÏÜ+nÿ'GÔÊ´¢ ÂQݘî¤v;âåp%Œ »‰@fXà,YÐÒòpNfË“ú&†0A„ZÄ¿YÈ"¢øªPEA^@!‡, ‰´ô'JJÙÃc(Ê_ò¤ uE(@Â-¹"±:¬d…Íõj±ôêúv1_|þ$ø|wÿÀ§÷Öj$Òn´Ô55Á¯VYΗŠüñ§ãñøÖ +þææªÛí¾}Ë—F{½î𢯎\o*‘§e•J³É‹Ò}öœt‡6àú½¶tZA³ uàj™nÀ¶J¿¢V§s–G£™ÄBÖäl6Q_.—¤µ7oß Ûº:@З¨ÖšgO•Ýá|½}Z.w£ñüq²¸»M¦šd,7ëeÍgú‹a÷†wÞ^] ß¾}ÓõÑÒ—bªJ‡VÑpY¬ŒUz‰‰ºr`Úw š o4jeÈ-®ô„×az¿Dp˜¼4œ„ÚÝÅ=~¬qE:œºA<ß7„ ±Ã÷’¸ë·XWA–[–ˆ„åî,©DGÜå?Ñ“²ð/á3Z¿ Ä,Ò”ÜNŽW One}À™cž°"K§7¯úÍÙ9»ÎÎg‹Õ|¾žÍW·Ÿ4Óùôùn¹Xi Ñ` “`0ÐL¤ñíû7on.XÖm4”‹¦x6ê¶K}Ù:$­0sׂe"rš‰†÷¤ùÉn·¬Fó9*[€Hä,Bʪ?¿{šço7•²¢.ê 窷¬s%„<º|Œ5(-WI­a¾Á!ÿ‹ÎgˆR;Ê!F¶„õ3sdÞ-ÒX_b?\꤃ ™øy¸¥PÚ˜&v³+$Š6ÀEp a˜9JÈX- ‰'eRkÒT‹ùJà 7•*yÆ~ip^õfr9X˜ayGZ*T– ¶Ž4tz¾ÆŠ Ox›Í®ô$'›°QoÐoû=Yݵ ¤ÌÏK¼ßBMqÛŒRM46Š2¸".ÎwkÍ\Ïxñ·ß,7 îb9yœJ.gsv$Kçóš•£q,Žb'¬Vec3°²¢`wž“òØt¹æ!Þj-Ó.;Cqt¾D.¼'Aòæ@§ ëûB à™؉àÌø TbEæ\)ël.ÔéÏ…ú–²ð:µc$H‰³Ã¢2œÊpŒãøG¯T`ܱ’ÕM…ˆjΠeS¡,â…ºôx2~Ïy ¾Tˆ_L‘)¯¹O­|V/—4UÏ8ãl½à(4©ªù|¡Æ‘¸¨ÉÕ‹ëšÓ‚êàRXJŒvBA•5¥”öd9¤X$¨)ùdWMYNõÙî&”· Lå±Rv‚¶B»xªªF3Q_õÀà¥ÈÁŸ@ŲuÀ‡4cbÇH¨ò ž³]n ¤Æk3¿9htF`r‡7¿•y_“[_ôfåžÀiæ§qNò+BäøZ¦ÇT‘}Ž9ä!Á„òð_…¿ NÒ s8 ü¼zWÂó*CÇÈô:i(õRÍ/wg;¯ºY½#¨l˜aI…óo$ç*çl”¤Z_…/ÿspRð~3-°¹7¿ûÇ©?+Ï‚üÄp—º§áèú"ó”#jîWЙÓt&o$0ÒOÅþclgôepÌš¼f«cõ&ïFð¾ç›Ë«w×o®.ß^]¼¹Þ\õ¯‡ýëAïzØöÚCbœ$WkqúkÅob²ÍÜ{𓳠§ðj“ÝNq"ókƒC@0.Љ<öÔ`¤"’z²jä‹%*d¸ì¡G‰GS@oáOÿY¸aIäšCA0é%èØä50EÖ°0“÷Œ½ŽÀ [p%‹W¸—`(ʬ×|ž<ãžMTy±Ýé\Üz‘¹Lò³'ÕiÏ’¨ÊgAˆQ…gs2d¶Êz8l·gû-Knäk»rŸq1AògŠ÷Â-žîÓ ±DÇB*çû­VÛÕr·^ ÷ëÍÙVºÃ†pª9ɽœåZ‹µ•ÃYõIl©^*5Î˳j«TiVJÍJ¥]«´ëÂZ§VïÖ[ýV£ÛªwêÍ&¼^p{{ûø8šL8’Q}[ñËRqdM¹qþTñ£"ŽIœÏãñt4¯V+öøÊ¬«W|ÜŠ5~^f Í›L¿/ ¥ãd9iÒ£æVþ³Ùl.ÓoÁ«4YÜn7Ô_“%ºAêIA¯9@;Iõ+Orvæ,gD­U5Ë N¡¦[2L£ýʼn’ÌÏJ£Uoiã'¤-¡f*5©IFZx“1–$¸kžiÚIöÄa‚¸²§ã0àecÄ5¥M¿Èï–ŠIXô¼T*ÊÍïæGÝI‘r‡!U" %È<8 í9¸Ž!z ÊeÞIf¿¼š[%Ùa}” ï3o$Sb žÒ`x-ðY&¿^¦ Þ¥À ‰Ðð;ºBh_QÉ©>º^°wðž²åÿœ‡ZMĩƒwCZq;¦åŒöÂçùÓàÀ_'‰Âû (¸]_Ú7*žÀJ"EûPÖÖä47Æ“­ Ï Ž!€ÇÆÔ#1ü‚eÊ,º]ÂÔí,]œÖBÏËíÉeO·Ô(všÄpv\IH?³pŒqwçLÅLÝPÍÉ: Ou6¼sžk«Ó^]¼ÿöý7¿ûöÃï>¼ÿþÃûïÞ ß}ûþúÝ›ë·77—œŽq1ì {­A'>í`›LÙ {†«B?W«W«­FÝgÑ)[+ÃÝK"Í£‰­1*F–£Ê²¢ÁH]2K8ÖcïÏüa§­w|IÚ_g“æ·¡oR6ÊÇŒS‘ü¼ì®[b™¹µ}ÉjL,y­†$`QqÌQå¦,)E”E=¡¹)òˆ¾0`‚ÐýG¹Ñ¯Ðò.·DÀ‚%¨h#Ó¤¢T¿5éçžæØ6·^®²ãæëÅb»d3·*V~:(}˜&rîÄÔÉBªCŒñ’_XÀlÄã´ýÉLä[ëÅ’ÌV¬Ê‹Q•Š“|Ër¯šòùå†rŒ’¼yóþÍÕ»«s;pg—g§gZ€Gþ´@wØíä«u»Z¡Ã]õ#®—i:ípgº/xÈ?á"˜Ü0géEÊ z ·3N^ª´tò¬—³Mûò"|r¬–1qZg1¿©íi¢Qº‡=/U˜@vÚЇ¦wfv¬¾©ù6i8«0ÔœÑ`{Ë•"râ«t?¿¦l *ü¦¼®“q[´ W:v»•¬#ÊÀk°ÈÊØq—›ý¶)_ ¸›,¦«Ù\®Ûn-g÷.0ì  ÓÀ:B3JO6Q,û¹“›/×D3wŠËi“[<ŸÏ©Q ÛäÁȽ:‹Ù‚‹¿ZZWh_ó „¤EµÒ€Ê9]Ò!—VùRk/ öxU“‹Ì#>ÒàçT†,¸|ØM…¸Ñô§u1™:2FBõ"v¬Ê¬.A²qw‡{,ýtóJÑIãÑGM»Ô%J¥VRLî}ÐêÌ– _h¤Qw‹.•¸^0 :'ÀÒ>Ô#~Óç‰ ¬_ º-Df!Êj È Ï1ËçÉüòüëR‰ïSpN´¯*˜ÀK”|`Na’ñá ñ/qi«ºT#K‹Gseg²ê»ûûû‰|2 l±“áÈcÓÌÔ•Óã£8KÊq¡|櫜 qókÐä†|c’ÍÑ1„ã.lQ#SKƒ‹åRöÌÞÞÝÝä^§B3¹ZCÏ!dô_È_+F-I˜:#ũ»\/oY—ñtÆÂ½"ÀøôtÈ·Kïþe¿ Þf”Çï>–:ëàBnjüäTó¤"%œ¹$Î3Mäåô}ÞrnäíKe(OAE0•R—ÁÄžܪUz‚Ïr.‰‘¾é »Üu?ã5¨³*â•”€§á„‚ô„’ɰ^˜ƒ,P5تŽtú˜v,˜š™e®>ÏÞHZ­tVÂëùû}NYXÃ8€[Ô›§Òh©uÜ;=§¥ŒˆF‰H)³jaµÂ|öô“•¼‡) pЇ€!±2à# e_È‚}V”Î7DbŒŠdš"E°º„uÆ©|„ 釮¥¬5Lõô¾0Ö!’ÉÏ]Ÿ(£2 3w1Š‹LË” ÓòÉTuúètt~y~ùæâêÝåÕû«7®Þ|õæíWoqྑ÷VaR>€WÞ¯®Þ_ž_.Fìœ äÃY•u”ß&O®Ó“£_ÚáP3±3‰·À|É‚‹”õÑ¡Fù;¦äÊ>çTfɘÜyù3¶Yaj»ØqñLXù]‘Ϭí¡3i‚;Ƹ„âÓz'Æ Kâ  ýæDJmp;ÏÒê$›ÛYØF²sÀ7d¹È“»ä¡q0 G¡ìÐ"6C•5–ˆ(Yí·ÍµÂL¦·÷³ûéâa¶š-ü’anMÂ?µ.$‹'æŒ ¢P QŸ*B ; Ùç ½pW—|³ù\>Ûdòp¯•íîþNKÜͽָ-sÓ™¼·¥¼·Õf³ô׆ÖìwªqâLoñ¾o-Û8Iòà¬Tv<4§tÙán6® Ø ‘K‡–¬p·ÝΈ%”d›S——ÔwD´ ;¡/Pf ÁÍç+²S†8‚ä´ew[ÃÓ$…ñÊþ)ºIJLœJ=@t“(l>X)œSf d€2G©'½’Ú´nêËˤØ> ­/5Z. = –˜ ¦ªÜR± ó1Ô"¨‡¥¨eXräÛÅ[ss™Îfajr¥¸Ás·Swà뇕°ËbT¬LÆÉùÄL¨:N95ÏŒùÜé€;.ñóاõVmô~\;’¬² -âp?™\óáw™6Ÿ7• ('Òg!õ^*žUà_qµ¾Kj«…q&[ÒI š ·S-Ð)ŠÜµ‹³ó ý_œñîü6o˜[´i0Ã/‡è¼J4DÍ¢íat2%J¥½uÈÄ)ô¹lDøó™WrúÊKžËb\fð_‡B&|¦™ê…:Ñ Š”ô…_d›ôz*zû ;>ìOlvvØþrÃ5&ü6¦×÷cQ|ÝûŸ|1¢­1lµUrM5 ŠHA&ü@ê ަü$ûÌP‹ªl%ð ð:šŸmæÀºÊ”¥y<–å æʪaZ”`-Ë«BE£–õ\wS¢÷Ÿ¨Y¼’ߦ¥´ÛïÉÓ:»<»¸º¸¸:—+ƽnï.ß¼¿´÷öæÝWòÛì´¥ð[ß}õNË÷W¼Ð_¥.NÇãñùht>ž‹ý¶/_mà·iðiE”›šŽõ*fr}{R¬ 4TM´2)æK¥q‹F>¯•Ÿ6äü¾’Î5A pÕ+MˈŽ1,$ ÷Û‡õs!E3.WèR7VF„ΤµƒÔk[¦Q¾ý6v˜ü¶ -7Ü‹ÁI9 Ù}aÎų¨Œ¡PÃd¨á8z¾Nºâí¯á9Ý=Ì'³å¿ç6äºmðÞЈŠIÁé¾·Ä.©&  ÌØ¥e#S~ÛR«)oZ‘Óv{ww}s{}}s}}g˜Ü³ÂÎfËÙb5[®çËÍb½]jfÁ‡³$öF­†qðC©-ž«ÑIB‡WÙpA«×“Ýq±ˆ§ml¶y£Ë»j¸MyÜHF.ÐÒyLc’5€6Ñ)‚b*­R‡p×h9gAW‡Ûkç$$z}g¸ÃÒ—Ûl ⺴¡0dáým2ð Áý&¦N7ÂÍp‰D™ø‚²A dòDhföZV‚©|Šä–ù˜‘*p)ÀÑ¥à@Љ$IDSkÑØÔ^¡›Ma@Ãü¯"QÉ–Xg(*”‡þ°w)qÚä*Mx 땾Õl¹ZI‹2v¦Æ§ç†á`¨3 µi&o“‰‡ëOŸä½ÝMî4ŒOGoÞ¾ ß|󵜼³ó3¹q:WPK$.'$R¤‡Ùj½•«7›/t.r{{;¹½ÃÞå&r¦…È<9ÁB`^»°YëLñäæz²Yï®yÛÍÉñ¶×Q7ïÞ]¹Ó·?Ÿª­2"ùk1£hjYë“ í|òVÌ{ÝΛ«ó7ç§ïÞ\^Éwó«µÐª]2Fº-^£CkÏÚN€2k)®§ ©Ê‘¹ˆŸ 8=KJ¥p`N‰ÄK¸ßõ«LþãP@ê õ( ¬çfÎ0ËPOÜCN@ÓèbØ$äòuFDEø ެöѵBSµ:ÐO@>”¢l„VZ9¬¥d&V¥JjL¨u͉=ö)/€ÞÞ3Jf“éÿô§õfs{{»Y¯eZ:+ÐLúÛ_£sŒÖ²v¦‚\?7 ð=#ñ÷Fz’2 ø‰²  FR¡ŠpÔ`²Z‹^Å€—¢{x Às¹€¹ä‚¡öÕÈôÅXc‚Ïl½Ý€iqΧhdFñ'x a€xÓ¯© CVòà\ Õd,Ö èì ÊÈw”.dbäé]þ…ïBcBë—Y”ü¦¡V¯Ç'dÀ—&xQ>·.é´XIí‘ÎvÇrþÃÓQÞ¬6òó;lÛÝb>Ss´j¨p0&$LY@] %Q8ã.Q‹è¡êIcfw¥JWò2‘Ah47[ª´Wƒ«ƒ"-“yJVÄG)faaYyw.Øz™A|ª^ŠÆwº—s–T®ÞO¦“I ?ð™|ï´-…‹·q/æéU´ÊâŒåZ’àVsIÛWQY±Œž¦Û½…/‘D’ÉV‘QT8Ó¬HŽÅBeYâ§<{{}·åkýà"4üį•0ð#£¥-n2FíçBÂÞlÞú?Ž7Ô¥‡ ;¼‚D¶¦°ý6F€ÇCH DÁ`ií‚ø/©M1r ˆî  ùD.A £Ž 9í¯ƒK @*„0$‘Jü Ô²PR ¾(@iÄkà ÓR§¨º§M# ã0ørªðý[ßúvqöæL4£óáð¬ßv[¼AI+¢ÖÙaž›X;U_Ãò ªŽEB‹¨€Ñë:®“%Wq¹¾g?„Ðx~v£3jUå-d  U÷Ò‡Và—ggn>ó•¿D@à =÷ªÜ !6ãH?Q*ÄÜ%zç¶q“ØÕ²Óïòîºç?*.Qy+Žjb¢ü‡|FšA™ÇõãŽw‰­×óõŠ=ƒÙôn:½.&ËÅÃ\‰[ù¯\0 ½¨$gW¥ÑˆpÔ©ÖÇÞ€ŽŠ* Pqy_\']pë7Û{Zãîo'w7w÷:û¹½½.x3¹¹¸½{¸{àP>µxX.§ËÕLþÝZ|vëÍÑú‘4ª"êE*Zi°ƒ<‡H‘—æ=™d'q„óçhßÉ‚ÔÓ êD%Eg U‘³xbí2˸+¸F?ÖÚ:Òzê8…1‰fó˜WKp Ç9®H»[@öÛìÞŒÚä:©‘J ì´±1-?ðÛ,)àÂÌÀ}ŒVü4¸9¢_3uA¾¦->C§ˆÇJaù©¤v#|œ›8š}ü&ôÌ ‘…q¢âHYõ¡œ}9OsžE˜^_ßN&7w·rÝäåK:^^^ÉÅáÕAƒN¹{µºÁúd†ww··ò÷äÔëàêêê«o¾ûïÞ½ët;ýºKf¹h6 íM9fóÉÃÃÝÍÍäööáþnöðàóÆ#tj”òtC¿Ûl©¸ZÄé#lo×דíúñúÓÍäîöäx篞>¾5ö%ëéé©z]ë%óޝŽ:—ÐiA[§|A¤Û;ö¯.Î.ÎÆ|¤átÌ÷áz}Ù›ªHNÏâCa3²öPºç15¥ÔŒ¨=ˆSX1(L©ƒ#¢*ǧQýJ˜*g£û¨ÿJte†qr‚×£XK Jº@áÈU Â’– æh›ª!½ &éÇÅŸbHlÁœRa¬Iû¨”ž£©ZVH“µgE™2§¤tÉíÄ2ÌhN¼|»›i ÕtºP„Q› ‚öÈ;ÏZa´ZiÁŸã"—üZ| )ùvܲıøø$eo(ìűí'ÝUDró¼ªg¦·8··HÇ'[e¥i!m5wÛ¦M­™ñy–«œ¿ç±[ù&æÅbu{£“t&h5‚òÈËj< ®ÖÈz55«*N@xG UóÖ$Rí¦Ž½Ñ€ 88=?U[N/ÎZþ(“8Ô#É¡¢@,MV•@³.í"l} }ÿ´&a çkÃGóù¬Óî<ãyÏO7Ÿäºñ„Ìd²Þ.¥ÍGoÞ\}õõ‡^¯{yuéWvÔµœçxÚwNH &šår=}˜Nîîotr;}˜Ì§S¹æê´ø¤.ï!ô5±™žÊó‚ëÝÉõÇ»íúèæúæþî¶q¬•R'eïß]š4úg§gb!É“ß&ôLÔð{!eN<”Ðï‡|ç—Æy ±ÓÑT$1}0˜ƒc¿“®C‡¹ƒC½YÉ{ÑÀ'‰ô Ķ„jǧьN:L’¾ŸˆÝò<ÂP8JJ|6â$kÉ5F"èJ%)1"þu %V¥^Á48_F7°^$¢Á<Ž P—pEc¢<>R"Ä„£‡‰Â²à˜ŸñÛVkÞó SéùGùmìU/5‡ƒ«‹‹A¯û»ßüºßíŽtÓízŽ¡_Ì6@Õ²:Jã:©ka% ‰2qjEN{¡wg(P#¨¡mÜaJz*ö\”ØæÜNÏLŠ&ˆFD "z*(4FK™Ykè,Z£Ò¨ûeV¹l$ù/’IM S†üš„”ŠÒ)DÂ`#§DAÿ¨HÕ,íÑhMûEž“¼EÁ^ExYZáðáZ¼úAg–~G’?yÔãÖ.ùs"“F4w³–)/p„Ä]ǸÒç-¿f#ùmŠð:/ŸrÈÇäRòÛ–«5/Y®îîîøˆ¤Î¡ãÄZó¦*O éyKƒ(“4b›B5œ6a4G’kJÓ䛯“Ž[íÖøâTéj×q“' „*+Ö\áu'Jpô¤ /‹èÍšäWÊѪþ¸åZÍ™jhµïïï4C‡æ)nJŽ1œøE (ÈÉ"Źq?ÅЈöH&×wjÓ‰ô UJ9’@QƹªØòAOXp£›:3|8sä£GnÁ‘4ìÀ;ºÝm–›õ‚}ž~à 郸)ïñMÛ¿xÖGûd~­üb6Ç‹§ñü©IéCaœ5õø‹7ßèqiʈ Ëó¿ ]fËO’*ìÐóÜ¡º\ ¿¿¹ß­wòáì·¥’fª€¹à·Ñ)î(ü6EERÌõÚãâ½…œ{txC ¯ÂñãX,®›Œ¶­£lEˆÇ‘€³£1) ¸|7³ ·íÕ ¥úxˆCè´@â^ªËQCôIâ# xª¬&¼0…—§BMJ÷~›Ž2?zÒ'aòè§:-˜È]›Èo›N~P 9Ñý~Ÿ;ÛÎNÏ/.ÆãÓ^¯'õ+KΖΠ>}ú(¿m6›jÅÚ=nú. ½ywõáÃûn¯sv6V'i«W4%hZ xB ” ó êºç†Í‡û{j臇Z|è-°A·/¿/j9ÑÉ~ÛöäÓ§ûíêñúÓµ¼½Fc7”ßÖØåý¶þÙøL6 9¥NKébÙ/¬–ñÈšd]½^g4äÓyC®ïòÝB9þ\G@++žrV"J%Q p¬áÔ)‚HV®!…ѼÓDrì¦; 0ç·œ…˜&eÕ0€€éR.o¿Íþ ‡ƒ–ö ÅGWðsÔ¢ÿ¨â¨ç¦R9P†VD#¥„"À1„Oa§Ö`/Á{˜ñš»Mvr×–ËÕÍíÝýd2›Í¯¯¯eÞšèÅðt4zsyÙïõ~‹ßÖáãiŽôC›©²q©öä·a¥ Iç£QA½z]ô‹QÌÍ©†{¬JoêP ºê£ >IgÍ# 95ÓKõ3`†€eu¡-Ô1šÏƒ¬‡‚•Jˆì\€‰6AŽÙp–šCš„#žã0m5EÔ‹¿/JMç¾däÉÉnÛXòÐ49.›dýÅ1lÈ‚‰2‹²#‡A.Äj³Ñ™³ºÂaD<©LË*a1³æÈfm;ny&àz!mñ|òÛúZªûÃÞé¹<¶–¼76y@¡‰Ì´Ùo#jþHñ"¤t¥Êoób¡VÈoÓZ#­ÜÜÝHZT±cÄQTëœ?E3)¥ÓbÛ›{ î×Ky|ïK®ŽRV«•4¹Ýl¢Oµ,ªÆíŠ­V/Ö0>5ý†O„q'öÆO€ú;N\‰šñF_)v¦URgx÷3>å4Ÿó}-Þòhž.2+®Û®+1Y¯Äe£ŠäÞI\E¹ Û¾åxá-j¢~úIS› '<‹àüЦº_™áö‰Ïr¾’ã|}§zW|¥`£h(^Z3¹Ýß1*°¡aÙiU‘òl´ pIT+v§Óô;ÝnŸ×‘ôä´{|XfÐíveòâ ­v·G„­¸pøZ¾ŠêÏ ÿçÿÕÿ:lZ`yJ£|ÀÖÁ€¤tƒ~,q"1îLd*‡kH\0qb" ª©Ùùs4¢˜í¿" ̸ˆ! Êg%‚”èV•&X"²5õ.ã’ñ¬¨êTÏÊX•%—K§·Z‚€ûëk® ¤Öáh$§;À¸Bz>Ž4fÄZ®ÞõµÜ»é§ßËo“gþ——çÃñðÍÛ7ïÞs…t4pŽè׳ɔ01nÆh«Ã%¨¼8ùmܦ9™Êo›N&+Þµ»ì÷T´=ÆgòÝúƒá Ùé 2#Jç’¹qói²Yá·Ýß4Ov£¡<½í‡é:éx<–4Y¨:µš³<”w^ðe_ñ×Z:ìuøòw—'ëeWLm€ÇfL)tʌȼUFoòDCžDpØæm »z¼ 2ì…œè2¨˜vƒC¤0£¦3©ƒRÔƒbEV“UUEðŠêã÷G¡ù‡Ñ„½\PÅbÒüÊS<[]€÷c?„bK>©¿J÷ú~€’˜â—£æŠjµ×Sš‰ÛÊ–ƒQe±HÎàh`ÁBÔpÞ×Ùs‚€\aaF†ŠÔè¼4ÖR¦þ‰&jÏ J;56S@lùͲQXMs3uÄAp>@À%ƒ…Ì“y›£ ËäÌÉO³»&ÐÔÅìd3‘Dž…xÜÀ[É„< ÙŠÛÅÕb-‘Úo“3T¹f~yš–5ç6|ÑŠI“f^Ɖ_–gÙÀ——dÒÙ¬¦U…C¦5¾ÝÔQkvÞo;Ó’|ÆQk3‹¶]Uåb«ŸÄˆ:1Ú…&SRHEf¬FSÉb9×òss£,9"ŠÄ˜ ¦Šà¥Y÷XÄuC¨H¹1DW\¾“}¯ÇíÑrÁûa9IÛÅ|.j9ŸÉ™ ‡ k¹Ú*%ÈÛfr«ø¸ïï^,åŸÍf|ah2}¸»¸{˜ùA^·ë—}Ä—•T 6"Ójæ;ྉM~™ªÆ5|[9v d_l!×M5HTïÒiâB®»Þ§ô©J ·H–¶ÕJœµTbœìŽå·©^1]Å~[\‚S0cA´ÚÜSÞ‚Ü_X‹û‰bí´»Ýáé°;èòÂÑ€÷Øû½!×ÍÁgó+KxÅpÐU` °<:ñõqã:-lËݘ ô,µ1¢2º£-n¦s)C_ÁªÔž°žhš§ðlb½ºàÌÑÑgÀ´{¹ŠJó6[=%˜D‚`ßêKY‹ŒP=8—·ÈvD¯²­VË=Ý.β†· «œlˆ ô~‚èm€Gê“ö4ö5\}ߢj¤Í’#ä¡×ù!ãX#GÆÇiÄN¦Ë&0¶&BTÖ†‡ì±sžç …>Ìi˜@Ê“>|-øè±yr¤‰¨Ónñ€B/¶Ùx¨K­Ò¼Â.¿Yž!€’!z°SIïæØ?cº tµ¥œÀÃÉÉ"J£`¨#¬ò ¬Ãä>J’xÏŒ“S®ŽdÛ9ÀÈ… QšÛ¾lQ¯E~1áÑ2£‡— Ò›ì‰Zë ëáC| ç=°V‹®Ý¯b,3‰pÈ,8ˆÏHÌ‚ø‘_,öñhóx¤“í•ßSè!Æ»rÒ«•ø4‘~Y±<ýº50ìŠ0GåAMžÒ³)ñ€ ¢%%ÂOQðeau­C!~¢l…¥‚HÙ[¾Œ“~¬D:ô~Ð XRUô Ö}]0f0g±ŸIIÖøTzŸs`”u’Ži º1°rn¦7h1Êy·Ý­P„ U¥NU·[ˆ%š7l„»µ&î•n!ðØXeI2ž0!|7yb¸n,Ì8S ÞUä:Õ4¦D1´ÇšÊ¼m‡áA‹D´Q_–å>#ùX|ÎRÀëøYB;^’ÄÇúfÏŸÅáîò¦œ¦£–&PM~žL3îN<â)7Êò{E—KÉýpáðyþÌ þŸûá-Wh3ëT˜[iàT·uÂ-€Œ«6àöå𾦓VC“%ÝÊ=:Ò:´æÕnøc Š‘f\KêOÛ˜„–è"]?â&-7ëùz1Y,ó 8.‹ÉT(¯‹½Ø0ó½hrªüÞä´ÉåÚÊ«›¯Ö³ÕêA|f‹é̯ó],ù:ÂR¹»Õúh½;ÞÈ›>Ò$r¼ Ö’a¾®Áõwj뵦³ùÃt>1*àw¥ú>¹ùz…oÇêÎún£b%@{éÈc+Û$Lî>T9`mÑFÇlÄaÊDŠ" PZC™o_ò^dæ¾®ÖT™Ó°ç—Et ìü™‡ÑÀG…#ê/tza¿Ýë5þóÿú?ÅB°ó<̹_Àöa™mCn,A"â¼a-(²jø†…)-Âþ #ªJin1U³†Ã¡NÒþâ/÷æÝÛ«·WççrÁ•‚ä±ÎꟆ贮 ZùÖÙäÝíø; ù„Áh gœS”Çc­Kê&îo{¼¾¾™Üß4»Ñ@óÐîû+ÑËÓ?Ÿrnè¯8 lu’A²ÈÄð}K‰?.¬,LC2¹wDŒÊ¼1¦ô$¹Š‘«ˆ&g®5¡ñã¨PYA,BŽ^<"ÝÅ‘`gJ£Iõïtÿ&š:JÌÖ?Çø >¹HýØD¥uO)#KYEI…°)áÒD~ „N “:·HŠR˜u‰Ë ìRèTçã§kÍœßÿñæúz6ùbÓ£N!u2puqñÕ‡÷C¿§ËdƦ¼9yÝÀÆd*ÁBƒž"Ìpv ¤ÿ*ÁPOQ ™\-±@ 1 ‘R ìcÀAâÔÈ"Çz  àyÕ+>e9Ëòí Ð9îþ ¨Jˆ$ýhbcøã8XÄ>*HqA–¨5næêâ×3I¤…¼™2uZ$$*lufrÚR3MVU2ÅÄ<ƒxJau„eŒdÀUS Wú¨Òó¸N‰]š¸«tŘ™ÃER”Ëœü™ÒŽŒ¦`¶ßt.l9»lƒôø\Ìwmžòlý©þÏÏÏÆ§Üÿ/N×$Ì=%¼²Ä¯ ¨¿^Èüy¹|¾V§=¾8í øúÙûm£S®“Êõ[B‘¦²°± BvÀ;p ±h!”Á7Z” ‰å¼¨jÑé¤_ªPÃÈ%[¤JáÐI‹˜|­Yú„*1C^Œµãålb­·<ÀÛH§“nÝy¸ç»û³Étz7á:žúœLïヲ€R&ÊšÞi9¼¿ã)Ñ”òÀ›á¦|a¾âb+;m©…ƒ3m»´HêëÔt'öŒ´G¼ûc·]I&¿Õ{ÅS­–-¯TCeê@¦µ_‹[¨W\Çj›5:b‡vïø —üTyö÷Ÿîuö)ŸRË®ô Re½QÆf(nN%¤„®š¢ª…µ…»&ï 3ÚÜuÚ¸Œ5àsºò:Ù WQ{ƒ!GöÛzìº ä‚óœ®þ8gèŠk*èĪpÄõ:ì@…t¦˜i0¬ˆ–Á éÓïˇÆ_•ç:ð T|2>!t Õ.éõ«;Ô©tþfã·~,e§³¯óP©ÞŽwÎâMÌlKu::ßOïµêìÂ6´òç9˜MØ™Óðík˜Çò»ØÞçþЍ-ÍcÐ 8Õ¶aíxzÚ(E“y9lÙQ‚4ÑAXÅ\°T*+§~ [ƒRá¬B,@ÂÅmµžà-™­%Þ«óÀ‡©6£W 7U²˜CÍj¯/ñCÒDö:ª‚*êfUQcÔÉ 8¹Â§)u €CI ØÖ›"HC¢Ð¼Œu÷â³°.Éb”’Yª¬0—Šø•¤$ê¸ÝóŒ?s' YUG³¬¾Í ”š¦Ømã¾.W•-(‰@ÀÊÂ`œ¨\Φ„ ,j`¤¿Œ!Þ³PEsqM¹%ë ZI厎c@=,P˜è~Á”ãV‰‰¹ôPnzO𠬇t† ‚OrÁÌŒ($tHç ®8³dÑà²Ôavƒýá§$9¼Ê²`Vܬ Ákãí¶Qm‚$D*Fy—D­5½†?a(\Âq·0šcâR9W ˆ•—oØ)\ÉDË¢R®» Ú<è'?ŒÅð™ËñéÅøìâ4P¼Î†ƒ³Áà´ß÷ÀQ—opõ;|,§ëel=nÂk qyM]ãØ[†j œ1»ÙÏÍ4&¨¯}no9ÔdÝjð¬†G¿<]b4ãyU¿mdwr´=ñf›Ôhd׬YR¬ e Õ?ðqó¸]m·ËÝr¶’7³x˜ûå xcòÛ䢅gF"ˆ£Æ½kàdq?5>D`~?]MçKï·­¼9ç/hm5q4v žKqÏã´yûUëçNþ)èòðqââìfÅU->Ç"t8Ázé™Ç›2ØL­1ô™ GYèÄ ¶°Ì$‘BSƒÄ ->¥£5hµövˆ¦¿¸î‰·ßW— ¹ÂÕõ*”! Ç=PÑq·;ê6þåóÏe™ò%]O§³ëk§òÇÅh8ðZÁ&§^Üäÿ‹~â¯(|úô‰ôΦ:’užÖíuþÙð———Ñιäh£û$–we MÙ-›mÞ¸ëƒîù^ÛýDž£Œûd»ÊWìwÏÎÇã³S¾µ0äyRÜÃ%,Z/®?Þmx.áfrÏs §ãn»ùøÕ‡7|e”¯WQ1×WS`Κñޏ/-¦<ͱbx€‡yó›T›JÕ 6Çœ§ÿ”ì˜É%L&f’—±4… œ9mJºÀdþu‘ ÈàÔ  †‰ÀéüUÑê(«ˆ@•˜Âµ„#_CNLéΊ° J¬ºê˜ öX Ãb]O M/~>ê_ÅãH –¨Ã4ŽO1 Ná¹x°îd­ƒ£¶ûîûóùüãÇOw·wËÅb½\ŠíéxÔïv5fÞ½}Ûëv>¼ç;Û, àzvMí} Èø†¤(7¥ùà@u,XÖ¡ž¨G}¬c¤X*k© ³nI…¸B'¾„™8YBNã—×"5xhÀHÿh€9› ÒF™tT4 ɈfØ‹)ì3UI¯†gå)êbü¹€'{N âT’,Ò™]SZ™Ô“šV´ {­¬£iÁ¤™$SG–!÷,GYwÙòyƒJq­0± !‘¢ÐäJ©:¹p![\'Z5 šñ÷³±]ÆÎY—[‘zL £!W¸üD¿¯Ÿòp/4ú,^é|§KTæw2qµ7>+¬² è´¥?È{Ó„«ÊñbÓ:DKÝ"–B$OÊ Ì@ÚäñIBÚGó´ˆ(_¿:'Ò¡ÅE˘Λ´Ð˽½Ù[ål=xÍW1[A•÷$B6¡Ð,‹5r‰ò°÷¬­øÊ‚Åf9_ —i¦%“W{àØM˜/üÄè|âë˜,‡ R¸Q{ƒõjÍíî.cо$.€‘Û‚p«IÏÆòˆ¢ø%[V¡È1æì“È-êôÔ5ƒOõbZq¹å‡&É!”>ஆê¨(ÊÐÏö±qÔ¸ùþæqýM•Ú¬ t楼$bXŽàbÅ™AXfÈ£Ä<7#©´RËŽGܬæwæ+W¼M^[9MÉ„Ná.ñHò6Ò(0_Wu¸ XP$îA-1åë„ ˆƒ{IÃ1Õ\pl$JwqXwÎ &™F:$Ïô ƒPnµ÷%VÞ6ó;Ûæ 9mòØ´-Kuœ BÃQ~ÛÅŹNÅ4Œ»½ž Eœ´`ù%‚ÐóbÜå\ãF¨võä4ŸŽÏÎålñmŸ6hâ€ÓØf…Ëd¶ÛÇŸÓÕˆØÈ‡“G([‘xêFh=Ü)¦v!3sÀFaçF²K¦Ï5iX=n?öFÀÏ/sê—kÕC†\„Ž’²ùY¡Ã tVD8 Jëè[”dþB×+A)⦇ÂÖR¢ŽM)ö‹EnnJó¬òk¹„*\IhÌYQy@–¼Êu¹ç0óQ¤„­¥ Sz½ÔOÃažB%Ã>e"ö9Oã7f|ÂÜâÆíÌq c½]óm+--ß•¤y5® iÕŽÌ#3£•Zâ¬;Ù`n~­ú êÉ%|} %+r£j?ˆÖ(õ“rSLQÄι†¿ÁÊ«¨þᩲ1Åo$: ²•lúg0–â‰òLÃ6lFxxlfž $²šÐäÊu‹½#O&ª †e*@H¶Hî×”¥©1/Ï'ä„1¡m¬ B0A¹Š`B:>NÜ#‡äâ †;Î|ÓY´âPKHžm:µ0¸#¡æÆV£ÕÖòßä™r¶ÎFš´Ï/O/Þœ_¾­PõÊŸOå3\|MU‰ï¯”¹—ïÀ‹·Wo.ί.ü]ü³Á˜çº|%³¥óöðØ$¾Nºå¹.¢†L ‚&ð”}j=Ò J0¡Kìn+n–ÆçãÁxÄ Rûn܇'W y8ÛRR|^]ÕÑl!ë2÷‡®^]`/!ÜÉ£ÍRŽÚrÎ~ÛÃôvòp{Ïñú~òénòéöîãuàý§£Rnï¯o•{/‚ë»éí=o\¯ç«íB~ÛÖßÎ’[úmxGÇÜâ—‚èVR’Ù¤å¹ë˜·ÝJg߯p±Ûë¦ç2¡½´ú ¼þa–dD²ºÅOž(=Õ㚃=WÀb‰x Ü1du¡G+Òj-õÍjï›5šíïÈjrTO5åçtÀ†°ÛlÊ¿èwº\'u×› Óo€BVrâ7À%ÚP…BIAP°@*|ë@4’rE6¥8ux=M=ƒÒ\ bs•hÛ¿‹%ˆ\ó܃ ”ÍÚuæ–jùFªGΙ%_5gv6ãuŠªˆÜ¬xÁ„ôx“7VSk)ÅiÈr¡²ò¸Ä]ÿñüˆ+Üjt¤VŽÈ&-(ÀÙEn,ZFÜ6Uà‰IEd`â¨u"ÚíÄKfà–‚¶V™¡ŒÄV¬º¨G­Ue¢£ý*fO+)‰”Œ Kï ѹQ‚ ‰@èÖe#˜Žüî%ä¬/wç•{ø3YA–ÛûJe}Ãàô öÛ¥p­ËŠ}yfÚéÜÔ¯Î974¤dñ²Uyj¾7—–ÛÃ{•ë3œð¬*°ç_\ñ«ýX‘U”aQ6LQY_*Ç8MGÏN)#~^…()HñÏëÄ?a-rn¬C|¹c¶a–)BÉcAC& …ãèÀ˜L >I’Êç‰\…õ4ÊA€SP*•¸oõ«´“Cά|.#™ñÙ“Þà§bØf˜ÇMvkn¸P…ÓélµX^ºþþ»“û‡óoþ ¯Ï^¯dçïß¿?;;ûðáÃpä3§V‹F>>òHólöý÷ßÿñ¼½½ýø‘ëDþìUÿüâì?üþY»ÛþíoÓtðªÛ-^çê-ê Öëñx= _š;’ëw{s÷Ç¿ûþO÷wûoÿpÿý§ÆfÝÞm~ó«¯Þ¿»üÍ_|óõo¾:½8=Š'8›í]£=›o®ofóùñ¿þÿzù°ýÿü¿ÿÇ¿þÃÿ·ÓZ}õaÔkoþWÿËÿÅ×ÞžŽG:t×IŸ2Ðöq£¥Ú7ÇíG6Ýš'M)‚kÆéÖ7i ]•¤‹ ÑÙ%"g¥|ųރC„ ˜O-®HŠé'ð‹¡tt ì’S¹O ~ˆé!«¨=l¯?®Æ:…xÖ!ôŸ‡ç7³¬ÃÓâ{hÐq`ŠÓã“íñÉäa~s{÷ððð¯ÿõ¿ž<Üÿá÷ÿöÛ?þèpЗL¿ýõ¯FÃáo~ý«ÿÙòk¤_^\¤ôÕË*›y¢ŸŸ¨ú'Á Ý÷çðôòl×üü ·F3 „˜ç™h9E3îtÓB£<…™ÍœTõYtß#¢¸¹Ðî§>!&´ö_ˆ²²[³fH˜È}J ;M=q’+a’çÅlda*àjl@ˆ•j#àuv¥žtª@åÜÅï6j ¬Ó^OÛ¾âm2ýëÌO†I°EsÍNçñ:áöùõJ¶ÚòÉþ¯{Ð"íøœŽ{l~Dß/œóòºî õ%Ž5MÜï„/Løå <— t>å¥ê’Šc³-z-©3Ñì@šª."d }P³5„Ë€ÓQGžYpÚñ,ñÌ`d•ƒ)€ì±ˆÖ±‚,Ü!¢X‚iµìEx?"òó•ìCJ8¨€IËí«ažòÉð„öó~ ¾â×ëRÕ‘½7Žÿâ¿û±Ù&`ƒ-7³d¿u¯é‰ 7 ýDˆ¦$'¢/ýÈVNɄќ_M[©Z¶5‰á$é×G ñLÝ. D9÷Æ0Ér¤lw p¤FQîwËv#7  mûxs͆Á÷ß}ÿ퟾L&÷÷wbÔívÇãñåååÛ·oOOÇç½>ß³SžZÙlîoïïîî>~üøýÇïîïncË#ÎÏ///¾ùÕ7Ãaÿâü´ï-:Ô)°4ñ–D˜ñV’óÂ6bø<`;›Íîî&w7·7Ÿ>-fSUÖiœ\]œž /.ÏÅ\g*Mj"9n¬×‹Wt¿ÿîz½Ú~úþÓäîºÕx¼8õZÇù¿>;õ»~¿/g= x:ÃA<¡:~¤Ä̃- œm%G\ P6ÌÈè'dÈ‘ýDKïü@¥O r2ÏÏü3Á¾XE}ì¼@ZOVøE†µ¬ {…òYx*Q¦Û ÈÊ”&ôlÞØ>žè\q¾Xq/èbñí·šÍ¦óÙL.Ú`ÐÓ þêÃû³ÓÓ««Ë·oÞh0ëL†žkËb‡E¸À 2†<%s¿Ìƒå'òø¹ ÚôB³á@fE_E{Kõ”§àš!‰Šš)Á;]©>!¤ÙUaR)Ï->š AÍ^ÌÙ)=®ÚÉ÷,]¡£.îR´¬‡g?ÑÿôIDAT€Š29‚&öœ–«C¼6y–ÂÎæP`q1yäº} çùrª\Õ³(^pNä qg9³jÛo ÐZ*wÍÏ“ò&žäÝ~¿,¶øX±¦q”Ä–eŒE8ç°ú‘Vòø¥R.ÚVÉ8âëJ °·×éJà!ï^çÕüívG\TûNž›}2­ŒÞÇãݳ[Þ°+ðCàÛF-‹ì¬£G¤Bï/¹ª˜üP’‚Õ ×M@x°;É,…¬¹ÁÛ{˜Þðˆâ’  ­ŠF£ËjÛP«²ãk/?¸)·˜—wú£3û8=?ÇCÞÚ2îõ{½^7Ô$ÄÏÁ²Ðm:ºž8Aka£uÒx¸}PO,æ‹ùl.–‹´[C_”xTA•¡8rKI¶ ’0[Ÿ Rˆ,‡¾#9ôJa÷§ÝЀ'¾-ßC‰æE- ²d~NGèT¢¾ "Ëš<„`RÀzÏÀ¬Š®Þƒ 4 (¨®É ¯ ±,@”Ôé¢ ÔýY)³“:sVä†KGw`CÛÇår½ðG…¹³m±-+[Šîò2nnS Óá®j alf®7ë%·¶ñr›År¿è׈شàÓd<æâ m‹O÷†nƒ‰ÅA* O ƒqËÔ¹WHë#¡KP±H€Ì ó=¤`§ÁEâà{G˜gêú ðä·=`1‚&cJ+™Ïd9˜Ãdé’žWÉö¿˜ÜvCávˆðÏ ðŒ¶ý=Á/×´&‘,:“7àhÖaºö4­iY3ÿ»i |˳ð£~<äs¤ž{5éÇô(üœÉÌi Mø"ý¥Ü,p0bh”ħää>ͪCʵv\ć§šòÌp˜áù¢Ô’§éÒœœhÒ1F\7ö Â]Ká’RBYÐΉiµÌ4$:ÝáT >µ²ÌòB 0Vˆµd!}˜%·¿q´§):¸›—E<Ö¹oœþ²º7ãÉÞŸä)ÞºÁikñƒÎày“›Fr¼ø„Føü< ^¼˜ñíp8ä8 é“^tšä‹¤Ý~w0ŒN‡çWçWç—o./y¾õòì*=*¡ÜN¯ƒ‡‡K”ohëÈ= áZ‡â4èÂû2h:ˆçГFL—jð¿ÈU€ö!·&Ô«{,õ,l {SÒ§ µB ÔÑ~þ‰îfããý^wÐõX~?Ë ï7ËóÖû¦*¨ßµyµ'lUZñ”iÔ¹%õ³¸Úônõší)¨¡\–Sëc37\ó‘ò¼â²ŒúvõДâ Û˜ñœãzÉ$xÊžÝL¾[„Iƒ$:Ä„2Z[õ?üïP“Ð@1ƒµjOÞRÁ˜m=q ³të;L09@"7Ä*ÂdÙù( ôoÕáâX:rFÓDñ‘d$Y¿%©ò¡aT) M(ŸG? ò½VËõßüÍßÜÝÜ|ÿý÷×××Òl»Ýï oß¾ÕA®›@ ÔOòóÞšûî»ï?~üx}}sww'†r×TêW¿úú«¯ß¿ysõîí»Á` VªC¶Q«î°j…˜!œ` 8ÒiÎr¹yx˜óµ†Û»»ëëírÙï´Gýós»Ë³Ó³‘&µIóÕj7›«-GúãÇÕb{óéz2¹ívŽ?|¸ì¶÷»_Ÿ5uÈÔ±XÔ‚d TÍÜÅEuŸÚ"ÇižÔ¾J 8×¢ÏC"BÖÈOÄñ‡ág¨ëUx‘yT|P½Bìçƒ1c"Z þ°¹½O RŠUáYÿ¬eËív¹Ù>Ìæ·÷|ôßýí¿{˜Ük\ì¶ëN«yqvªãôÏþòíÕÕé)¯ŸgjSܳâ;-ÎarS2Áäi$äBµ´x.í4DsB3V²1§¡¢À=uå諘ø¦SI‰y)A ¤©?EœU0J ÀRR×ìé8XÀ"VHyžœ½ä(ìë¤ÍØ<3‹}ŒÕ=,¨ÒMŒ1T’¼¡b©š"&5ejž(ÆoLÔ!D4Òˉ…¦>TùjZ.XQ½ü c…iòd#¯€ëq¿×F•Àkº¼!¬þá&~ü5˲ò%`ÙbÁªªFz©„ÀòÄX ¨PÎG¯Ïûö»Ýöx8ÒÖ ^¿/1z½®¤•z_®Õi‘vwÈò«V¡ý6ùÌè÷„›ÖØÀs³s’L(k‹˜Çª1eÅÐ…]ºŽ†{KXõ°Ÿ`o¤†¼xk̼ü¬)ç©ÛAøÁvÚzyTƒÓ¡\49 ãs¹¡§ço®†c^Ú2ym¿#?Ï^5ÆeûB½¡F÷©xt$ÆŠ³±–%[Ì*Éw* ÑL¦"eoÇ.j(¾I‘à«öNMŒ÷…šNN SÝÉf»ëvøR¸†ên­àª\¤é|k†ƒÂèr÷¼»Û:D£0š|ÌCDŽ/Å}•"ƒÉ^¡t_¿ ¶“íÑŠ§Úš,F\D¤ê}«j¶~¦@¤TޤŒ˜¢D‚6ä T$JQ CÔæ®qGšC‘^MQBˆhB‘0Br%%Éǰ6G¢lN¦ ù2%Ê $Íéþ ŒT#}ü™ jò>Ô+ü³Aó¬<>¨iý)ü8ñ~°]/å–‚‘¶W ÏÏA29‰Ï §Á×H÷ è0Zîò &•™:®°§°œJÑÄÆÉUüŸ"$c7\ÂyÀ(±(¥P*T…¿Êèÿ¨ó¯Bî³ Ãá}nõ°Àn(‹ ”Ûí2“'pXb)Àt¯cT» î¿üGb½Š ‡öY¥ˆÐ'»`r„MZÕ´·b$P^]€:xò®˜¥5`z'› Iyb`zš«SŽNÏåhð¶0^âÚôuÒ“vCxÜö¦Z«ÉÛîšÇ¼G y¼km8ø'<¦‘>· d7)†jÕúGPuç[èÁt-´üÓbùÑRÈUE¾8튎U]|æÕWr# Äþø¨e×IˆðØ/´suZH;3¨Û'àÌ(PrxÆ^äy×¶#ÄÁ†'ý§r5`Y–^¼ÓæÞH»n\ÿô… EÁÀÝ#÷Lú.@²’n0¤hA¨,ÌØÁ£Æ_ý÷ÿ>¦½¹—ÙT!£)@Ô ËqbJÅtY“ÕQÞ‰úO…˜#0Œr¡kŠ:G10;@¹::°üˆáRâ˜f!:ÿ¹ LJÁ”Ã6ž—\~{oä†öóåjµ™Ïæ×þ–âïÿû»»ÛÙìa³Ù ú½¯¿þúÍ›«ßþö·>|`§k<ÖI“š§ŽÕr3›/îï&××7ß~ûíÇg³™êÌæw¿ûÍû÷ï÷»ß~ýõWçg§£þ@'7a±ôX6ÿÐ×ë(ùêÄõš·þΦó›ë›>åv·Û¬F½îé°ÿáÍåÕÅùù…Π†.ïgQ=NVë¼ßöwß/æë»Û»Åô¡ßm~ýÕ›^çä·¿ùæìtÌ‹O[¸üÔlÍèà¨~¸Šžm&i9G‚¦_­ÃSÊ‚ýó@ê‚_ ~®†µ< ¨‡¥iéŸÙp‘¥yµal1¸ê0¼”=]­ç«õíÃôã§ëûûû¿ùÛ¿žÜÝj„hrî·Ûï®.»Öÿü?ùß¾}Óï÷ZÏ'‰ãs#¦ÿÀ¹ö*-2—9ÌØ‡×sÿQ@ii ?„sîgˆA—pÁT6‡ùM™ s@Jަ£¢þƒuN!A¨§ )A…ævˆÎÒ€÷OH“Ìôt‰¶-!Ñ!Kip0Rë"G ÍG¿‰&2âˆ3è@t^}àáõÅvI¼¾©OûeÝÖ¿—€Û•ÂDkEÍ(!9 Œ²qUŽ¯Ý–Š¤#Eù|BH"FMn¨á]²]¾gÞÄ¥¢áPëÇh<>=;S¸?ž)0õ¢ásª-¿¤—}/ñäÂŒªÅ»Øqǵ_ã"™è½2ôOô¤é¶j™e;MH¸l­5¸¶/ž:……ËÒK¡fz’5Ò®“SÔÉǾnÛèjõ>æéÞ©Ñ?=?œß}õîüêâêýÛË·oε&^žiMì’ŸûÞ`ë 勹Ò=°/‡^µæQ«¨,º™ãæn³k5Ú¾mj-=jBS;‹›Ý[®cÚq•Ìf/†0d ×)µå³ÙÝj³–&¶Û(åBlwÛv·Í7ÏáŠ>•£šWtm̼#V¡3`—Ò)›?²S%¨ó8`ù´E+³~OÈ hΘ ¢ …$ðÐà ê^–kØlÖJÁÅË#p_BÜOŠ)Š}Áˆá©w¯;U¥Ô*Õnû#ŒÜ†Êæ¸ÛN×ø‘êêhR:†d¹w<¸dš tvÁ°öcÞI™¹a‰6ÓRv#“BØ€„©Èá‚ÁAåBS:Èök™{ð9ѧPÈêø~цæŸÃ_4ÅÖ ûDüy¨S ÂcØüöÀ)•25Ÿ0ú¼‘ghüª¡ ùðûßeLœ3±ÛÏ*ÒÒ<žL7ËÃM2æT¯Ê¤™µ¢H¥êÔûÂþã†<0SCêÑ~НçîaGU®dÈ"¼—å¼—°@DËúQðr_Á:0%fë¹”• @L­žúRXæ}•Ê ÌôvF\Æ.‰ÓMò…Lp Š'àìlç6õ°à˜ÙÅ Q$ê݃Ÿê8ѯÙ>!‹(¡½3å;Ù‹Ð';6OäŒøµ B^{ÝëðÙr¡¿¯ÐvÛýŽ}¸nó$ÝñvòØä!]ãh×<âž:r£›ª©cí¡ î3ô]ˆÚ'cý!Ñw!ÊÇ`óìT‘¹±É‡·¢6üT]óäÈ÷ØqïR^HÛhtÍnKÒrÁTG…{\Q=n«Þ³bëÎÚF_ž_P^L-I§å³ˆÖWy­BMXbËVšÊ è àf À—H¨š·=zÜj²íw;ïß¾Ñ(øË¿ü‹ñxÄN¼Š§db˜Ÿ8¤Š4¸ÿØ]î+'q±` ü{øIPuxÍ tûYš®úFÇWJ`Êlðêx¬D$é°—tô¤Z’ G”²îªY4×ÅQl΀³˜ÅŒÙÒ³²Aš©Ëebr7[sJ+WÃħ7>uOÈ–·eZ³÷ˆ•DN€È xê#…åñ–N¥Êä4v±Ú2D͈…–ý·V·ÓÕ2ÀÛ´Œ Ã7Šu»þ½Ÿ ˆ{Ú8ÅR€[ÄÌËû¬Ø¾š–6§xçÌJòŽZDC‚Ý43iÑ®¯}HÏwp‰žMž<8VÕ¾âÙì´O´Vá“ÝQ/¾âÕtãáøü´7ìŸ_]õF}?';èð‚+ž±c§ŠäÀJÕ °²IcY_¡=§ Jc)²G3øF¹JjHuw··r´²Z½Ê·o™Ï?±: K†‘*ee&—DùR¾’¥@|F³¹ÞP…M9ûö–ÊÆâ©€`'·ÖtBÔ—Âa¤Ï¢²Àär¹_Âo­ÜÜËîäìûªXö¬(¾õ0€š¢vO­+ë°ˆU *.RNzü àAÕj>ŸßÞªƒîf³Ùr¹G™ôÐ{Ègg§| ¾Ï½¥R·x°ÑƇ°–‹Ålúð0¹¿ŸÏgŠ‹{¿×;ÎNOÏOÏT†m:»zROt[Cä9Û hH¸•/¾ÙmÖöÇíïÊÿ—ÛÈ}®úÑ©¤ ú–ô­{žûFeÊ@95 T`ÝWSé[£hÒ@LòºŽÎP ž¾ŽÿSÔ€á? ·:¤D8«,×~˜ø0¸ÃöˆyÒj»Õ,·X.g ó¹&#¯r5¸™~ý6œxÞH£]Í5Ÿ*"£¦¨ûK¥\0r_àðOÊùÙ±@NA߯ç ÔíÌ¡Žú÷ä•!b.ºGWÇÃX:þ@îù©XNHóWÉ$+¤‰¡\†Ø½Áw E“n^Ó<'Ê´ÇmO„,ñQG£âÊ­ ¥ª¨7â¾¶Æõ{w® €[ ™˜j’ç9#â9#Cˆ¬´]m@ÐÜcÊóâïmœFë¤ÕiuûÝÑx8:ž_ž]¾½zÿõ‡¯~ó͇_}õþ›÷o>¼½z÷æìÍO›žûãAoÜï ºA§ÕK{ZÍ^[¾NU›· kikñ¾“£fóˆ×Ÿø½+¼€…]>0…u”/uòØô7cÙÉkPÄ_‘eo¯ÝltØ?kôÚ'Ýö‰Â½N«ßm ºía¯3êõfÐ? gZ•ÇZbGǃÓ飾ü6yxrûüÎŽG¿i› ³•R†¾ DC(04ަå&ðT„ÖYv%û\>Ö2·Âx:“I%aBoŠš§?£{®\ 2;m~OØjµ^®ýÑ}>´?<Ìf:Þ?¬æ Íž«ò0¾²øy¯ŽÏÑìè_›¢«V}X©ÂÆR @À}H²Exrò3€YQ‘UäÆf4‰gŽ;é9HÅÁ#-¶»S€Ô”TKôŽU øRçn¹Zù…m¼dO NœµÀô <ÓÖiÎ¥9hüám6›U¼°B*¯ykt:mj¼«ƒ*=N©8äà¬Äã‹Ä ±ÔfåY0ÑÈ/ îÛRµð™n½–@A=¡*š³J4 $ ƒ­Sc­p°³“߇à NzV+™Ÿòe¥M·x“N‡á RØg*FÀ/×Rðy€2Ö¡—iþ=|1­'Tï2B5w«g¥hl8ü*0À^bÁÄû/’%’Z”Rw= âýÜ4×<cxä \¸eqõNHÔ³141O'©Ô†¤“Ì,*=D73µ@F+OõÐZ[d‚oTcw°Æ§´zŸŸg²ÀÅ#tœ‰É ‘–¤»¸UXã×;9\Šã†µþD³Óìô»½QO.þÐéHîšœ¶Ó«³³7çBÆ—§Ã³ÑàtØõWY[ò¸œÚ‘›¥¥î¤Ý9étŽ…òášm{cé²éî˜ßmãê'ÞÛ±”"¯Î@Ø]óîÚQ§yÒmw[:6äv;Í^WØî÷„qûá·ÉìÊ? Gªßmvýýõ¶wÅÙN•WJ§ÂTñ\C¿YuIíØ§5äDõWé %‹Y³ÁnïLî¶å°ª.îl—îlDµ$Ýk~ MV€¹3æG.‰n8»Ýøw5›ëw9›-¦ÓÕl¹ž“¸]m„»õ–hmw¼Í­Â£Æùûß«ú´Õå«¥lܱgE‡+1A«lÞdªWO ‘>êÇ¢>}Ê q$¹-Ô€ $ž°uµÁ TCØEÄDGuKR1QW‘!mæÇ$¯"ì½L0a¤é(Ïl½– wr×¶›ÝÇŸîîî?}úô‡?üa6ŸÉõÅÅÅûwïÏÏ.¾ùæëÁ 7òU!Á6^Ÿî'××7?~ä ߯5s4¾{÷öêê꫆þ8i»nF³t˜nÈ`wbšCwûœHÝñzµ“G~ÿp7ùøÝÇéd2ŸN›'ç£áåÙðÝÛË‹‹³äÑIÎcޱ ^óø¸Xm¦Ó¥÷¿þÿ[ÌÖó‡Ùfµèõ>\¶›¿úæýh8áµuzDE»¢GÏ?¡[…}ªšæçYÈ9nYnENÙÏU×ÚœL+®¥4h;"úKª­jþóA²êày$i / é/ñ6QE 76ÿë¬BE¡+¡Ç)ÌUi^:ÚßÞ=Ü?̾ûøéúãÝÝí|6ÙmVý^kÐ랎‡¿ýõ¯5Ù~øð¾ÛëxS¡tRA…Œ 5 ¨b¦¾XëªÓÑ™¢¨ òŸfŠPS÷Ï ¡½ÂßÓR=1rR0kXQ÷“Ã:Ò{1´ D¹ÔCÐpŒ€ Ì>Û”•a› ¯‡åP#Á 2C‡á9¶Ø\­ãä€n™õc÷]·X2*q°"ùdÑ4Ùg¦À˜ O ­Éºzÿvt:>“霣Õñ×Ĥyü<¾g5Îî®o?~ýéÓ'•œL&¶Îºo¼Óvuyy~z*·Ï$°û§óÉÆç}âåæj°¨¡ŠØ¯ÆWK¶ì·m¦ó»»ûÉäáÓÇOröW‹Y»q|1^ß^]œ_œöûÝ&§ ¾ rtÄÆêîq±`¿Mgýû?.æ«ùt®&j°|óáM«õø÷Ûtž#ÓCe:@ƒjC“EQzŒ@ü|¼JZVÝH¹ÈB/ü²`Aþ=h`AÉQÂ% bضÒC?‚¨CÐ? {é¶<ÿ&„ u`À´_3&«ñÀ áÑæñèãõíõí仟¾ýÓŸ&:=l?Žt?蟟Žÿâw¿‘ÅžŸŸ¶ÛmŸ>òÚ"šÇ°¥?¸„Ãå·Ö)ÅæF±]ä€{©ébiÜ+Nh|! äb½\I§rÂu²!£’i užÀëoÂ4ò”@i£]nz›)9=5‘¬Á·¹aMª[†"W[AœÁnÏ`†ñ™:÷Ç8\ÛóT­aŒ^õ¹ëmÌÖQh0Tn^\Ø}‚:›ÌžWûb6c"Ö/Œ­ûðŒõsÀ³& U]Aé*hël,Fb Šõj©?åJv‰òâ–&çŽw¯eÂ…^å²6軪d¿Âg ÿ^á@Â×¥ýѵ|)¾T°õÄN˜ÇJDêá€ä 3O ÷²ÁmN@ETAKä¦:³­%&‘Xr ÕƒÈ.x‘ Û"‰ø/1I µ^ØL'òD¹]¯UpãÛÑ´îÊiS”ŠÔÙ'Ì[â*Zãd‡,t](oO“'wÚ?®}‹‰:cµ\Ÿ7py"QuqÁt»æ™ü69"Þ†Q…âSêf愽£¤Ð4cÔÜJ½1›…sQÆÁëÈK4 5Z!–×Ô.S@4ntU—« 6“ˆŠCp‰ÔÈ1ûBÖU©Èh†BÒ8’o6<ްW÷÷÷«Õêü£|°Åb¾Z/Uõ×_uzvúþÃ{a·Ûå}6r°Äf{$Ëç›Ogww÷·×·7¯'w·ëÕR#ãòâüâüìÝÛ7Þ½“ßÖê4xð³%Ûò¥Gý=.V‹õV]Îeh-xbëyDqzzÃDØ|UNf“ûÉôááúúz³Zn׋nûäâbxy9º¼:?=?mu;b­3ûmÕZFp²\ng9‡»¿ùý_/æs¹ôÛͼ×küæ7ïÛ­£¯¾z7ì÷åFÊ E'tNJؘ;†þEç_>r¯%f¬”TgÏ!ôfDÿiÁ³ ´*| ¤[MO êÑ׳êÈ<çn.ø$jH‡óÁO1 øì‘!ÆuÒÝñ·ß}¼¾¹ûôéúúÓµÎúݶÆÍÙh8Ö‰÷xø›_ÓÕÄÞëh xdŠ“ì—÷ãd©’< UeËÕYÉ£„„ÿ€ý¶Ï*üÒ_‰ PJ¢‡Ï„P`µGØš>D&¤„ž&b‹ÉIø©HÁ´( e@ ‚eH£ûée“‡´f*…j¹–3,‰È«£kÛÑΕëF–iÃñ÷^” î*÷iv0D÷‘‘”vÚR‡Õ˜Þ à ‰ád!«i5`í$ω¦g­ôu#H=u(ì¹Ì¢f1“ÒÈ4B}û5R #&Ê&i!†s¤Òqþð|—ßÖÛ–ËÕåé9\ÜúÝ :ƒ.4ûÞP~˜²xÅŸ4H›g쨖+ÖvÙdã3.ÑŽy.aؓӦõ”åãHùtÞ±r[™ì´Y?4ƒGû  ´èöÑÜ£¤Â*D‡Ñgàz'V¼ ¤¥…óèq¹\jâšO§kyløXkñ”ç m³Ù&Ç5±¢€Ù[ެýž3Ébw†šÔ+øF*ÌB¸/XÉŠUüQΉ$ܬ”ʳ¥ëÅÊ ®6«uã¯þÕ¿û¬–ãºyå¦:qN~«¹ÓQ ½gi¬Š¤BsZ„œB#7j!5ýf ú‘âyf qMü4N|ÉÚ»nQ ðÈ5 b”ˆ"f% ìÞ[ÔÛâñ*Ù{Õ‰Çv·bÃ+¤Zdf³Ù·ßþéáá~»[‹¸Ýi}óÍ×£ÑèòòòüüÜ:8aï•—½qëõ|¶œNf÷llÞß]ßȵRŸ´ÇoߨÀÇËóá°ÇgØC ²”â=n×';?ó‚ÌʳÄLÍkqò¾%Þêaòpsûp?ùôýÇÍjqü¸ô»W—§oÞœ^\žÉ¦íÎ¥‚æãQKæ´ÝÌæÛ‡ûùr¾þë¿þëùl¶Ý.OŽ7£aû/~÷u§}üîÝ•†›¤s§¢}N¦ÂªŒ•Ú *7%HIÁCÀ¹Ï™þ1;¤¸ÃRÀý©pÔR±ŸÖ±-aÁçGƒÏß„’!tþ™ Êg‰«6­µ;ý*D0jÄØ"«¦¡” 3wyÜÖ)RÜóžý6^ñÍ4¹`ÒÙ~ûýÇ»[6¡'w÷ÛõŠ—µ5ŽÞœŸ]]œŸ?|x·µHÿê ¸¤“å$’}5!€t.B†u §,r)þç£/‡"E ×¹Õ³~pŽh (í­ë!àÛUØ ‡g¡FÌŸ4_¢ˆÏ>Ó4ïþ{J–MÉuí#ö•ŽØAp HTea–*ZŽžY$“<°8Ú° úñ1­¢æC‚/eíbÒ–äÜTDé2ÜÁ Š]·i\ÄŒDìËbd¦™-hИJ!7+C’ ·ÌÍÊ¥ri—gÿ@‡œ£ ©&óÎ ¢y¦ú ,::(D’K* (ea)rƾƉŒª UKª/–t6½Z¼¤Wþ\«Ù>iuí^SÇ.o­N¿ÝéëØò®[W‰ræ:öäØrcN)ÞoSî°Ûêñ ‡Ž¼A?‚ ±ãÝ»–f |? áY¬ÜEµÐËMå^"õš&ÍŶbê–Xþ ¸¹èÝ¢`Ã_R‘AÀÖæ¨ø{WU\w‹ù\œäQÉÍR\žƒŠÉ‡«¸-R9$ܹda4È'nV3L…ÍÒDŠ‚ê•0)ÜF÷Àf½‹Ír#ï7†,å»6þËõ/¼íâ.£xbnŠR\6Æq‚*rù愲èx •0 ÁˆB¯u”ŒÙRn‚d[bI»Rª O:ö©üòtZC5G4µCÊÌtI,!OÝæÞ ×l6"áùj1›ÍgÓ?üá“ÉÝÇï¿LîUr¨s…^÷w¿ûíÙùÙùÅ™œ}iB,5²×ëÝj±™Í—9m÷w7··×77?ͺÍÖ ß{ÿáíû·oÞ¾»’_¥ÚÇ++ßó  ¯a ?+T8êÐ…ß&…ÉÑ^/f‹û»û›O×·7×úÓßíÖíöñøtðöíÙÛ÷ç—çýÑP^!¯â{”Ö>:ê¬WÇÛusö°¼¹¾›O¿ÿýÿo6h”µÛ§ãîøü¦×mŸŸvüR’fìs ¯<Ž3ZPch“,ä}ˆRÏ@²„ö(U·Sœ˜rrU-C=,øÑу¬¿' _„Qäóá°ˆ[]z¶¤×´MZè_èÙÆ]4²}1©{0ã}mvËõf:O¦óï¿ûÞNÛD#âh³Ñ¬ÛlýÕ‡o¾þpyqöæêB¦çÉš4ÒYz>ö!”Í€å˜ÅôL’@˜Ÿ‚6¤?'d±€zXpýRx–³éõ¬gÛ*z Šn÷á¹ÔzOê‘§|4K¤Ð+JÙ¦ŽÖÏSQ”XË¥ÓRBp«m®•¿å•ˆÕTæ†Íb^¥£o/yÃ)”¬¼LÚ.ºª0G•Íñ$‚iâh•é …r''&A ešL}ÌÞmù(ŽˆÜ£X:Ñg á ‹ ¨&ƘÉZ|/ä^(=Ê\X-TÜ_n ç¯&Ï÷>ž¬7[?|À*³åjÁƒ|ÅIÿÓùz±š+0_ž°õ”0@¦ |ܤä 8©üʨR8a†€žÏ ¨€ŒÈ«€hô?^j%ÍÆ èWjBeú§7¸ , E×!ä°–` <È}qW˜¬HºT޼"!oËHñS®Eòe¨ÇÇV«1乬§3è4ÛMü½ã#vè¶»Õz»àÛSËùmwÓÛë‰Rtã¸ÙÑYWí;Ý®Ì줉•û-ƒ|¢,¾RæKIâDº×Ü}Y?Œ%ÒÓj=÷-úq ù‰ëåãv£âêrÞµÛ>9iqÙ• ¸GA]ÞØî„Íí¶±Ýžì6Ç»ÍÑvÃWÏŽ×ÇÇkÞSÍk«cï2Õ'kQqd0Dj’Áé9ŒiýN@®»#•ÂæSûj Cö£CÛ+é*~9ˆêþ<aO_Œ?¢,Óm 39÷ÓK¿Òzô]²­–Î!I5²Öi˜­6Û¹æ¨Å|!Óíñn§“do°µ4:4ûjVcå fIÛÂ!!202fI3b²´uü‡?¯0{ -…:Rð"]*KZ¾ ©÷}‰2÷'#´t$ *âĹtIÆÄ'Q†µD‚&έ ƒ~R*á>Á!Š•™=¨šã:'SyÔeyˆV³½Hi…·1­ºL8a*e3NOYn»ŽéVaM|ÊÂã¾D…^u3nÐeõº²dh‡èEgã™B=QjÂL‹W¬Mb<‘Ad,¹ÜPÅ´ ã} AÁ…r)P§ÀÓé±£¼ù’IP Úq外?%‘«U¼ã5µýh9³Àð›G'M­<»£ÆöÜ·vÇíÇðè¸õØh5:ÇO¸ÄÙæØì6Z=°Ýk[­^SØl7š¢òJ®‡Ë âöW-¼Nân˜…¸j¶Þ‚r’—â¶Sn'*J+@º²ª°K5Þ}AwxñÓºË6 @*<‘0­“v—=ÂÎKÃ#¡ª8¸²eʧ¡xÓpøm`äÓñÃÆãb¥f6•Ãöð0$†#-/§§cÁ§Hûá·If)Ãח׋Åj:ßÞ=ÜÞÞüt=¹ŸªZ—“߯·ÝüÖö)mñê8ûWî¯ðÛdÒŠôbÒtÈè¢i´Àî¨|zùmk5[*=áÝÍl‚Êzâ5þW)¹àXÃv#ô§±øº=&.dââÕ6}ï0Ç›:‰² ££ÂÞbÆŒæµ,£g :˜°êw8õºHÍ'q((ƒOÒ…ža¨ê§¢ ì'EM!ÃçG.@,‹á~!¿†õh@=ZŸƒP¥ñ§€†ëœë•šÔ^AÔî¾Ô‘ö“¶/ODÌ"åÃ(J€aÇœˆp>÷­üi+¾7"»Õt§B:=m5u£ñ°³¯3Õ ®SÆEÊ.Y‘©ÓšqÅ €€­5¢ú­Œ&'ý=@ÈWð4Z‡W¢QP<£Ë D´ÞÒ  "·D…%úsUUÙœ¢¹$uw2•.Cä1îR)!nc0Ì£ÉÑ<ÇÄ,‘e¦ÚBôD-®•:RYcªÃrU.KL?¬‰^£H°­K¥É2Dòæ [ ¶Áô@b ªN ñ|\ʉi’¶ýƈ ¢Xƒ¬:kÒÊ3¤¥Th¶±Žy•UÐ ­áHZO¹~[@ÕšLÖ‚ëø Þ)VâL+×g½8PFJ„¡6÷#ö3<ÁpÓP]®VÜp0}иЯN64ÈTB¦êwU¶ÚÞoó ²=1 £ ôâYI¼/·êIÀÔ«¼g$#% ÿ™H‘ Áá'À³D£J‹ž8ˆ êœ#üJ@àô`öÖË’Q§xàë7+*ë4N©ÂÂÚ1CÃ1W˜ƒ' ôìzI÷ú•(mM5ÜK‰x=…"øIIÌUí! ÀþGdٙɂÑ"Íf"ðLÌ™v&ªö ŽJ…‘î‚)ÅÍOµr˜‚´ÙÂí8y½ LàuŠÅBR»¼[lÀõ¢¥¢v¬r8ò*·€¨­ X ½q„¯€[ÀÚY(ƒ­}’(– 5Ðh`°âãún&–’$uhZævr½Çe×Mƒ›ý¶ pݸ3BNØ »ZX’Žñê$GMEÜ5áí„N¢·¦aá>¨^óAˆ „Àq E‹{Pt(Fq É*ñÃ(‹6ÆeÐV£ÝáEu<-ᯟžŸp݆Ý~OnÀ±?ÌŽ¢ÎlñÕ¢8mt°•ŽÄ19ˆ©B˜,yëåzµX3/æÓùìa&ÔÉEH©‰fÐZI %§ÐóðL®’QžÑQ¼7Uá#”E¯¥ˆ£¡ÄÁp?å`׿Eà]tQƒo—ZpsÛtº˜Îä ­|³¡dR×È™îzñAR-4QV–JÕ…GlÙEš~¬¦7T²ÓíÊ+—‰GKl>ÑBËa-×U‘šnARMâ/y|WÀëED¥5¯-gßK`«ÕVÔ¥=ßhĨ¼œ6»–Þ«ãZâ¤:A>§ÔØUŽ€\feÞ Á‘1’‚d´c5*«KC4M^e,”%œø@É­¥„ ÷rë Kø‹¢ ?‰f°÷…¬Md‡)…U@JÄW0Sþ\pXÐÖ‘¼#¦'Z½) ¦|w9ˆzb#^ËTš ´DÙ‰ZëÐJ~Ûr¥SŸ¹mSÍ.X¬lO&&S×¶ù:)F+È–¯Ÿ8#{øú×W` ‘@ É£Ò%“Q|êÑ¿-ðl4RJø™b|h^ÁÂ3À’±fº&³yyµVº‡v}*p´æß(U(­ Q“^E3`@˜fô<ÅŒ^dû1À"ŒˆŽ+¯°R€°³ÈL‰`@­Rƒ'cçŠ:Ì{Ϩ!Ϙ*‹Ÿ’’ÃæQÂ¥­9|)…•0FZø6±Õ!4¬ÕÚa÷"Y€$›k ÒùÂ9ò]&„Œl#í6Òöä}šVÂxxžb¬¢Ä-‰•€5]¨ªÆ"UiE@BåØW±È nSF˜©D…fÃp7­ôèNÑ£k§Vá¶Va>>>ór×S>v6úÃ~·ßWÞI|h+ž;Œ¥Ö“—ÞÓkÈe[&’ZÃESÔAäÚ·9~aÉ›!VÜß–š“!$SéÃÁ0,P ÊRÀ[q…r_pÓÝVš+ ÑT?ƒ7÷áÀH¤­­ `œ L”™8…í¸Úwõn˜ŽÎ7ƒ8ZYHCuH'¯È~WtpÝf«ùBq‰-slµZ‹M§srÔTKÅWƒÑ£êà-+Kn‘ã‡ÎÔ‘ýA„ßÖïx—Žž°.Ÿ3³H52ÐÐÁ>ˆœó.âWË-$ Wüžy\¼;§É÷6$$· yÏ,ŒÝ},`ƒ•ÍÄä·m¤SY:ææo{ %-~[ 9˶§÷N›¬2ÓüKûã>èl•‹™ÝrboÑÁ…-”ydÂ!AˆŏmúÄù—CŸ *@] BŒ„r†0Œ&±È"éÁái4?Öá k£4DM Åúw l. ‰JT£€lMåTweÒ‚bN2ºår9›.&²á¦(rt_Š PXFë§Â4P®²_ï^8‚”îb%Z¥¦•þ‡YOðYPɬ‡=8 ÿü¨ÂUÔÓÁ>¤† “e¾†€8¼‚iŽÎX80À¹ É6ƒ; væ‡4äA¬§¢7J¿j ÖWM T¸7ùàâ@{lª••|sô¸á¡,\BËP–4ëâ†Xl„®ÂÞg†Ð½9Õ½íH,C:nŽ2óK×è¡M‰u0’Á¬ÏFqn%$%µÀ –ª1KƒÂ‹ £Ši™B‚Ü-J¡ý¬qßV2. qxXk¼¨‰Ø¦LU'L‹–¹C–ÓÕ»ÖHkýº-VYÊ3¦(c=iUËOƒ ¼¸`"¯…»Ø¬U„BÖl;¬[ëD2TáV¢<Ïj„5d>I-†­Ð@÷œJ×1¹öqÅݲ!º$Õ$f¿wòóZþÓS¹nãñX>C·ßku;¼ ˜W5DË=Åœ=6ä÷¥±¤áÀ1f:†IÖTn@ T‹$@ìÃp Mëºü6·žRÚBaÖ u®NÊ:ÚŒ# ¥ìAØŠ¯}H1®=ŽO!ÊÂâe2Àödz5— ª(,•Dp{š"ÕÄc‹Ý¬»Ynõp0¸8¿àAͳ‹óÓ‹^§Ûj4ÅŸ5å’åœkAÓ‡‡ûÉÝýBZŸTE£Õê ú|d©ôçG:íŽßpv„ÛçÂáÙ™šÎå´Íg¼ w·m4ŽÛ¼*ºÇÓú=9ãrÉC< O H’¤K­@sú±C_ÄHBÕÅ;—r+W²;ui 7¿©ŠäÀÉ ãñrw­t]n¢hÃsã7±TÝœÎpWÞ|ƒ‘E²ålu›žn yÉç:+YrÝÜñšU£½ýæÎvs—gÂRÄS±?¹}5%ZêLCu×\,š¥KXQTáƒh ƒI˜gAéÊ-€x)Ô åëÑ?3Īê‚!}]SH•t„ö –&«£ŒmƧCc©i}ƒßvÒà–_ShéèϽ¥Ù+Ucp˜)ÛB¸~ÎÐuŒpšïÂn÷Â&˜–$a´à—Æõ¨uIþ|˜Ç©0 S„qoæ¡åù¤Bf€Zà)²¶O™¢LpÖtx…ÅÔ¦¦,yH•ÜGé¶U¡çÚÃ. û, MmaS‹Ø ò–ûÌÍU¸”˜ÉÔñ2rŠ0Âv=ÄM³K˜ô,®„Lk«%µ'kAm“È^D$‘Gf´†IY„òÀ "E“. 0[Ó»«]{ž}Õ$ƒÖŇ¥JÿîŠ@_ƒ½Æˆî‚YßN·¶àÄ<äD×k™]K쇸]‚»êÂ=‰*œÇ–h‰ÚÀÈ-êF§êX¢?Ï/ôuyÓÌ-J.ÍiBÓ¬&·ûªß/ç§­ãïèóùy¿÷H¥w áãŽýDaå´Å¢,¿¢…E:‡"¯¶JŒèÝQã_þ·ÿ\¼<Z ~ÆsÒÌ©LG#7 ¢€µÆ/ì,ÇSØ#Oš‹c€Ó€BÇz4  ¸ç· ˜Øe£Rl­Å:9j…YÌùÊÔíõÍl:»»½›ÜO¸ó¹ù›7Wgçg‚÷Þ«KºÝŽø°"q9TÚZŽÔD%îînon¯?^s²Zöº³ÓÑÅÅÙÅÕùùÅÙ`8hwÛ'ÊÑVjO¸íòæÅi'',MVà K  ±Á«€ËëO×÷w÷·77··7ÊÓ¢7õÏÏÆãÓ3y÷C.•6[ì1?žÈŠÖ+vÈð&—··w?~;ŸOîv»e¯×ê Ú*þù[ù£á ÕjÛ 2ÖIú³Ø­÷˜1éš{˜Ð–„´÷‰úQŠ~™­œ§+PFYÒ]‚ŽóÖ9FXÄaþ KÁ½Þý¥àЊþ AÒ-ÍKMD«u¨ZÎÌÄEšèGSùÈ¥SÜ+î*Ðóêãt¶˜L¦J?~”­N&«ÅBÓLÜ‹ùþý»Á°÷æÍåùé¸Ãm™ñI+OºYó ¦Aß÷F‚þ©Ë(P…½ q<•*âªkÿò‡¨¿ê@%õ±î ê8`*Ia¢ÏAáKÅÍÀ#6Fô!=]˜„t&Lãª0ÍvA]ÃD@Ì9Á$åF­%à°ø¤2>(ŠŽ*JWMJ#lÅY^õT‘)et¬ÕJD³O„B`(&ppžŽÜ»ì@Iª¢Iœ¬7êÉKŸrå@Gj¼âAVh UB³fV@iÔ”ƒU©'õ*¬|F›¢úɉ€‹îÕˆ»dosbÀšÚ|ÂRBbR`Q ¢ì–jºÑP7ܲ}„HDWé c}R¹ãÝõ0BX/`æK ħ&‘ÓoâeAàG§hbbŒ¨û“…ÝbrU2ý3y±•Â{gÉI¨É6E!q[cšè„ò¯|í5²¥d„F* #0@hÕ•¤ûÕ4œ£òvw¼¯Ì‰ÉÛÅ‹·‚fbû'ª Ê@RLgo´z› T rƒ&7ÜÊ䀪©cU{ =ƒ»uj G›ó…OœU)póÛ¼\…Ԃ㋉«åJÚ‚»Î ß—ûû•Vž`UÍ— #†9Ãü=–3z}d†YЕ±\Iá½ô˜XÌ1Ž`dÃLȺ–à_Ð’á½±€N'™(é” ñ‰‰öq îòÍÑéö./B^Ï\Qª:++ª3’eyj8$\•×5­G±¨íáä¦Å4EsU¡)Âõ ÷Ó-4‚”üJ}… “UY©Šhž†$±å–Wê´ñfZ_¯¨ÎùY¬Óä"úÙî©£úÍr&ºè‡ŠÌ4%\LÕjDB{)IæP¢f«!§K¸IžbP0ñOà!Æ;xÛîކãÓÑ©ÎPyÈôtt6æ‚é°ßéuZ]?¬ÐôS£wݨ!”n®+]"eÁT©«B䨆¥‡»ÁÈ•Â`îÂ+KUq7³O‹@X[#ÂPJV,Û]&šØCqÏa’àOˆ³èÖ šI€8Ä )ÅI$Y‰öÞâ% så‹ÉñŒ›MyEr½Úí¶™Ç'­Ì'™©Ê­–¼žj¾Z-¶¼¤WîÔ ï8à›‹ív·£5*žÙ”¬¸>¨@è\ÔÑiQ‘Ÿ]ñEeCò»Ø­Ð¿ý/Ù’'(Râ˜Ò>µm)“TKšZ;;ømòöJIE º“…–™cNäÂ%šs@†ó`AW[G~²,¤„¤áo–DÍÙ<q–Ea/-^`~aT†¢Å¿ ¤(íúsbÃøçuÄs–‘Ö)=b!®%Ò³î\ÂR[ÊÐz$ÛôUy;m¶9?Â,æšš'rØdu6Xtr®‘• N:Ý2AÔX–§J”@ hb@ÒðçcfþEXà ý§ã˜!‘W1iÌãÛŽ‚Ïà€ª zb¸Tâ$ks™ª–òŒú"a==•,ÿª² Ã×”©lDeÁšmlœ”ÊL"%ÍE™‰³¢T©+s«¯4 L5‹žRiÂL)`!PAÍÚÁ!šC½Ôb}é¿äg×!e’¿‡fVÃ`ÿ|¢y·§""ÈÜ2¥‚YÆ4ŠUyf•T“©žÈJuRW`01A,²@8°ò¨%JŠ0Æx„sôøˆ÷›¡f£Ûˆš¥U¹JÕ¤L¦zÝ[ ÈbC…--Þx;ˆ¯”l\L³\7gG’ÆÒ"‡Æ±ü6Íq¼¬ÛíúƒÑp8NA¾µ:âÖ)>¢ßm7»rñx“ˆ¿ßÉõO  c¯„fYÄ ×ö!¦J¦ÑÆÿé¿ýçZȽ¯çÝ:åúÀv“ÏÙå3V–· Yùƒ–˜=•e :Šþª¨T¸­*š¡áT"…[=B3I˜ËùÇý¡j(æä| ÉÑÙÝfµæéÑåêûï>N&Ó‡‡ù|¦ÕéÊûj~õõWggg= /ªµÊÚøIR˜ñ^ŽÙìúÓ§û»{ïÕ-´$õ½óóÓËË‹‹ ùØc¹Û¸Gã ¯ì[ov)Ö¶ÇøÇÓÐ=:ò[BŠ)cÁ’“GTy`d=}˜Î¦ß}ûÝÝÝÝýÝÝ|:íuÛ§ã‘øŸ_œòÝ~oÐUói÷76·ÇvA7w÷“Ùtv}ýéÛoÿ4›OWªÿì||v&[êÿê×_7Ç:38i4“s”ÕÌ;fœ"»±Né¿4dÈIÊO 6FÌ£‡þH™Ý3ô£úב.1$%¦AVC•€›‚ö¢Á·­Qþ`”X¤C-((±R²Î%rŸÍìsJP'`¼~Ï‹*,(Q„Ûš’ƒ80 DéÿÐÝ‚¢­@—•­Á±Ù>®Ö›ùbywÇ×Ho®o>ihÜóMRw¦A¿Ûët¿úê«á°qq6õ}‡›æ:T ~\Ô$Ž‘ê1íéI Ö§cRæ©t P0z4¨RÔ•½D)x­ÃAnÀAJD¿ˆ­H Q xhæhä”h=X†[zîç@>0RSԣ׳}ä†ÐaΕ-iÂË4Jbt@ÀIƒç§"ªí™g0bþ1OÿëP‹š³£6ÖpÑHO•Æ’Å‚’¥‘hõëõ;#É>A! #ô¿X]¼à{½OQoP¸ uœ`…8 ’ìE« õéG™Tap4Ad=I)‚’fäÀªƒ€n••§L[ª.Ú¡ì¬>«FJ5MsÁÐ’aQ­5#TÁ=h¨Ãà`p)y"ÓYl]* ˜[@N2$Õêîݶ2Y:Csw{Ò/I^L”‚œvã,aH –ª£ŒJ¹8³Ó1nbJ%‰L[ܘfÿˆ›Ïx"V>’œ%Ü(ÿ“[€ç7Vr­gK›í¦}%Ë=8á­-.±žø{JR¡4ýÓŽ¨$<2Z@eå@T”yîÌâ¿1¡ ¬×ñj)A/‡‚%Zr÷x>Á:e)NVz >Å è _Øßð"[7PK¡Üíï+:(ц%J³3+¹\ìÀò¿TÇIãˆí„N«ÕiFǰšk t,EÊä¡¢ 7ªØH¶ô™²Õ‰ u‹;sžÀ2;¦ò±—Í>ˆšÆS¨@ã¨É%+ßZäu3ÄH(H<„¨MЍÊU(m¤ÄFiöSD¼‰Ï•䫨Á¹N)TEëуÜW(_*ü ¤<ýLxZð Zà•h„?3Z‡zº”ÀÙŒQá/Û„F—J3ÈnÚ4»0Ÿ5ubéGhöGÅÀK ©C½C Ô£>ˆøÑÑ¿”+x=«DJŸÂA?Šü²âx©`ʈhš˜]ŒŠ:ÀŠY pÂ1Ò+)š0¥5`/ e©ËsgÊ «ÔBzDSøÄ´c$;™R¤Ÿ\Yž-A-  ޯ"øSû—€êxòÜœx:œI^ªZOE &å¾ (a7·È”û«šÓJÊ“z4C)`§$ÌžSŠŸV¡÷@. Eª[QQj¢)"))A91ÿfØ‹м{POІ³ÛvÔlœ´åð-|>„Õï¶…|G¿ßéwÚÝV«Û:é4O:­£Nó¨u 6ޏ=ϪA5Á`ë®ÀÇɶ®0Ðø?ÿ_ÿ9>¢Æ$E¥‘¢c]F#Œ9`@:†‹q9¥§ÝM¤gÄ|¶ÍÌîý»”E’™9|÷!Ò ‰ëŠt@}â’‡[m&ö¸½¹Yrñq6ßßÝéøÝŸ¾}˜<,Kyï­vóíÛ·£Áà׿þõ›·o~ˆ—»þ}q‡«¥«(ÙN¸»ÿ¹ÏæëõZ4 ÏÏO/®.üD‚º«ƒhþ:(g\0²Rö–,㤑æ öFü~¸ߎ垴åýýýÃÃôÛo¿ÜÝÏfÓÍz5öß¾½R—Wç§gãn¿#™aG<:Õ7çáŠÕííÝtúp}ýéOßþÝ|1ívæÑÕÛó««óáhðþÃ;õ¶Ä–ƒÅ¥'Ðç1ÍDô¿èQ±p †f©Õ¹J´2R%ÄŒøÍõĶAäBL‘‘eYЕc?#±%­§FþL:+ìh"Èé)š~ü«ÿ­ è +ó!”õ¨ÉR4²ªGSXP§Ôùäh `ÜDAJJM%é3ÔçvRÐy楰–Lbš O6ÛÝz³Í—ÓÙííýÍ5ÏÏÜ|º™Nî•Ý<9î÷:§#žÊþæW_GËó3Ùž8£s1§B1óðO Ó b&IlÂ/)×d9 ᜔Ò#ZŠÄO=j¶ñ (ìÐóQ Íe (\¢™m <-3vdE´€¢iàìÃAŠÊ¦”Ô­*t£>JQó9¥’Iè¨8lÃGaö ·Æz  ¬º7®Ä;nF0',¾E8A긄TlzŠç0r1e*5Ã0"ê2Š‚äX‡‚KBsv™·Ô¤TÒ2_dp +õÄ<ÎÅB"Þâ1[GŠº*ý…ðI'8‚[„=pËÈQňY ˜y*d†à” ’´ì µHÁ„Ìв‡.n ³ôeù‚ .æâ§Ùn7¥ðáH.´=,)·åÃhXˆé`(-^íÆÉPºªé€–>^+’A‹¡–E±Ñb×h4:NW~zONyz9M¤Ú,yƒÓ¾ß¶VkãV›wš´;þª·Œ<-½hÚ£­ÐáÈŒÅ2ì67@‰5è1'ºM‰÷ªTŠG8•†,j¡ÒŠU$ÆTñK€ÙSCŠÈ{ሆ€ ŸäÖ£u<ÈŠha"xš[‚z´„?'ú@ZaZ\Jä~ÈIllëËìl´œi€¶9ìXK§f°Ï4:íf§ÛÔ\ÔÕÙ¤Ü6±HÕj½ÁtéåHHà:©ÄµE… Uúx.Ê©ušþ¢hÀA´YÖ,UOS~X?e 9`N4 –} -© ×9<5aâJŠ=E‚ C™|ëÔF×a÷o åÈ”URJz¦4»’£Î HáŠFà°'Ã:¦I¸DMZYW˜M,å¶qZY!ó²)…@„5êÔú|XÔLIÍbŸ1êŠ"¥T —” ƒƒg:“q_· AðLUyã%-yšãä7NŽ›à‰7Òäõ†9m£³ÓñÅÙÙÅùøâttq:< ÆâÒŽºþ8=/~Ó*ßi·´x7ä·5ñÛÒ#¨r íªq^ù“nIÝnužL´XO¡ÈH©Âþ-©Ry³M4>ó ˆ”‰.S¦HŽÖ!¥+'!•ß¶]ïx+ÆbÉ«røÎÁ½Wçr rí5¦u:–VÏZ­¦Êjœâèñjܨ…?—-TIqP‚¼#9Cý~o4îŸ_ð,B¯ßm¶äfkb’£H QW(#k#& )^®¡¯iã·…“%ÿ}‹e<ª8¨~¥I$l5å±õú^ÁÌUN>¢…wJÏ% Yö?òBÊ×piœ<6^½ßFÝúÇ7µ‰a“2´äÉ!­íTX_½ÝŽhÌ^ÐPR÷0lº …MPK|ýS¡7Áa´¡—Ù‡`í¼:A-ùEøA‚× ‰”f„˜52˸Ô£%ü9Qý¢—¢˜ý<לÁé{)@¶2ö3Å{“«æ"Àè¼¾ñBs…Éé,Ãï ï¶›-Ì^6æ±éÛ2/ÌXHij¥… Ôa?¢´ÆrxþRNí~ø Z žR ¢‡ðlÞ‹Ô÷|‚”ô$"È >…* ˆ:}=PO¯Ã+YJFå`;¥Jt¢X#Ì|\­‰ó$i4y=rèô´C´—åù„m¨#V„ UÔôq[@“¤ ÂTa½-H…s¥^„Ä„¥ fn0w^ $†§kfì€ÄÑà‚ô¸ J™}ÙÙƒT¦>p © !r#={‚»0<*¦†à Ì(irÛ·Ê- $ŽhôÍŠ€ûßÎvh)ª®UWA´Îe¡£@@°NõŽf¥*êÓ_Éæ«¬è~¿„VëP2šÛsÊá¼á·±7†ßv®[¿Ûå^œ^œŸ_]ž¿¹<¿ä“LŠÊòyÓó³ñ¹¢çýñ¸#×MîD·#<é´NÚ-yo±Ó¶kà´á·!]´•±n óÂXAR™#Aš¡(ˆI54Î6$:18ˆh@Jz!QZE_/C*`HIÀàö¬ï&ÚÌé] €Rdºìfq¿?/>Öð匲BœÚ(FGÃåóz*?/Òh¨“¸aL'§”(‰UZ£å&#…¤ Ù²xøë)Ka\¹õš‡v%ù% ^²ËÕ& 7 ŽvaAŠÀ»VÓ@D?âK ²RÊ "‹«ÑAàÚùD²1š7à}Ri£¡4f1Ì­%87\ÄgÐÍbµ¦L”}ö³˜ýS4ê^& 1^ ÖþŠ6>‚O:Ϩåõhƒ¨Âõè¼Ü@± å× TJNJˆ>Œdu1û'Ù LN*cӑѶý¨[Ì âdÈ}…À¶}lÂy02ðcvVEÚ‰Eäš’^à€ò¥h‰ž!"]Ç:èR ^€DôJgQµ£VN¾Ê#ÈØY“€Ò¨çâ.¨¬›U¤ZžƒCƒ)F{‚tk@ºG«Ñ}žr*è¦xå08ÕyU”ÀËjn`ŨB†2Ì`œ(B=ˬ1þ¤Ø:+…÷8›(â jYpt AÄÑê~º J R|"½ä¾D <ö`«†*FÀ¤_‹ Šý €x§<.»exTX&q;¬ µQÚ?ÏÊ•f”àéRÏC]HÀ%‚{d…e`‰aŒ*%1`U)ˆU/ðäQmjhÑr›Ng alµ:ív·Å»Ã»mnqëøò¨wÚNÚ ¢'-M£Í#¹n`ó¸Õ|Ô‚þü¿ð½Ÿ•Mdzg*9–ü±êã.,!ö¥âN0 d¡èõ‡”"ºH4!‰AÑ:MäDŠÀ±°„—Ó‹ê¥bŸÙ«>{°X><<\º~¸»W@ÞQ¯×ŸžŽOÇ_ýu§Û=çËb#µB3™¦€˜®Tn±ýþð‡éМ3ô¯®.ÏÎN/./NÏÆ£ÓQoРàrIÐÝÝÝÎæÓFóèÃWoÆãÁ‡¯Þ½ys9ö.//Ô(éU²Ps²Z)êD>¬C£:àp:»¨ØáœmÈQŽ9mD4Î¥¥`(E”˜B€Â‰Ä?uë5Œ¤œQ‡à¾Ç xšRç”Røµ"?¬“¨Â rüæÜ*ëi´^ð *(Q;±Òº òHÎXýuÜu.ic.8>jˆ¯Î+W›Íܯu¾½›ÜÜÜ}úts}}{w7YÉ 7ëñh0ô./Æïßê¼òô«¯¿Ò˜êt:ÙªA.ž˜k,k2cÀ9H}L7PU‡8nq§%©žgºÏò¦°ã7¬½Ò†£¤<¥Œ”ƒ¨CUu%ðËÀ³Q%†gsƒéóQD HÑëÞamN/GÀp;ô;Ùç•L5žÿ<ÇC*d‘Ì‚ÛÑH;*~|.Šû'n¬Ÿ™ChÒ¸lp«ƒLs«U]ÂâÀi½!*õšÃºÖjó¿ÂÑìUÍJYÌó¦Iœ¡#×§Û¾#ÙuÊö8Fó¦qËhª ‘"W¡)÷ä¬ £FÚ–_HáRIÓjàª]Ì 2JTíëõ:(¹Ñ¢½¦Ùp˜Qo.S®ÖefÙEµ ðTbäš¿Ë6[¦!Ñéñc%Š,„±" €)šRBrä@’íç„ÏäR¤î{ž•¹@=ðBxY' ¤ð²–B5‡Ü\;±T»/ªWÅUPŒ*=+d‘ø²}XC F DC²:e¤@µx]W.K®¤¬A,oB…œ³Tš²¢hnT²ÒÓd#@ÕfÇD“ù<¨Ã˜”¸‰OTê‹_¢ÊYOA¤~Û?A–kå7Ê r” ƹష;$£&ôúœîÜšö‚Ø(Rw¤° r3DñzÕ†šQ© ÷¥ÑÕOtV€ŒÔ¥ Œ=/"󙔨ð•W¹ñ\B7ˆñÂÞ–¿âÌN{l 4Ý&G^’Ž`»Á{•´œËPâUæ0pNPë m);Z” e }â*¦Œ˜Z@ ™TXU0‰@äº(Ä0-jU!¹TÒòZ¯·ËÕf>_L§Üᦴ҈®Ýn ü()¯ÚívUš%ÈOÉmÖ[¾;?_N§³ûû‰ .y³íZ‚p·Y·3ö…£ñP%嫟Ða–KÈå£v(Å©á\xÕÑ3&«ˆê”„Y:¾¾¥ŠtŠ¡Š$¡ª`÷NÜiÉa§ãå€qÁ´%ëТ¹Z©ø\¥)ÌçVÒ´ˆ:¼Ä™»âN'T'Y±Ú°iALIK+zNjô@°ý!/&˜RÃÜS÷† øð*E¦«JBJN?%ùëYŸuÂRÎ)%YPKþ¥à Šz´„J4 ÂqÞR¢κ4À¹ORlÙ*4¥Ú„}óçf¹\y@ÍdoXÜb!“Ó)¦h5:Úív¯Û‘ÕÊnõvvœ5É™3—E¢"yLx!$û˜AF‰]Æ4ºGñ ¤*>Ex~€/Á+Y?Ju¯WZh (á§YžÍz–2é_è D]¦eÊwlÐ#Q&~½ë'[Ô¾Né»ÔƒOPÖfÈä dQ¤þ”Rbžg™wkK‰þ÷A)ÌðdÌ13G4‰¬–¸¬!ãÔRƒ—&FGë ñR(-üˆ•ÖšVøU •ÎT½§¢ JÌã‚à©ÕD)¾súy@ßI%ÑØÒÀH‰ä‹pÉŠ€ Ò•Ccüø‘…\ª`aZ Ц¬0AC g Ì $ÈÄ@óC¥%ÁíVê¬A°KƒWä$•š@ ýzvº Ÿµ8ŠH¬`é‚(ä²Â- ¥B^+%µÜ²¦ßêØðåN£<¶Ÿä ©?)ïCNÈx _œž]ƒo.¸îíå廫Œo.߃WÞœX DK˜¢!§ûƒhJWJÒ$D}8è3e©îšÈz‚° ”h \ÒŽ–Â)ÑXhêÄ¥R»5Rž4ÎãÜþ¿Z®ý"y|ŽGJ—Ep½ÑïØ‡l ôЬvå/Fñ Ꜷ)—.iÊ'nÊâY{Tò±¥è¶èBµF¶§å·xãž$ƒä6Ý.*’ˆ à q¡VRI<ÞþÁtØýg  T % Æõ\?ѰZ.·Ûµô!ûW)^Ü܉X¨ZUœúƒqÎÀ8‰ï¥ås Pu5@8uð ”>Ȥ{Ñ Ï¥={4¥Œ«ç7Ú’’¨ž‡W²!Hƒº„¿(PÖÃ.83©_r?/T "YCö·Pµ‰mÓ26 >öZ…Åé´Á³?&åK¾…«ãö6OÓ§°æt{ó™@Ì£$ RÕ£N1  ‡ õhJJ~¢¯ÀçS~)¼ÆV:+H•õå‚U¸Îçùh.ª¾®æê'Àœåc”r ½–• öÂàm”X‚ÌFDÂá©|%%%7Oe¦šo Ø-ËBOÕ5°m† 6\Ð.†!5‚0pÄI^òò|ù),'0 ÌXá\$ˆ÷dõˆ^IÝŽT#>xeÊc4£`BƒhR®×D¢`Ôb1i¸(eÕ£PÔ?©]¡1Í©uuÊh¾t°NííçtÌ41Oe ®§ƒB<¡sõëZ'âq73iA@$…¿Din^Ø•‰³­é7¯ùž6®êÄUˆWbtÔþ÷;i¢lñ¦ˆn§×•×ÇNGƒÓáàl4ž ÇÃsžB ,>/šñ1Ô”Å&EÒöª_eB)òÌ E‹½…ÝG ¼}Ìz/S:oUI"7j»åî¾9Åë ’HÞ!ÃБC í¥Ežä„!{ŠÆU?äI Ì™"$¸òzJ˜ÈS J«EÔH¢bfk)‚r5ØkÈŒÕ2ˆ#—ž˜„Ø<©(CÈ•Á•Ñj˜G–Bàå?°©¸o´ >ªvÌL¥(˜ªp µê|Zy ±H)I6rªPâ{¶J9uÓöÕܳР†°Þ Ád8?Ý w';Ͼ$*Kçžä.¶èxÝe“ÇZÍ^«Õï ùèB¿Ó´Ûƒ^ÇíšöÂÔ€1Ù>Ãæ“å»ý’ÚHH´ŽbÏ®ïvÁsØ%¢^©ÇfH¦‚‘.¬W¤Ž®ÑÖª¨%ò¨9šÂt ¡¥E®Ú|¾˜M“ÉÃäþ~r7™Mf³™¤èv»þÚ OW(÷Æꇀüµ…¯]Þû9†ùb¾Ù­[­F¯×ézC.°ÆåÇV«íöEÄ)ƒï'c8Üo‰ŽO¹yœÍ¸ätssóý÷ßúôi:,׫î€g&../ß¼¹:;?ëݾßÁÖj<ò%.5“;ìdÓëÍn>_ÝÝÝßÜÜM¦“Ù|¶ÙlÔ5pÀ ÿFCÞ'¬ïå7Æìä#w .Ǽ&PŠV?(—-Û(…ø#”À”i »#§óì¤FÏQ¤“R¯eˆHÄS¸˜ø…+qÙx¦‘ïåŸ(š–®&3£¢´Pˆ> ÃT9mÉ©é7ÁçGͨ‚J%¤xž– þp”~=Zà£qüE±€Âjlz– Ð¤¿±HD ÿ9Ä|øÙðe2 O’_Ê¡ÀÓ‚õè+¹‘U@=¥N)¨G#üƒÑ×ñsà H`ƒôÏÇRöÀÒ@&„âD¸Då3P¦YSTcö€:Ï9>Èåì4lÆá~Ì)ù7ÂO›@Ø•VÑ’›å¬¤”ÿ2‹>IÜô–½¼VÖ¡r.•Œ@¬9)ìQÖ³LY@Á‚uP{‹º¢¦}íU]$€ ³â*o^ÉúAˆ‚EZ¯™{Eø€O×+VU᪄C9š(s‡»”CÂäø {J¤ß£ˆ,ÌÎl‚*’¶n*foÈ;Çœ pb–O0Ôäá¦}Tc„QÉsÐé–À>¾Ð«Ó‚p©áfˆÌ+_ؤŠê¹Q¶@f‘¶;îf[. ®æK>û9›/¦3nÆ‘ç+fƒAŸwížžžŽF£P`å÷Èq>>Þø&^Øë’ª¶Õj †ƒ1¬(Ðé´-IÒ MLš“æƒ–YÁÜ$ùíÍ=2¶›íb!þ‹ûûû»»»O×ן®?*¸Ù®4ÙœÉÕ~ûFxuu%);ݶúBBn7qoøj³A×k1Y®¦ó™_'|¯*¿ÑjކÃñ˜¶á`¨sG4.£zôDœpÍ4p§¾DÜ85# ¥£dÅu¾àmÌ'PÉcÄâ`ÒT—zâlšø 8š'`Kõ%GzÎÝ ïc€â ¢a4Ht!áÖÎç (Ü„õh@=ZÂ_ýEѦ––ÄH@¦¡³yõhx¦‘5æ w“TÌù0¤¯ÞKÛdÿ²¥]ú†%1¾0WD¾jLâà@„IÏáz¢ (õ”z¸D “ˆ–° ()øÁh@‰ª®h`Ázê):–¬§X/ø£ìÿ—ñ‘ÇØÓ® X•µéCuÍÉ7v0Õp)‚°S`¾Ä£*3FáU–M«l×±Õ¤HL2Ìf¼‚“ b¼/õ6ÙøˆºØ q k3u,lD=ms?RÃ_‰änbÐY¢±Nâ>éMìõ(23fX8´ì‘ hVWØW)Ò$™€yÍÔ[™²ÄLź&DÆ  d!€&«ŒfxA´*ð¥hPJ‹×ŒqWV-׺Ôy¾ÜC©CÒ[æâKQ^vèLõyÌ´*`.Yz<„ )X‚¤£×€”h,ÑÕ¤%†nݰ!©—Fë°$q@z7À] Û@F¶ë°Ëö·G¾‚„5X´Ó ‚vi0#“ÀHˆ¥1¶¶'»ãæ±÷½ ;f·Ù2*Ðî¶P"Ú‘±Ê]”‚nƒŒW¢>ñ‹XGKc……Ñúª¥K¤Þ (AJw妪).y‚$dM®ª”–®Æ‡o¡#’ž´ÆhÁ`4(.–'M>ÂêÛÄLü)H9áKq—]Ë9Úð:õKÜp-`Ë·ÕBg Ç0*в9fRO:(Erú>!õ)· éß°ö#j&w¶uŸ¨js6•Ó*[®l3J\™†„\­7‹•ß"é'jX<Î AI«*iÐó%‘£–ow³¬òÞHô éÝ Ò Ø[jQê`cÐGz*eÌ¥rŠb°‡ÁÜ”) ò¶ÌüU„'Pjv“? †´ÆªÆ "!pÄ÷:õIôx½`-šªûÑ­+³,ý ¦Ž&=×9ÑbÐ%¡¤§ÀœÃ…«·SÊä°Š#f-Mû,z ¬¸ä„Õª® IÕ\NÈW®œ˜DFÔÚ=U¥T€¨’MœZA$' åÀ€ƒÄç1[—…,×£þ³°tGHdH5¾Ž©‹éVŽ5ž¨§ÒX´ˆ5€,šüF»¢Q%Jqw†þž£Œ@cYΓ>(±‰X{Mœ ’ÙÆQ'etÁ¨…iAS–yÚ;ehªÄ\ã^–4FÁLk¯}>–iVj¼q¦™1^„Ž&>''"€åQD‘D,¥Á2$Š7kŸ¦`p ˆÔ' #8¦¬ÔV cHa®L»å¬R¦&RšÆã8× Ë¤fIœ"upïÛ"R2PêJñ' b¶X¾œO’ØÂ1òcob#§¸ë{ÔzýžßžÒŒz)m÷_m³åM3¾h:_,Öëu,K¼o0è÷yË<¿–ÎNdÖ! ±ìßEè:wflNÆ-ù³Tªïn-æ’Pµ{õkª ÞÒïuùî¬ü6Ï{aÊ4–·™iÁT‹TÊÊ.ÄGŒE¡SòQ\…»]EÝÍ›œ}Æ(&n•QG_ =!*`«Nƒ=h2æV*œŠç(?NA Ep¶%Œ‰saN‰"?„ÈO$9Â[þç0¯TEqA_ˆj•ÔÂz8à€òs¢OvÔè°ê£„¡"Zm*ÂI{dš6< °à ‘’Lw…íÆs02Zåz€´|ºÁ™†¬X)YµðÏ›4šŸŒQì-gP¥Z„ŽWÄAŸ£??Ûg1à ñ—Æ€ƒÄç1FPVÙŸ•ða‘„éOÐ cV`ê`.VŠ~jò!€~³© ÂáÄMo1ŸD Ðô{2D´Ž™8KRöûô%ü£"ó¯tbÝ™¢TVW„£ ŽeÚL¦ÃC­#ÅbÉÒ@)—‹bæhˆ •J¥d§8±ÓžhFOÜH²Š‰r»Sþ™·.“߯–#h§Í‹jÙ„Œ,¤¥6u”ÁÛ Sx["ý· /¥@`Ps}B8}Sbˆ[¥SŠš 欙RTþIÉ€¹U â2ŸˆEx¯ìB.’D¶Î¥1§H €´\ ª;¨Js¤Ý–8uÅ᎑WU!æû¹Øl6*Õn·ûƒþp4Žrl:ŽOœ´P±“ `UZ­&Æélº\-U-‡ƒÑx< Óçäã£ý Z¥#¯sçXº½7-~r åIº"^Û“j lù)×áp8–„CU$ß«ƒƒÈE5Ö ûmÛÝѪø—³¹Vq‘Dq.SÙÁ”gêåY?"ÊUk=Ñpꉑ¤G-pXÂ…õV·xÇH‘ð !YÎ¥]ÊFj§@JñÒ](µŸâXJpfYG®Ô4Bv›­$¥Ö¿„?ö¥ÒÍZ¸å³r¥9¿”-kÑ  íÉ_t)y}땎Û-|¼ò7kØ,yJ*Y Q:êÌ@w\hqƒ¿À>âN¤W;j©ämÀ@«Ó–SÈ+û´ø‰¯w.”?xÝ’sçÛÝðÿT ªIÍ“O©µ>Špd±PŠŽÜÊÆ'{@³¸bj¶:;TxpÁ­, 2Á7¹ûÄœ•š„S¦É¨KÜÜ`”=@XU`6_Œ’ñ­2#Í6 Y•ªx@©:àÙ(MËéβǓý¡È}‰hIȄџŽu8ÈJÈÃ|~ ¨õl’¨þ±c:‘´ÇÍmØ™aë{Ö0Ztz¢©^#ªÌö°aÚ`äÃĬb±À^lÕÒ+=Ê 1ö!馊Ãñe â…OfDzd””§e)´j¬« ¢RŽE†Š¤ Pþ¨Á–;B=¨E~,]醨så”3_Ùøù8v”-˜&I£Á$ƧY‰Ñ QÌ)l—xð ±’{h!A‘%cóúå°0M|@-Ì®QQ#kŠHæTZÜ*œK¦[AæÈì#œM|‚5â¨v©Ê“©ª}L:øG‘D éµ–ˆ9ºp”å0¨ág&ÃT&VæA}@P‚ÈÊ4E!ð E Ì4”ÊœŒ†ÜêR+… ÂD#‹ ¨¤›ÝqÛQ_ˆéIÕ8š"O@l'¸º¢è‡z#=åFjP*PÀÄÄLÒZHs0Ÿ‚t%˜¼ ºÐœ€gÑ„K“~ÅÀØ] À{4(„hÆ’ë:Ÿ¨¹É’¢ÞL¸ÔjI+ƒ!² ‹2=E|¹^Í2È “3Ôíóª‚SžHöúÜ@fÀOj´›ÎÜQ¸ÙÞ=LîxwÈÄKX¨.¹Aqçõp0à¶³¶|7­ñ+iB*C›-ídB¨¸‰¢é\7??±\,þêéd¹\)] Ÿ+0PE?” ðT¡6óâ8kÙ\,—ðîîþI§²µV«=Ž././/¯‚‰8»nr\¬©Æ©0Ñ0 5ã4¹¯R3&wûÖÐI¾ß‚h‚,xG_äJ*(Ñ  ï |Bù D:¾Ž‰Â€ÙêY‚z®Šøü‚ðRúÏ!IÔ"1B’À§RÙˆIMõwBŸfè ‹ ¦3V«•7uKC£×z›Wc«×ïi¼$€,Ž!PcŽ$6Œƒ­'†lEÔ€ˆp8€gù (Xà úSà'ò I “zXP¢:† ¤D´$–Ru8(â”ÄIމ™c(W)² Vu"IÁ¥“¢§#¢*)´»‘lN¶SƾYEe¦P&.ëyåèâOêûlˆ&EØm1D<•j–ÕÇdËÔÎJc`J™l³±Ú1½×rb® Òï«`÷%ÂŽJ)QeGåHÙ ^¬Q-I-2¤ö@ÁþÅñKo÷dB«s¼TÃ0¥Òxa¬EÓ²XvÎt—0ÝéEÎ;\}‚µAü¢£ &>¶ {M*@A—Mq§ ”‚û .1S!„¡Õø,‰x A&0‡ÏêIÁ1­ªw ™?j;ukê ™X•MC WV m2{@ŒF¯äD:2×ä‰×õãp^qˆäfž\• ›š~ÓYASÂ%ZOyŸ¥'‘tvý”*w·;ⱎ햭#[X»‰£–I@0’p¾ÿ,=Ê €V,‰[ *ê_ R­©ôcT¶˜ûæýçÔø‰î’fá@ד*2šÒH]ª1º­Ð`1?ÝåÏbÆ'‰.NJÊÖ³(J½HIؽS9}/ü‹`ˆ¡6úÓ‰Nð98ýY뎠`ïBÓI9t¢„ç9ny\ð¨ŽRÆ…ÌÎUc×ãCüĈ[#:Ÿ ,ÑH!`M¤DÂQ]NÉè. áFºÁ‚I‘6£gÐ O\RS£95ˆÄ Äl3ÆŒUKaS‚T‡ŽE1ŽËàâÕ®©\Ÿ—ä2¨sèŸ=P® An¡A³tòÿíÎèȉ‚‹Ã ñRÁt©„%1U¡Ä¸M¦–u%š"H®TÙR†\"¯2Üë¶åJ'Ž‘¼ͤ^g0ìGÃo²íYvZ 3 m-5\»ä1O>r¥JƒYY~P€×زK7èñQØV‹¦Iމ„¬I#RºH¥Ïç¼g$áq:›Íwb¨*.¯®../ÏÎyAIOúÊSh‹µâÑÛz³ZðÔ¸1N nñâS„<3(<è÷ÅV3^]Þƒ.lÀ=ê‹0“Ò3A,cÅfT4˜˜y Òà ÷Q<'V ÛœHÁ`Xÿ qÁz m‡¨Š–qä²{¹Aàô*÷¹°£žÏJ´`ƒôŸÙý÷iHêcdU`%xЪ{ÉÒ àŠ¼ÆÐ’ï¨q¯¨P,N2N$hPÄëve{2ºN§#àšs TŒIÁ¡KUY E‡8ñ¢Œû%Œ¾rJêÇ‚‰âó¢_„¥ì+P'ˆpÍú¨g ž‚µ¦V‰ûX‡’X:·Ž¥Ó#ðë”%°‡Lz8a) ÞŒET£[e`DO{Ê$˜ˆUÜü" Fz‰‚ž—„®7ѤÄD‰p6s‹¤@’-Ž.ÈUܬØ0ózÌðÏUh]dË+OÝ,-ž!£ó7F‘œŽ©–¦ƒ¥5˜Tµ²,½¨¹*4£ä"Öi"š„²€J7%“äóÈÒ…€IX©ô‘nŸwÁ‰ˆ†·„¸N/µñÆX›œâôÄYî4.°Ð¸à/NóÏòémä¦)‚T]`´'¡$¤Q–6ÄFĆ䙃›ly. Ò…î…„©yF¹ŠªRZ (x$ à–jSj¿¡žOQÇ kpý®‡~€ ’KŒÄÄBÜ¥D)Ëåݼ”VƒÔÚˆ¬BäòÀIÆ*ÈÄ´²¦Ð=>Ey{œÓH k :ðk¶úçÒÎ.vðk¶RU«Óìõù¸êÏ$^ŠE5 _‹£X‰VYÏQæh'Ö!úƒ.©…J4 0OpÖÿŸ½?Û±-ÉÖô0w_½÷¾›ˆÈUáUW[ ¶‰Øxþ {‰™¢šyâúþAcbµÒ®FÛzµš¾ß“ÝÖúGÇÚ0¨Óòr WÕ-2#OÈC—Å»Gf§¶ü¢ÏÄíf‹Ø6= ^…pWo¸Eïb'» ÿ; Pù&{²ïרê ToŽ;’>Šm‡ÔÀ6ž Ic.miq|™‚_ ê/g"¢‚ìgrˆ ‚ž.E?taZ̈È4EnÌ0 Ö1g›ˆ $nÉhÏ?‰‰ËމX- È% B•VZ¼Ï<ÐQ©Åhý³gçUPU¬H¥n ùç‚2Á™yy.¥Æ\§Qà JÍ×"¼(g7 §Á-š­YÍa¦ªZËAT9ÕɼŽ7£ …Û¦¡ŽT³Ž6Ú°Û8ç tN…ÌÚRð& öz"qõ$!¥%¥|—›øµÀTõ S|å sãG©DmF`Š–@¸²¦~[¬‘*fKEŒjLŸƒ¬ålé6l“!–Ý riÒ ÏµšR9µj™äì)Qô‡Héú°ÔÖ@PaJ2tr?Š#S4"ƒ L{5?“þIVÎU-#€³¦ØEåÄ0—éâÛ$#Hªf%[`áðabuÔqÖ{<<ÊiãlÛJ–ŽP··?õ†~sÛðsftYIdÝÚçãîsÙRËùlµœñ©„¨ÛôºÝa¿r|xâóXÂÑáÑp0 dWõ¥•"é rô/nkÂmpI%”Z,f“éd6›ÌSÞ3r°7öF¯^Ÿ_\œ+—ÃÃÃ~¯Ïò€prŒÑ{•lµáM»¦Íj¹Ù¬TÙ²ÕNø&©T=:>>–zª’{ 5@µôSrßh!8˜Mê~<¨oêìc;ú¡ý®Ž®+¨œBã±GBGÙbInÀöŒæ¼Ãû½(Ðr{D´¡q¨^u_™ì X¥/xåÞ‰ýrÔ’”¤»¾¬ñûzåÞŽî”Q¬øˆ9r' æ•v@¼O£ía¹Ü,WK†”†ì¶ÃQÿôhx~zx~¡N; ¸ü¡J¶LúWd iñb݇=öU©ò„Ò† NÐrµ£cÁ¬cSØP<©p~žv8ŸðV”—QÓ>G v"ÚÔF»-Z¤ð¬¯V(jVQô"ªÖB¨¦Ã‹>µhhx‡ææsšÖà rŸE“J^š92Fg”¹”PˆÒªCZ:˜ˆ™1 1H,ˆ[ls~‚Ç3’Ý\A,ä)Ť‰˜ìåÆ&a!Êë‹fËä&eÀš&QØËzCK! ’,p Üâ)nk5üQ “ cXG–Pê¤ jxbœðÑ1Ûȵ® 4¯P”†««aVO¢&±Ç’ÌÞ¦@8X(.s:j9šÄE¥.÷š9ZsŽÊÌÖXÎY°ä+Ø´D˜¡Ýœ©Ñ-ªŒ(’€ D° ¹'„ZƒÉÍ&8YI[GØ6©èƒÇ­åJÓX †‡ÕƒÌ¡éÝx>›- )ßïÈÐêó‚þ¾_ áaK ­Lkì:¹;{›½Åtµ˜­VóûõB5£…Êäs¸ªIºhBжŒ¡œ+¹Ûb3gùMH†Úd2žb±M«¹JÚéí '§² £Ñ€[öº¼½BÉéó®)‘±§BMÆ“éx,3óa³êwŽ‡Ç‡‡ÇG‡²(éú5[TpsnU¨”U™×>Õ1&îÈK¹‹ØÊÅ4ÔöFOyŽ"¿vù¿'P=`KÛâŸ`Þ¡Çh‡¿Àx!jå|6­j;¨¢†ü(ÔÆŽW¢]®ñÅ‹«µÚÓà §k^jo³X/æÚu¬4¦5ʨôöFý½ÃÁþá°Óë«ÜÎK-ïýLAdÄv<{›}ˆåZ]%èùŠ‹$:º»buÔ~TQC^ @Û-ìx%<èËvè‡A yç6µ¥}yÿlàôÑ]k•gÅsr#§š ö¼“׎w Lù¥ämÚÆŽL¼eÞÈy¦ðdHÕ3¹ÓŸQ kS€‚DH”¨Rä’åh%‰ô5I8j´~IBrlÊ”f m*ìv¹hÁÖ`‡»%(Ð'ÅVbý[ ù£¦u¼g¥…ƒý IÃê…EÞf¤š;$=¦˜¿ ňNj•F1Ú¦u÷z"¹ƒÝ¶ˆ 4'åùº²$é¨ÀÈ65&Ö'tÊBlbÛ=(3—"iÂl y[é#¿-~-å(WÍ3K(ºU1¤ð4þÄNÿN;^ò\ªnO¤æÞAfŸÃR 4j’Zí&ò3çxin„RT7GÚ \|ã‰Knt—‚ƒJ,Wõ<‚Ô‰ÖR®â©$æ'HêK$g™Èh(TS5Š™öÎÊÀ—bdAJivXI!A”­EbŒy©¤Þ¦oߟtR™e=)‘úÉýj=»›Þ\ÝLdºMÇû{÷ÃQŸ·Ø GÇÃþSØÏiHîr}¿\ª”Éþzù ›ŠáNf‹ù\µ×—ünoØ—½Ç™eHw§$œÇòƯôYÇ}t÷˜©µŽ¤ÍA/IÝÇãñÍíÍÝøVf×l>VkJäñÉ!gÚ^ó<ÁéñqOÍl±Ê…ˆØ†ÛèîÝwÖûëµÔ»½¾ßÝÉ\/—£áðôäXIÏÏώл\õ$‚u–Aª~ÎñSá>-¹IýûÍÚ+¨8TÙJ/Ó|ô©5«n=Žª¬ôÖòºøMH›T /xåßöFHP;p[øó]p—ÂB€äq¶êø¬7P½CžDtépd÷.!OCÝæ{‚ ‘JVÉCã~‹\q4Ra'ЈՀð½›åêa­V•>_' ©ñx®Ízƒ^o8èŒ;Ç'ýsÞ9ã~'A>‘¡IW­ƒßô>pS^骵6û¢bº•¢-é¸N+hˆsu÷ûRFîÍþþš³nyâígµ• ¨¥¯šò9DC¿À° b;síèÞßí‹LCNfÙ´j q GëÕÀ•êɪàöªÈÞ,MBw“àt+øœzºí-TRhùgÂrÉÃ7q@‚ϲ†x’†Ì–~òJ²í‰àH¯æ–ô²ÖÅiþ ž ÖÃpø±¡VeNªÖ3•יΆ‡Ÿ u¯ÝIeé*MB™p  N´øEeaÔ0èRÅ>æÅt4ao¹çkHªqY­#­äàÐ,¬ÅŸ+ŸÁF ÃB@6´$ˆ+$Nâ…†žøœ bv‰u·) Ú¤›õÚ$ƒ¤žân¢x˜<†*gœ˵TÙŒûÖFˆRjî0RI¨QlMÎE^7SqòJUz±Ø?ë@bêf J™c!ŠŸà—¸ú¼!°Œ’V5CkQ÷â‚[˜žÈBfnÖOGj-+KN>½ÞVF¼–êñùJÞ;¦æ÷W×T”Ï×E«z1ÄڡP Ú0¢*³cú•¬&å,bNdºÄœÊÖ4¡`¡Ò= Û„úQã¢ÚgÉÄš‹ß®Š¨²ót\„„[‰ Y§`}R¾¼˜—.¦8nÚ_¬îyŸ»˜ý~¿£nÄés'U¯)”°ˆN>’"æ0M>ÝÓ÷kÔ½¼yG}ÊÖÁŒfB9WAš;|G¥Êĉ‹ÍƒÇã}rãñó97·©·ôÝãc¿î˜h)/1‰r.qññÞ/ \?,«ùt1çët9›Ý¯Wj¦a¿s8Žú‡Ã¾ÌKF+ÝJ©\QGÒ˵ŸÁQ‘y² £Õ"¢aº‘µ§6—k‹õ¢S± §ùBЙ2ŽI7ê%õcr^OP˜h-J N+†ÆT³xÒûU´Cª»†¼ŒZÿáøÞJá9zžb#Öcžadû >ßHžûKq³Åj6_ÍëÅ‚}ŽúS¯s0ìuFýƒÑà@ݶ—»Ú+ÈãSâ,ØÄ…ÎPc—B%–`¥@ÃcË ­‚2þOB4Mæ›aQŠvÛ…’`«ÈTÛ<Èåixök •ÕÄdæ­dCÙ_ÐÃÃ¥àvßzŒv8n)³Ÿ{B| Ÿàñ,ùÉYå$³)çVý`¾›9£œ(¹²¦XöªEMœÈj,Òœ¦kÝc =StêS)›Ò±¶œŠ6¤pرE‹@½¹Å# ±» 玦ZÛd0@r ô)‚”:¶Œ€£ÈÞÅ(flHiÁr« \­É#cšê¶r¦xS¢ M/¯QU&N7 [¾JP´ '_DV®›û2÷ @v¸áwlôÁÐŽc!O!åTOÀE µë)šÖR‡ÕÞBÄ&|3’Œ¥-ÆHÖÎתYǺµUÃÐ ÐfEFhͯ…=.zzËCþ†ÙÒøI µydMÊìÈ!UH—åW¶½íkù ¹~ƒüß*¼Ë¥!c¯ˆ»ìvP‚òäÏv% X¥T–O!UâûÚàI¼ Ûû½NO6®_*ˆe…Y%õb‘¦˜´'sõ:on´àF¶ÁpÄ7Þý­vìÿØF©²âT07g|9rš*_î}g<ˆ°˜Íæ²ÛâÝ‹Å|µZôzÁ wx$»'V##ìʨ¿:«²dü­6ËùrÊUÖÉ|<‘ćõZsŒ,øÑÀYà“÷ÚQ°¢®Iª Dóô5FnZÆŒGFª&ˆàh8§··¡Žd¸ÃÛbpT¤ÿ2”ÞPù­žÑFMÑýŸ¥¸M TTô2ÊÞâª{Çh{«{Ç[ñ8Dˆ‚Ä1:<½;”¡áŒ²2h§.aVÎãp›èl¾˜ª÷òɸßçð·4a©—÷{òm¿ßÍ^KsÄ„´¥M”±RLôžŽ³ýªã9DªFÈ£2Ô¨/Á²R¬\E1#oex[% Oõ[¢g1ÛoðDµ@9C¥7FT“Žj­Ñ–ƒÝJRçEeϘÉiS‚Ñò¦¸Ø)oòÛJc„˜w}ž‰@&ÙX"¹Gi jÁ#ÜÚ‘?Ue %Õ¬“Ge}ÕPÚ•‚Ós«©ŠC®Ô¹-ЩpDŽ5<ȱ·ñˆJÁ¢øãGG3q’µ°_?Øj15·$+µ÷2¨å¨s×{…³–¨„óröOAü–¶ß.!Úñ©6JãD>Ó?¥C’E”=Èh²v`¨S”A=ÃÒ¶¥V›Ë€á¨PHb È.j¶E <µPÍZX¥¢¾ùU¨´µ‚ oÒŠ DˆuHfK´¸ô4ˆj½d$ú¤Ÿ4òf¸ÃNyŽ­ Ábêñj4ÉeB©L¤«`ÖFÉ)Ji ‡äSa“Q¤âjJ'‰-©tYI<*[‰šÑ|×ÙóiXàWxp> ¬'F}vJùpY‚lT“RT©0£†ƒÑˆ“nÜ:Ø™28±[M  @ Þeîñ Ÿ*s¹äò³él|7ÇrÊ’“®Ãa4ꟜŒNONŽF² ejÂCªª‰Ê ì*G<ñ:ŸÎ'·ãÉÝx2¾[Ên»ßtdíÉè“’~ó©’£ZižGHÔ÷cD%Úó–ÑtJ@ÙÊQ(Žü…õ³T2JÊV5íD…Ÿê$P¢xj¸} í~ iVùv¼¶[øS¼øKP;ê9÷°ª[ǘ|5f|&AÄ›ÛVYÚyÑ6f8è«ßņFPŸpZ+c µæ€™h»wfßÜ44sÞ{$G_BeÍx)Iåí`'ðY†2}áöP¨^B¶ÝîèY´ÌÚ5Ƕ)`e˜ó œª»’„›’Y¤¹çáaíë“I>ÃÂBk!™õn-'B^¨$Àž®ÉÃrb¼31 õÂ0Ò?"q‘†^D &¨Œ À`nˆƒ  ã~šR]{R‰øiQt©`KI3Ÿ– üV( K…ržD OdsDHDy¥Né s* cSXéíh (q¾Å ÏÁ/NS}† "P·ÏÀ],7ô˜¹´ZêÙí ²ÛAÆ ©öÓPŽü?=µIˆØ]W¼YbyɱÅ¢ÓS€Š”ÝÅO E:[µ'88÷—¨Nk[áΰR ~9ÚÞUK¸ê“GÊ™bT‡!“Ÿ[¾ÒŒç›4š?W³, _b7u¸¦’siQÅÉ4OEbr„]äȦѽ0o¤ÀP–=Ÿ½¶aÄÉ·ŸíbÓø}¹2«¤ŠzeJ£–÷Å)~j>“é&±²Ò0ÛøÜ'ß õVR*U­«ï ÔÅlšŒÞ©f‘ÝÆ‹¯æóÕt2›L¦wwc‘–@µXOFÇ'Gg§Çç§2ÛF>ï§äQ/$D&¸­Ð•Œ½Éxz{s+»M²TTmgeêœ]œòÒ·Ñá@vÆ%£Žë¸^+%‹ANA£Çg©}ôîÍ÷"‰ß—~³²?TG•vaíšð¢ÛÙB®êTQ±¶rie‘l.f)“Øä¯T¥í„ÿéúü ¨MÕ°ã}„G™µ4y*I‰VœÚÿÀ×ö™ºÔý4¦üŽè™:ð|Æ·ä5îÔ ½®ÆÄ€WäøõÎêr)9Ö»BÚ.Ѱ•æð 5¤M;p‰ªúÏRmÙÆÝñ>G΢,™F\Ìõãyõ’P-;Šd­Y%%Év@¬ÇŠÕð[\'å^@ßÕ°Þ{àîÀ$…p§ ­ŸxÏùùûÍêAtÿƒRerQX~TˆdrKDG¥‹vKÝLxc1Ú± ŽÉ×ûfð 2óü‚‡8y‘ξÈWsN, ÌX>G‡×WãGÉËF]c9ØËX?Ó—/¢¨žîUUM‹1­ªêÁTKEw1A&#*œÞhò§Ðô\¡ˆ5pevUÅ€¼¥(Á®‚ÓL:Lz¢µXyHÄm✻Hí}Þ±á¼h-O´—¨@ñ’L»Ä¹ÒÌå XV ÖAGÒ´(ë¼/MÑÀŠTrgj]œ¹U.j8ÃÐ* Á‚ó3“‘iEæÍpS¿SUB¯ Šä3ðÐo\ãeX&e3D”[®5AbºPX0îð9ô¡œh£ðq}9ѱ¾R#5+ÌŸdNþQœññ-AWÍpÖ cYÇ:À;B—XÍîâœh‹ÿ>÷>VC=žD¶ùÖËÅý†}ªTæ>‘’•Iójò—.&¤óQÁP«­ýÜÃr)«k¡Å/$Œ'2+iËý¿³Ô_b8å5 겜œ±!Ú¦·êI·éL–ßÝx<ÖR*}Å+펎ŽNOÏxW/7¸õ¹:‹–F-u Ô“„'"~(£Ÿ-¯ÀÏœÝ?~Ô ‰eà ÔP9<âPžÌ§ŸnSܬ´ü3¦:ê{=>ª¦möF‘òÇÄË"‚ ZDu¶±ãÌ0A% Y¼3‚ AÕ<^ï±ØVI¹lC$ ÇcDÔs±»ÐÊïÕŸ5ª¤ª¹ä}¬OA,²,ˆ­rW´åTùíÀ6žð"žô³áyzÕ~²°=Š¥…«…äø`ü{ ‰L…ôo#¢BÏ€<‚Љg²SuïßQKxUŽÇ\ƒj´ûÄݳ`b Èaû©ì²ÅÑ~5ïpö­28FµÖ óN\âK]íÕÆÛ²PÌY®æ¬0»«×#'³7þcÙìíõz½ÁÀŸIˆ»Ç:=NEÅÍ;ÞÊÚӂĵ Y~{J’dóu»]õý¸JŠùÉcdÌÛb‹R÷û²øÖ« dóñ~µØ¬fëùt9¾›ÝÝM¦²¼f3i|xÄ[æ/.ÎD| aÄERÕݽ¿*T^@'A|bˆÇT¤ñXFÛíÝ]\fÕî@–ÚÙÙÙ«W¯Þ¼y-Ûo4:ô†<~dû]!*”*l!" ¸+4ƒË¤Ÿ7½Eó „ù÷{PH,ˆÜþX hgIxŒày!ÃÂð— <*«Ò4Á••Is?80R•Ì+‚|¢—«¤«Õ\Û1õ»a¿â%Ï^ÿÄ&Þš>S€‘þgØþDPz#ý?>ƒÕ»sÖÔtω1ŸK«Ôf_û¶Ö5æ×ýzZ)ý:M†ü”æ¹"+íaoõ ã=oIvcr:fŸçp7¼?¥ÞÕJ*âÑ [ˆó*ERäè9˜Œ!æNÎx¾153 Q(Á…Rœ4¹á ±Õñ˜B9Bd¦uΔ(Fl«Ìø1¢l¬H"ë!‘„,C§‚íyPŽä*¿[ˆ@߻Ҏ‘—À©’h¯Î9‡†-”–Tqˆs@m YõH­³º’ƒaÇf–M p÷i·å¥¨Û^VnLžXçY郃œ^DªÔB¤Šä;†(€<5SE=à9B¹‹F[‚Î é½^‡Ëp-ð¨V{õ:5½†§OŒ•©„mMð¶ÀˆÈQp_*](9:>ö‡CõYPÉE|àõr~O=ºù±†ñd¬2Ê¢S«}­›§§'²ÞüBàA¯ëÑ–uKÕ™¨f”Hîœ? d̓ª™ÍØjúï‰&Ÿ]ÇÈø3°VÒásjTÑÏŠ,BXvð™”ÿøÑhÿ¸(Ù®êOU9µÒÔ-ý;èžÝƒºîÊ70 º=û ý-yï…4RbTD®–¾“Á‹ï+?ø¿oªQÝMÆQS¥¾™Ä&,0 Ár;šZ÷¦•QvÍf¯¤ f_å¶Û×eÒ2cšò}~ª×\ˆÂzKŠ©¬„sÇT­·Ô²±Í³'Ê$®îtÅ© Êó»Ô·¶(,Ô‚TN¹§œÌD=¦?±ÅH6‹7+•BÑî2ÒWÑÄì c B^C;p¼3VlU4T+¨»‹ä{ ‘L6SÙAUç1Ô^üm9m(Ê š^Ã\OJz Î5ø#a;N`f(|[ÁföŽÔÑT†ÚVÈ]8w q Rðû@x²OJò¸Ú›¼motQYЩð9dý:m Câ rψìžÖÖšJ®ã%Á<Ë(ñ¥Ë7!A‘ EH+IC†vÍ Ë@ÕvQ­2´zIM.w)S‚I|å@ÜPÁ™³|l“¿°Û¸‡l¿ßïóá'îýâ¾ÿŽmðHˆ…¥uÉwù=2­æúU¤2èõ»£Ñ`ȉ0Ùàa·EÍë'ƘਠVºÆzeÚÜlöV˵$Îæ\$NâZÓJÂONŽL|æ~8ìóú˜Ž¤ð.ÜX1-#n) ³Åt2ÈdåX¯¹V¥ÒŸžžžŸœr¹Š»ÃÝ6¹ì†ž-ÊVv1ÐÙ5MeØK`q‡7€&áhEµÝBÛ‹#p5ï¸?ãmɪ·†íÀïOQ[xÄóãÓŸ MÖ„µèVOéGythÛ°Y2&¸³MÃLƒP۟Ѩxx¨ Lj7=4Ó Q¹•~B4EÉü¸T±ãý>ˆ°Å<Ì/«»|:ú¤i™^-à&mî9Ë¿^nÖ‹Í #{½œ¯WÐf½ä¬›Hmê1ñ+-'œx|Áy™¢È¡ý=§1‡”ÞD€Ÿ“ ó‘÷>ñä…â£5_¾ËÊÄNŽíòFn™h)À9EíìPpFªv²Í 7ÖaÓµð%äNÆQÊ*Dr¸žaI¶‚Âù–›Géú”¾Î&Ä·aŸ‚Y ÕÅ´ûO¿ΦavòD uVkNd·ë#{S> C«ª…Õ]³éȱkHP¬ïAUóèŸjÉš±7`¦N› Z r¨y¼´ÒR„È !@ ŸØÑo«&•2 ‘$Ëߨ[*Ž#²Ò¯xŠçbbZ¨û6 „OAF„l±RâÄh†c9çô¶B‚jxž„µ¨àI³ ¶FWê§©d£x©8 jAé,ÃK䉀ýr!§d9“k4!Ä$ÀO™D²½nSãFž-­Æ=8£!VvÚjD9!W!W<ïO3ðvYEbQÂÖ'¾IÊi,YD*Õ@¡BAjAµ]--Wl‹]¸Ù[®6³ùr*Ãk:óë?PLÂOÏŽE2ÝŽŽd¢­U”ÜI;/µàj¹’Ù7Ïîü²ÞÅ|¦ÉNT¦Ó““ó³óÓ“Ó“ãc®äjç€nªÙœ|Q9ZÕµ L:€Æ ª×!ºå_î­îÏzƒž†Êð=bЉv‹*g;É_:\A.²ª¢ŸÆÍ8Ã7_=¸áVÑPþdœd¿ßõ‹¬G‡G‡<³Cïõ}»Ðœ%~l¢Í3“ŸµÃ´»[}_´ëœ!Ç’3…³k¬,qådæ …9E&JØ@|×oOÆÙjñ°\ld±-æ«Ùt9Ÿ.ýípÜ­ËÙ;,³8–Dˆ­7ÖUL72%» /¼e2)Þv`²qE©¬pž^CC“òªä«·œÈ]­6<žÌK¿QR“¸ îªHÒLÊdÚäUÚÅTpï§ &Ï6sR Ó+DµV6Åáv§õ£ R9M¹ey‹õ;: 'mbýbŽÕ1“ 6ys‚ Árž3KJ/‰ 2j…}¬ƒ³¸\D%?îdæêg&IæàJEWU·¤¤×}* µ†ÖÂÓæ1)‰OÒ>Kª:iêü$™£ƒY¥­ Œ’.H)ÕJÂè ‘6ŽŽbG°?˵=>¢šQÑu•5lUJ²EÐg TkÚ3ö»pŸå ‰Ñfé|–jÛBð Õ¿Ý…9褓+ïi$ïb¨RGNš©‰p6%P”òÕ®L.Ù_²½8‡æG:]®uòò5¿§XæŽK—u¨)v|¼ª#h á†w·töx«²m=¥rBÉ‹\¥5)™ÇôWç2‡†]øÀ%ÎåŠ|ÿtµßíú[õ~_›ïêÖè@)-”2Ý, Z…Zi6ÖT¼àÎpÉZ­$_f¤¬ÉÑhÀ)_.§¢Fݸy*íf‘¹*…˜14.–Šp8„—æûƒüB„/ü¦ÀÞÌ®E¹‹šöIjãɨpTïJ`a«k[Û­(õ|0FUïåçuØÚ@.âçmmý®:]+¿¦œ>¥ž•Ë"¾< }Êd&ì(”q¥çz ´¨:³¶q=sÀMNÊ.§¹0×Ô$+Ÿ‰]û“±|}l±žsìj:[j¦˜Œç¢iXo2ÝĹ²I–‹v›eÊŠ#“F¸#kS0×R©BÉX®¢%­ ǪÃjâ2&Z.1eÉwG“#¢B(`Ϭ9sS‚ÚÊ?MbAíݦŠlX^]˜ËNC‘D,E‘FŒú†19š#d!Ï#ù>Ç™LÏ"µ åMGøXäNh6¤›2]^dÜÁ,DTzžG¶ÿã짆©f›x2‰ì±uâJ®%hA©¾P„R´©À¢RàvNá-v<ÇJx#•…Iõs`oÌÆÒ6ÍÀæ_8Âh•8:V!Cӹ豷' ½B»ˆrG}¥°¦M]BRŽœ©Q„ ðòu™Gù4¨ïO›Ë©ñÜíò¼ÛÑßY×1Ö™¨*A*höðY¶¥ŸHÏf“åŠ ¬²«Ä)»êøøp8êóyJägjÁze]À!ÅdlɆßM®.o®¯nâ1PEÉ”Évêód~ïÚ Ó•ì-Ò–³=²[-–’ps}{yyu}}--µCÕZ©Ÿ¿ºxu~z&ýº¤ˆli{ýØKh´Z­29ÚdÔ¬*NÌ’m´Cäh9ø+vÒîÈù¬—úl-_‚଴ƒbKü'‡ZµZÂPµð:¨åŠÏ{ð(é”—ãø®Ê•:SÐ9:œŸó ´ß9¨áâ­­eþ_bPDņ;(Œ$™j£Îdõ2çj{®q—=D>¼”ãZ‰î÷–k5Éj<]Þg×7w/o?|øøí·¾ýý·¿ûÝ~óÛßÿæ·¿û¿ùí?ü‡øwÿîþý¿ûÿð¿ýíoþøÇß_~|{s½˜Mî—‹‡M3áסh–î¨ÿøŽñ­)“«¤éM­™0×dý)?ÏÀ:ü%*ÉCóLõ(¿JQœ0ŸkÈ#!B“ÑÏ Mû¶IžFƇ‰™II˱ec bŽØÀÜ$ý Rò6Љà < ¤NFMžqBuë·ÜnÈ(¹ä°/Åxh(ÎgsC¼ÈÝ¢%6‡¹ÅüJì(ñ¸‹²¿|R©¥§X\5a=2[¬%J¹Ú_ Áé24 éϪE~hG@xñ¡Øö6¾VùR”\Û[PƒÊVGµsBžË«ÝŽæ…x@„«ˆñŒŒDJFæ :æ- ÒJˆXÄ«´=O*i×Zê •c¥y$®oZCu¶”õiÐ%–äZ$…U3ar®‚/g¡SL ––º~%Jý“ÎÄËIV‹…\ê²Ìí½^wØï ¼“Χ«~ÑÕŠ¨h/(ë1…à‡“¸P @ÚBíðï ÿãB*Õð ¶«él@g«U\TëD ZÔ÷´0–ç¢ï9}íoì?¨ÃjTôûÅâl·X°Öº§EòÈãŸ.êÀIÿž,3S]Ë_³Û×`äD•\gsWOŒÉº¦]8¦…kn£xX­E<©4_®g ήMµßœL'wÓñx:žLîîînnüýâ[yg3ßY±’ŦÉGºE[#Qz2Ë(ƒÌ_3OÌâ‰Qÿ˜R}£È‘Xõ,6í·m¢¬@_?ã*IîMI9bú¤A8bÝrÉ¡Õ}*PÊ[–¤‡*œŠáòhÖ<á ´O‹š¦9µ‚£ðMy »@¨R);{SHL¬öYÔS¦¿&³…·HùžÈj02èy É÷Úñ:Z~D´QÍ”ˆŠ }„Œ.BÚÕ]Cbw à¶Oñ•ç1"UX濨ŨÉH™> g\O@é-2AH‘¹ƒ` ÏY §åp‡z JØÎ‰¢<Q‡J¢QÈ)®r„/È*â)Òéd6¾__ÝŒïîæó©Œ±Ã£þð°ÿÕ×o^½¹89==::”çŠ8Ø,5õݯJ¥â»ïÞ;áíÕÕ¥f–ããáðpðõ7oE£QÿôôDu "ª¨Üþ¾jÞÖ†¹æ™•“õ˜kë=Þµ¶Ø\_ßN&³ï¾}ÿáçۛۻÛÛõf}Äë?Fû‹_~}x8xõêB‹__FeGÒ]&Џ¯%r±ÜL§‹Û«ñ»w—Ÿ>^}üøQ"î7<Ópqqúæõù7_õöíÛóó³Ã£‘ИJ<ÑP¥ž©òvèüyÎÆ¡€pCD™‡(âsŽûÞ]ÓLîV_NV;ÜÕñ4µ h(0ŽORe¯åÒý§N‚ Ø„pÿ;Ê[nׄ£¶·v0óÅJ«ÿ§O×××wï¾û Õ6™©Žúg§Ç_½yõ†ÕÅéÉñh8à…ˆÆÁÃ^G$‰õ”ñB‰Óõ=ñS¶Ý˜ñUmúR«]ŒŒ§2¬s2Œ)–úòœ˜VÍvØÈÚí-7Ë¥,3#ŸL–“éün|{}#;ìêã¥WŸ®>~øt}yõáý‡ëËËO>2G\é ãÇOŸ>ÝÞÞȘ[hÚ¬ãBv¯'C»ëw}?3ª¦ÁÍ%à¥|œ¼:„ŽIÍ ÅDEQñüH?W=f3NÕN§ó錇Zx¨^îšKï¾§“pLWÔ ÇÒû0]Hcù4Qo4AEUÒî¡*J‰fBC+þáiQ Pfð[nEf™úôïü áVaqGhe@ùtgHŒ'´µ6„Øa7¹'[ DW°æ¡²e¶¸[°Zü¥§-Š*%ÇLJX6÷jg×bÂéÉßAm™™Š ¨‰ûýµ #A)7¬Ý˜ òƉ19Âx›3Áœ5Dˆ@!kœÔ¯ŽV| Áæð&*DE „à1*†'£¡$¸ë‹1 "B¢í£È¿‘R:–z!ÜcÊ8$:3OIfZ² 7Ü&”ŽIAPƪÞ…:b˜êé÷Š¢RsØñ&²[‚`ƒߚ„[Å*¾äràSàŒ™þiïg€pê„j¡‘Ä)ô§Í˜Kíyô»]¿87–¦ Ò*õš‡IyI¯Ÿfð'î¹ëŸ7ð&ž V—TÇ“úžfÒ\³Û7*ŽxŠ. kN½òÖ+mƒÇcm€ã5¹4ãáááɉ,È#–j(éþBPT'ug½îeáÉEÂtÆ#¤`*%•S߯Îâ3ô|‡ž÷Ë‘Ü7-¡ÑM·© d²ËRTª‘’ÙæÝv¿DÊB™BFí6–·&Ì´-dÔóô½ÐNÅq»¼ÿ8釡¦}JHÔr6M‹ mƒOèÌe3Ä7ÔWœÃÞטÚðMRu¡Že³'Q^º·[®fó£RƒŸ¸í~²Ã£i"O ¬îA96›ñ«É›³b«õ½6móåz:-ï¦óÛñT›¶Ëë›O×W>}zÿñ㻾{÷á»÷¾}ÿîïÞ—ôî»ïÞ÷þÓ‡—Ÿ>]]^ÉÂÓVÖ—¹¹/–µ ”¼Q¬ŒÊŠ ËÉT‹Ð”E”œAqÚŒU›’) Ùm‹x&/œä•“|ßeH°9: {¯ß\œ_p'™lYIô´û}-K«åýf½7¹›iª|ÿîýÝíÖ¨»»wgç'£ÃþÛ¯_õÕkÙI2´öyIGLÇÌj¨ÆTjSÅŠàãXMA‹Å½v˜WWÒdþþý‡«««ÙŒo‰ÊÚûê«7’öú͹¨?èžœÊl‹Sš*+V£˜6ÚoÏç+m˜ooÆŸ>^ßjû|}£Ý³Œ¼Ñ°ÿæõÅÅùÙk/ÎŽGþ–ƒ.ç TAMÿYÑ-àu R¨™Àik";£CòWopÂÜx©¡llÒê(·PŅ׉ìæ?"Û®çðtìcÃáy X8žÊýŸ4jq\óúÏZ©å_‡úP«@Gu£)oÚ]\ßÜ^}ºÖÎáêòš›@sM''G‡g'¯_Ÿýö•O¶ñî™ÒY:q»sIl¾î/ßÛýögÂc[]¨¬Ž˜Óð3×%¢¤6ztЕ‘à£dXñlÁbáKŸ\ýç2~nï¦ÚøÝMn.o¦wÓ›«ë± ¡Û±hÊwóîxL]»:߃¨9P ¥Qs‰¦PMwýáðøèxx8:<æá_n(ët=ÂÙí¹LAF4$ÚšJpahJÑvÃ*`Ûó8¿öš¼ \†æÍì6Þ4›-gógÍæRUÞÅb%cr±ðUG¬ˆM«Èë sšrˆCâAe{AU·L4)ОZ„dFý‡w+UA°ê ê%2ÐmçX$[1KHr¶€Tí¾!¿½þå§9â0ápˆJmÞDIõ4\Cá 6§~5ªÍÉ\Íù q¥‰ð6ż(©¥FÎ`¶N°­µþùô›Žò —W IQDÊÒ"¡ ·˜-´Ú ÎÈGÕ ðªU•ä)•PaUÃA^v&¼» …[ÿØÞÐ0P9Ã!D%Á ¤7ŽÆc ÀNÕ¾tqñ…:BÌ>Uõ…¥@Q« i¯ðœn‚p7?Šq#²0ÏcDÚ*!àºp{á í•›ŸÒavä—4»Ê· þv’Æ›’_‚2‡è~M†ap±¨Žf1öp’›:Pˆ~èû~ƒÏ"ˆV›ûï>¾¿™Œ¿ýö»ßÿþÛ»Éäüãb>×ëw:ß¼}óë_~ó7ó×ÿòŸýÝÅÙá@v[×v›¨‡Ë&ÐGmÍ÷ÙæH<ßǃÌJ_ •NÄD•(jDÅ ¡Oje¾¨yQI¥ßèù1)k‡¾^ûí‘ËùLVÏ|)›FÓÓz1Od -f³õ‚/ÁÈPÓ”w7žrs›ÕµDËäÑT¸á +¾ s¯?ìö†ÝÑáðôìôüõÅ_ýê¯^õúÍ×_Ÿôúî€Üýþ]ÍöÔ}kèe²¶Ee·¦u~ òäl²° o¯®¯¯ô#»MF¤¦¾^—7žûýÑp¤‰Ý§ öûƒ^ÐךÓã:ûÁàÐoïÉÛ“TMÔ¬šÊøÌå~·Ç Žö}ÓŽŒ‚P%”·ºîÆ´Ò¶Š³PTˆÀ2ddÚâÝA»ŠCl‚öãMH nZ¼maàp ã[j´8L8laí(Ð(Õ¤”‹XÍ”7ÆDx5Pœ!YG-Á £* ­ÇH3‚Ÿ„yÆ(aI…°£Cšû~낌6îáÕQ;…(­]^qŠ?D ‘»T ƒý}1[ ²…®Tâ¿3RY¸´´Û¦®ìH+á:ZCs4õ@îv¤> ž`Ì[áËÐŽ¨àÔ12 ZyQ» µÃ-¸—’<‚Ò:EaÕ ÈU£È¸Ä†/ ;Á.K¨Ô¬›2|*LV‹ÑvoAµ)z6ÚP¾­ê+5(j9˜)›úîÈ|VyU°­R_´Aj%ËsÙW—„H²i!e|á—„E@n84u´gævÙC£¨FÃêŠP¬û ‚AGz¤Ñv?‡¶X¹ÛÞÏ ¸¿G‚ÿ?2¢îwÁÝ]HÜ}†¡žÆ lZëÕ»££Á³#â?1ìÔççQï¹ßð®€]ÆMn˜kAËùr5—c³â{c«õb½ösN{+îñõ·ãïïW&ì7Ûê!<Û%¦‰ Šï ø²©¯pêÐ…%ʹCíªy}%oÇ$…8­¸XÊoúó÷ÜôæG.6+mÇ7k¬Pg«ÿf’G³czÀ—)öCáìþ ð°ûYsþÂ~ðžSøËKQ9ÿDMþ2ð\µíÿÿã/+8lOÉtPY¹ì'1ä–m!§âåå‡d LO©gLÅ0OxOO" ’V[DN_A“_L%&H] T(ú“·«½»b8M§=V§ï=¢ÌMlj ê% Š2ÓÌÅI÷1OS]]^¿ûã·üÍï¦ã±¶dý~ï—ýÕë¯Îÿúo~ùö›7Ç'G¼.c¿³–íÎù6ígE¿ÿÝ»½ÕÞÿòÿû_.?~\ñ¹„I¿³÷¯þ³vzqô÷ÿü¯ÿöïþº×?PZÎJOÕŒ,&6|šXüÀíz1ù½^j‡±?¬onfãÛÅø‡ßÝÞNß¿ÿxss×ët¿~ûFIÿ÷ÿùÿöâÕÑéÙðüâè ³ ¹ÈD%yç$Ûz±XßÝÎooÞ_÷ÇË›«é»?~òGÃAïëo.~ñ‹W¿øÅÛ7o/^¿>?;=Ô¯H ¢U5š&QŸ;U®oW7gDìx±)¡Äx g] ¡ ‘ØloÍ.ïKU€þpXHrá•O‚<° œR‡o ‡ÈÅi368¶V®- 5²ý B)ökªT·é4Ei ÙbœoS—>ñ°\odüî÷¼º¹ùÝïÿð›ßýv:›¾÷ŽA½÷p|4üåWoý«_üú¯ùÏþæ×§ÇG¼¾M3¢Ôœ8Á¬S»øÙ¤¨å/Bí[ß?Oó©íRpš*äù†&òÉÁ ƒè¶Lƒ l†M[IÎ i ã4û|qws;/?^ÝÞÞŒoø’±¦¢»ë땟NÀR»ÌùJJ<“Î&œY'þ|¿³†¬wt{½þ¨;òÎð³óÓWo^ýêï~ýêíë7_½=:9Ýïv4‰ñ:UNjt|R¨V^øP:Grk\º(¾2õùv•Ú™ÊüZ,e¥M'“»«»OŸ>^~útùñòêêr1á©òãs0­7\á‘„¿sØïöG‡û>ö×ïw5цŠŒFîA4Ž”ìôìl¿×Q”,?V`U<ÇêÝQõÔ5êÇ}5.ŒµäÇ“’Bœ¯È©Avš $P`»ñÖ^ç ù+Ó„ ‘·äc‰„$ƒgù8£ð8¾·ÇæÞ'_"\<./,‡³—·r)Êr_ ‘¡†³ ɈTñc™‚¹Ð­Çq_¡œª7¤ ½c95$¿âtD§‡P@G1¨`‘Iˆ…Ó=ç-·T¥´æáq'¿[Í¢Â8 ÂëâžVÆûår©XõÙ¹ ’Ï·Iªùµ.ö áÐ1â‘̱ò»¼5E,a^ÜCýL%Èo½÷4,ñšÃ­°§^ŽyàÂnP“ÜÁ_‚2’Uá'öˆ²ìk¼‹Á§k8ß&È«¬.j¨Çéß”qÔ_)ð(⮣ò# à¶>4“ôp$œÑ9²1Ìê*e)›…z(ª~™ÃéynJB$3ðØ¥¦Î„Z •!ŠtÇkE9«nï3´F¤TÊÉ ¸µÐ*…& ¢PÀÕg6y´ f¿ì»¹dkVŠ÷”а˜ãËV -ž   ˆ¥2äU)4eÏçìR—<Ö¼C˜3Ò\¹¦ÕIµšÈlêÎ Ñôæ´–¬.áoC†.†@‡ÒX¦šÉ®äˆLQ¤r8 Rxˆ NÓ"ßô´¢Û¬m÷óˆü¿*¿Ò¾,«rðà€ØC §»‰ëAa¬î«¶QƒóØ÷€Š4@x¦FHNkÊv.^2MFŠ| ÃBJ~™¬Æ÷ÅŸ£ùÈ*FÌcÐßéþe01Ù[¨ºʬ’Gȯ‘¶á«-X? néŸM煉ÛÙäV¦h6Ïç~.߉]Š•E‚üh¦Æê¶kÑ6P*øRµ3&47P´QÉÝù:Äój"”ÜEÕ{š4jêdþ̉”Þ™Âårmcn9[̹Wo:¥ ã wæÝe¦ŠnîîxˆŸ…{7QÁE³Éd6™Îy‰ ßêØp¿›uCSÍ]PK)¦&y] •­A[ù˜TCQT•¬8¢¤Aº¡¢’In¼-Äz!„èf]0<²€Ó6i[EUÃcd´R¾ˆÙ=â3045`x ™®Ò„\ÊÔ9µªòí T ¬B²³<ÞN®pl4yI‘°$1›9NFMòVwµ/„D²ç胅@B JfɈ€vÈ h¤ÁŸÎ(¬€ƒÂ5ÞlCœ™»@lð‚Ô¶@ÿëÿóÿh'p¥µÚÕ5É1D»OÇ&ØøõÑ%Ú¿ªpg ))¹øDޱÝmi12’K?-€IGlÚ«i¢çø.^ñŠKK‹F´6tLsÓé-³ÀÍÍõ¦öjýîéùÉÑñðôŒ—îÊ‚“8u]^}útÉ)èÉ„ؽîñÑèüìøÍ›ó‹³Ó‹ó³á`à­—OÛH–äÓnÝÙÛü¨h·W»ùªƒþt°ôÈ·W3U´«3©0µØp:zBióæl:žÜ\_kâúÄ«=®¯/¯xøàöN¶—G¹NÊUQ7_ð± =ï9c–å(¡ˆW¶Î˜³ZþÖËèptxrtñêµ££#m}² ¤³¦\Äpbëä2޶úÍÙ·Cp 2õÊšuŒ¡ñxÄdª²hæ âí,¶Ål±áydl;îäc3ë‡÷}!ufËL³7·÷ÉZãñŠÙÝøN“úx2–{n«O¥Ÿ*Œ=äý}§«å ³Zhpæt±8¨ Üš”""DÁ¸˜É¹Ã^¾H÷9©ãað„O™õ°œlÍ‚Œ!ƒÖâ3– ‚ÐHÇ@ÜLîw@.§>nñÌa>§gs]agò0øÇ>Å2®’k.En…G±Z`ï.”¤†Ó ;Yb«r„[ºº¨kDlÇ Q4R` "Q;$±Ã¼ÃM¯Šm#ü NÑ F ®"J]—¨~*DƒˆWY$ÄçÛä0sv>¹;ÿåó_„•‡ÔŒGLäF&üⓤ*1N¢F]VѤ,…q³ãT,rh'QŠsX-]‘$OkO¹ÈÛÕÜã+¤ØIi·ñ˜‚§T:ÊöÒ,À‚4]hŸv£MO1©eÌôû³óãã“Ó³“ÃÃÃ^?í6%|¸?àQt>ÁŒÝv¿¾ÿðþÃx|÷p¿‹ì¶¯¿ÑL×;??-v›f:×f$K•k*vnLƒ„¡Ï”¡r¨j)팹(Ðí ýÓ“ã7¯.ŽŽ_ýæðhÄæ»*œ Ëi?\•ÇÂ&‹O5‰//oDšÜ4qw¸ð!eÞ¾}õÕÛ×ç*×Ñèð/®b·å~!V̨c+誦Ž]Ûá¡;â„O°›_;8ꧦd»ŽØÒçoª¨! m1Ç,jBfã G"b‰l1ùΛê‘Nùà1»|ö”˜ˆ l;³ÜçùŠÚ†Ñ%Ôˆ¶Û¢3DÁa(.F¾ß¨î¶ùãß]ߌÃnãÀùT½l4쟾º8}ûæ"í¶~Ÿáà Üpdëëÿ§³Û4/ºWTw«ÅÿPŒtn!ÓVÿTÝÒÍÝÓ#]“*M ƒh7…Û€[Cd¿Lgw·w×W×7W·²Û®„K¹oÆw“õ\“”Ì5îÓ´.Ûˆy5_—Á96¦2 'W‹÷÷|J¿3µc=–ÝöJ ì6m±ØDbò¨F#´§W`£ˆ\¼,#y*+‚`ð¿ç¿€¦»{é¦^ÂÛŠî&7Úw^ßÜ1ßqOo ‹ÓWTý ©¦5l7eÚv럣6¨i·Çc9ÃnãlÝ|¦¬å KU*_ì¢EÔ¥ë9T Ñ”ÿŒ'ÌžlÍo²)ÆL§d¸B¬¹‚3&R—˜3(²Û…ÒFx>Í€TA5™±˜X0Ó ¼Ò‚ô£H¯åèhްÙpEƒ˜‘LyF\pªc V5`I ý†:ŒëEq‰8°¬U‹ÙòX9#$àt@îš©óÇÍ1ÚÐq”’Vá;0S8<ÁV‚ÂAÑH‡DËÎ3JB²9JÅáÝ‘H—Û ô¤ÈDÅÜáWvê+;v[(Eÿf(>p ¶­Š|„¨ÓÀsœ  ­$ñ=‰ †´˜lû¥1J—6PÅpfËõÇäEÏ产ú0 ™mX¨X«J]EÎI:Z©×”YKZ¶5V?IclS‰$Bµ)¢øÚ©y·îa8d±õ†ÃÞáaÿp4 ±½ü ÌTKmé´*‹ökn1æâ” ¸WC¸K™MÆþýAçA±Œ4 >.üæ•_çVPfŸ¨,_5—ƒkY•¥h•(–OkÖØRʧåžB¥º¾„œ£4©íéÜ™ ÈKÊ‹èÕÏRÕJ¨Q/Q–TG*Ð:ÿ,ôgG£†+Ë•O¥áȹŸŽ\óF­‡ß.âŽXdˆÄD´åèj³`1Öã-êùK©¤ÿr TÇÚœ?”ª^»ÈXsdv· n;«þ ”©ÝÁ¦OƒFF—e¥ñ¶¼%^jÞâ}6ˆÛlCq?îRµ[{,=·ð++]¤}/—´¹DP¦Â´NÐɦ^¨‚È2šb0ÆxÌ@´^á(1žMË:J¡è9ÞŒ«˜&♖ؤŠxŠ‚³†\ó]Ê„]Ç<~1_- üh¡ <®À2z¿^%º*É[‡¤2´DH%ó°ÅÇ’£a³œ”2š!ŽÚr€ªH;[Í|¿ÈÇ÷Ÿ´íûøáÝd|§" bÜÿå/¿><œŸžžp§o§#E¤»|{¼$Zšd…Ø‚Ö1ôTMh–äŽ=ép|vvòêââÍ›W_}õFÒÎÏO‡Þ”KñI@õúíèkm5?|¸¼¹¾ýÃïßËñáçËËUKg¿{||ôúõÅ7_óîo¾y{|<Œ¤(74ª$'§!oòlÇêȬ¯V‘…G-Ú–…àTž1CÅ=¾BÊ´eNÜ\Å% á•§Rix/ô/ó*ªHN¶r¯\…ÁÌ QEjÀÒ‚¸9þcäÒ$­ìmwxZÅ Úá?œÛŸœHäOõª®Â¬W”úÀ¯–Xs‘t¢4]ü‡ßþþÓåõGC›ˆ‡û•v çç'o_Ÿõöâß|uvr|z|ìA*i¶4 ä5¸Z̨ð/¡†„?XÎÓȾQKS@¯cäÑïÌRížgD5Ê0/ä`†t¿NýòÍþõœOÀO4w]}¼ºútŸ@¸½¾åe¹“©¦*¬ 8‘vÚ€’Gž¡˜¤r€£ê¾£}a÷`0h~8<:<ÑìãGx{åáq·? u˜­-D",ÆÝ@z»0„æ´¢’û\)m¿¦.4’¥L4îl›M¹B*å?}Ô$¦™—¸-ùR†YÉi¸ÚË™¹×9ȃ³>ÓÆ¥R_eÎfS^T>›ÜÇÜàfí?èËjëõý ]·3Ñ–IÃËIü»ºSCŒÎÔÙ1,#{œoóô%NM’^LHòGÈ‚Ã)ÅWŠ “Ñ<̯UTY?£ÅŠ’dÚG~˜OY#b•k…öÚW‚”D!x ¥#ÃÉU9™Ù·ü5·ílwémb,ß×^jÁÕ!1TÀj œŠuØ—íap.]ÖÏgEBÅ•: ¦ ²WÙ¢ £²ÉXÈ%óò!‘4yˆM¯¢ÄhY¡{ÛTF¾¢¶—Vpéß7ƒ#i6ÔLªe±ÐAT—<õ±¢­g‹²)œU*ÎÚDžv¼§(¨¼Ø ­ì£„¨ Ám!xÑñÌ¢Zv ‘RÔ 9ƒcû+Á=¹0a·çω¨ÕŸˆž@F” TPñê¨q±ÌÊ…¨!TYEºç[çw¦o×;í]>:QT¬ȼ©d¦{i ¶Ã\qx†4\ˆ¬*†ÒL?lbÜÚhÀš’ ¡“œpBê#Žuþ2ü­»Bè=lÜ“¢X ƒ©ªëô¬.Ž‚µÈÈ’:Ø¿ï(ûý¿öÏQÌå2™eœ{0ÈPÂü“ÚR„ÐÙY„ZïLø‰lžFðT™:&sÖ¹ð|ò%ï"¥=F“gƒL }Ÿ,*HôCÒý@„žBú«æ¢hæèAÏÀ) Q](D`Å“ßßGª{ÂLÿ3¨…„*¯»ÒÖ¶xNÑŠ•^¶Ð!#à 4ã0åïªO.Þ¥T‚QÿM€þÓQ!E1|© `…›ßÖ©E.,jc§Ùj½TI»ÝÎpØ?Ú˜q^J*Kt$‘í$þ†Þ|Ƥ¦S W¦Ú¬Ž†œysÂý˜T­°UQZž–’ö‹èOÛ°ça‰äqÔ~¿st4:==<¿8~õêäÜOH TñÚi‡…íõ=¬WËÅf>ß̦«»Û™h|3™ÜNæÓyh%UNN^½:¿xu&!ýaç «|TqÎ_ûY®û3Dž>((3):S¥®Õ˜W2šÉW<VÜGb«K<쪈Å:´Lº"³=yá§ù£˜-k¬á‡rJu’Jœõ±õi¢ -^PUŽN±EÍ µrùb²²Ydçø£Qm…;úÙ ŠÚʮ֦ñ`ÓÕƒ¯Ï©_sÚÃ7itð õOÕ”:tŸ¯« ŽŽGGGÃÃQ¿ß— ¤ÑÈs6 }Bƒ±\S© 縭ÂËÞp‹moå´êMk×öŸLÞLÕAAvà– Ø¾p᪭·(û32H…­æy5=>š¸GŸiˆÛóáF¸_k*‘y¢!.;FJˆWfž'Oú2žmÅÐpC¼Ý ·ß²¡¦Ò Øðº¸B[ sMT\¥ie¡Ú•)Uiãâ-Ì»*0ç#xr~é7,ø˜•XTô2² Û0ÖïC»]ž­ïö»ûR®Ë;v±áÒtÃÔ¡ëì4£TÊîìšÌ$°©ND9¤|fJGÏBLAÞ@®¸ÂÈ­úñðeàòõf,˜8;- £ÉòÙ3™mpr,ä§¹Ü`¶¶5¡uâ{¾ë„Þà>Q”ŽQ`DTdX¥-$kO±JÅi6Û,Ó/0£Rú‘ÊÐ\MÔ–¦gY™;2×´M½y}‰(9Kf}kNUÉ4%c˜æca©]*l 5ÝŸwÆ»Þ`@¶åE [°’g6…š± %™ý ø½*ï2õg@2àE¸O$h»BªŽJÛp}žV2ØZÀ3¼»pRýºo}f~5{œ™ÒÈ (µ;PTTòU¢ZK_Qò3z¦èLuoñv¦¨-½H‚¥ZQDESìJ—¡p_ bÓ£4»7Q¤P¤¨»ª‡(ohQZÉ6kÌÃ1TŠŸŠP–<|Ü—b8®(êT®\(†!º[ ñdǤä“l&îâhaß©q®$ÎJ°K–rÒysµrB¦C/K­„‰¢¥s Âðp ãÊ7ºÒ¨jý?tºÚvº¸÷;ÚuʦT­p‹‡«Fì­W{2Ú8Ù6[N'ËÉd1,|È› …2 µRކÇ'£Ñ¡–Mi劈Ši·Uhh‘µÓÁ¾p›rVŒp¸jx›ˆS´^aÈHýS÷åÜXDi‡œ“]TQ´Oö—poœµˆäÞWW†2F.EZW‰"6Ëk’j"«ë%¢ÓÛ‘ÉMm†LHöI†íð­ýäÔ”Š^Ñ8ÂQ¡N!ߤÄYžõÓò뛫¨õý¿Ñoä±™±íó؆Ô_´¿áö¹‰lˆ1E€‡ŒÝòDkš ¦Ú¸öÚ½íåHJ$…‡bºªÛQ? ¡m¨ºñ³2‘oÄ–ÜKˆ¹I@;y½Ec–dÖQ]óæjáM£ÏS-ç8x‰¹i-E}¸Ròbl“¼® MBœq£½h2ì¶ng¿{ Þ:ÐD|ÛÌ9È[3!‹(O!J²9 Á/%™}4‘ÉPó CÁ/ûK«?ÏB™Uåv¡”ç½_ô¼×9xàòh¡2·O.jæuöyµ.„)êó‹¶I™–Õ'P-t,ÇçIµç–PÂZX@9DÔÕ„A;±I†çbÁå…T…ö2“6B‚Àje¤¿Hªšk1 [žçÉÝKyA:Q'¨]— y°TÚBU­ØlŠTG¶èI¨ÿí3pÚŇšqÁÊQíRdß‘½1Á™³B$‡!XD=-5…KF’¤ž8ŠÙE·‘z¶‹‰»œŽ6Ù^Ò°ˆáÙd»-c[ã•BI‰pÇ\Ätä‹•ª%ÓáÙ'Œ6%)¿©R”"Áô iïèÇŸ¼WÄÁ¢ÖAîpîYo÷<–9c©¼U ¾LÙçúÀ¥Fû4çè:Sù-U-ªÉÅ×W"”vsyT œq+Š­§fš_"ꇉòöWÕÇ=m]©±Ç-nÐ^§ãjØSýpAJYc´­x9åb=ÏonÆ××ã««»ë›ñd:×ö[®L]\œ\¼:»x}vrvÔvËò :£غS P‰¦Œ»`²Ú…¬´»J{K2àpw[*rÍÆòi^9ÕQ)º‰ÝV¬ÂCI% rcW†pgl+¼‘c­EÛƒ/‰&3¤=Øg)ÂÑæ©TwÉ·øOŠšb¶*ÍU£îâŠnSÂ]½:¤Ãca¹œÍçc>V>›Ïø\¦Æ²F™ÿ“aÛM]Lu¾Átƒ,HuŸsP€ §eÍÇ1(Tm{«»M[ cš°Š@gTÝŠ ª!Ei¢;¹ ÖA5RyˆãX‹îÒ[C×¶R)^ΘvAœ%wuÏyÆ|:åÝ“ÅÜ_RµkƤY$D²j‘H6r.·;ã¤Æ¾Œ¶l°ÃQ¨Í^³Z¾Ìc-.æb½bFÁ‘£©U¡‘YÚF‘Ëi¶µÔæeL¢ùB&¨~-QaïÞo8ç22×=%Õ'Ø4Sñ©Ñz¦-½:zzb'°…Χ۴)/ÛéP)r(:VÐ[*)ŠÊ*‹B”°50D5 U’dWÈõ§ÍœØB‚ƒªëŸv µC9Â-·âÕWꆞWÞðââÝfÍ—.ÅÀ®ñÀ@¸ú¯=‰¯ÏÑ$8Ä™ •o’äã OFëoy=>ò¶>òÚê‰ÍÜ2”2ú‡ë_CtKçba;E6ZÌK†Æ<ÄcïxÒâNWª>®5"U,´™‰âºŸ—ñ]¡y½ŒƒÇ»ÛJ«€&1·j¸½öùðX AGO„p[^c·mµ\õÖ„‚¼íìÅöŠŠÃ>ÝðÊ$­[d‰b°¢¬ß!¡,6ko͈õ™6À\.«S´×õ4ˬ$¹ôÃy¶™e¦]Oõ +¥â¤DeLE]ˆ}Ïï=ŒôÏfgT9V‹£¨ú…!(Ùs,m!/a‡§í ·ÞŠ ÝEô×-æˆ<™®ðû’-fkð”UJØêÛ;TaN@ïK'ÈèÀŽ÷y¤ùÐêISrŠüÙŠîe…€ä(ÎtÏ/eÈ &+¾…(‚³`쉒ƒ™Àr ‡=:(žL4Ëi—'s'ï áÃ’Ƀ¤^ï`0ìi»ÉÅ.ß9ÕT¢uÉS”ó•jÉŠù¬Vä,SuÚ«r¦­«*†v÷Q«“ð„"CŠ9Eö^Ì)J€(¥ÌJ«ù‹Í·¬.ãµEš«y `¹ßMÇw“«ËÛo>~¼þøáêúÓír!}öµ[>?;ýêÕ›7¯ÎÏÏŽO}´³sd¯#ÙP›"gm7HûL/ÒÖüe4!n§¦]#Ðh’” —G96ê¡p¦†%[K® \!Ѝ­Ø'‘ñ¤Ü¦ï%AhúãàÇ“ô¥ÈŠ®¨…zn¬µ éÌfþèˆ1ó´ÎrÅc1êfÃÑÈOùŒGÚCô0œ–šÎ, )ˆœ ½à­îoÅŽ[´“Jô³€bŠ”»S–ú‰Ü5½ì ñ…?ŸÎ‰&% ûÆ7.üU`ÁÊ8ñ§ª4)1„”ÕKe¬QezåÊ¢ +»ÓÕ$6 FÃÁáˆù{ÜܦÉi †X…ŠÁ¹·2´ÛB•e®D“TÃÈôº m³t–æyÔ¡4ã쀄ˆ`fDGŒin¤«Í<²?ýч~o· ÚËn÷ñ Z=› aÄR„…)Oòeé|(TIW Á\sB$ë‹êSy/'ˆ¶¡J2Í#¤è E{Ci‘È![lÑþ/ÀëHÿ6žÈ7 öý¢ÚȈç±Ãzº'çê/dÜKPoj-„FH¢öÜ8ÄQÑ_â›.øéRê%š„¥¼¡ŽtÏ>@ËgÝ„†Þ,ER”Üœió›Ž|–0δ)JýNý,îÓëu´UàÑ ¡%ª%L¥H kÑè[æ48 “~’ÞL!ÛðøØ®†WÇ‘}¢…dxÉe¾z´ÃâžëQ±…Xã#yEÎ…u¨þ+’3\ÈA1-yŸAˆ È‹”"ç1BòcDª´ÃŸãi#óøbHj¡&­ÝA ¶Ý=ä! RòG’ê/•\Õ.wéÍäèròÄsà ò ¤€@¸’†N¡Oq!Õ“¢"C{)Û8ÜšÊñ0Š™À“ÉÚø¸‹Ð„9!¶12¸|l—v4mÅÔZe4ì5üUi¥‘TÎâ Qî•-K”fŠ.3…+CE3o¨¤zi*©T,EQ4Éù¤VS\M©LŒšâÈÑ»÷¹T¯I}>[Ì&³Éx>sÖm"óMÓøjÝíö‡ÃÑñÉÉÅÅùéÙ©Œ·Áp u”‰íGæh›ò®Q…S&M“\€a*7y’"ï(Ž ÜqWœ){‘cL¥ŠÀ¶Ñ¿¤.OÓµÂXõ½?XŠfðÍpy‘Ôµä@g^§Ì¥Ã>ú¨²ÈÚ͉ý3ÞŠŠBUR”9¡c¥”õ´ù#ñŸŒOÒD(ô²3Ä@ˆ=e±ñ©¢ÉDÎår¥~ Ñëö¡£'Üx¦Ô”ªû¹9 ª/r¸ñ²*Âñœ·BÞ¶Úµ5«çþ$ ë¹×'\Jú)Z¹ïy¨@̲ÁøTØx<¾½½½ººút©?½Š/òÒÛ›>¬~§1ψø'öœ?“`kG²JV1ɸ¦ B1O?ŠÑ,«yï ËWŒeæ`±ù µ¤2¹áR¯h„,F& 7~Ul¾m?“ÑÆ—UçSì6.QÍfsÍz*“4?NNŽÏÏÏÎÎŽµfö]MÓÈ—4‰Švù´©ËWz ŠCºåÛœ&ô³Šé¬ì´¬U—d3¬Ofù2Bó–®@u·ò·¿¢Ð²5­l%}ãwÔùK‚ ›]_F“«x³·; ­·²´•˜N'³éLFÜfµ—ÆÏ ×Á`;Ét;ކ²Û8‘Í~HØë®;ƒ²ð,Ù®Y3ü(5úçkîèNÑßé¶®E å…!æ#îÛX,ã+חן>|úøáãåÇO—/EWŸ®®¯®o¯øìú„/Ç«¶Ù¿Én[ñ´’-ÄÖÉ™«j%¬í6ÎDNÃûž67´ueº²MRƒaU%¹:C~C ÊP4±´Dz¼eúÐ|ÇDÊ=‘kY¬~$–‚¸(b,3Ež”¡ÄÍŒHÑÑ›¼Ü€R­Q¹¤ˆåCýL»èn’5ªP3¢÷Ð5¤†þø{l>™ïµ€¢/pã…ß=ØÁˆ²Fɼ¤†åÂ1¢ÚD3©ÞœÐ,V 4H ó$ž Â+™‘E‘W ”¦è¾•}HxŒvønUÔG:ŸC¤k%uš˜ÚáÖééÍ5Ú&[o°àÍR)ê‘Z幄ôè`5PIQ¦G¨¢+Z¹µÉ+}…m¶Üƒ¤N[@H•"Gã@!:‚ì0gÆÝ?h/¦]çËDq¹SðI¡e6u};®*ËÆžæM9’ÊÆ„=«6~1„%Z|xì—·¨§â8¹äiX!* l˜{ “à¥å-~µiLy\–ZK(@5S ‡ýÑhxx4Žz½J ‰\…€ ]Ð"{oÔVÔ_«Ê2ßPöj0 ’L:*×l”¢‰à€ÔBPÐŽjG»OdšG¡„K5Ô Ö5Õ—Ð b娈ð]gºŸ!‰ÜÍô/ . ãY½‡gôJ³beŸñºXv@긫{õCŸ0ñg#5Nö:] ¨=™j"ž±æ¢U®ŸŒ)õKŸD‰F”'ý2rr5G};Uþƒ«GÎO,¹Ún Ü^é=ÜrÄÅèÓÐW®›Åd1ϧ·“ñÕÝÍåÍÕ‡+ÓõõÇëÛO··W·“Yv“Ùx6ŸÌ|ô‰hp•qŸ÷Iy NÆgü–Ì¢é‚4@l ©a9#ï)–)’¾8\[™²‘QBôë²…ËnXQHOvy™BUC 4‹=0ׇý@ž™g3 ¤çe —e¦¬<Åa˜²V«LÈ̾æR3¬.aP)I’3±ÐR!¥! ‘ÃúUf£TÄ2ERr3×ÇÈc‰ÚgV>õ&Šb2àD¢¢JÓgeµÓF,¡áxb é˹–¤¡•´¤ãÓAèbÔÓ÷CÃâÛÈ|Ì®çU ýG’bpîÂlœ)Å@T:¿µ]£äQ½Ñ¬‰ˆ 8öi$÷ž Ån ¸«a¦x×@ÛÅK¦³6é*š%OÑ,n±òVj—@ì© zs'ø $M$[§Y¨Ë™yNÉN‘=#™nŽ g­aêG®ïyNSytözýƒþ°3ð0&Àñà1{Øܯ÷ï×÷«ƒõjŸIR+”O3,–K±ôö»ýƒ^¿ÛtåÞã›L;žX($Õä†á9}åËóbDºY5EqÝ ¾€`å&­}Ú sgS(OE‰4ÁM'‹ét13xxÞŸN– YCYlLJ'gG§çÇG'‡ƒ!WÜ?h?>Ãtãf×YhÅ)æÈ¸l!„¢>“F6P‹AR å7(¼BÌót„(]Û_‡rH0‰¡}š¥ò êTõ$k!&]Ö'ªfÒ45”Îb©µ ;”/¦IÉB?:'lVœ ‡GÚLh\=ô:½ý}žïkš6Š,œ5ù’+Ã#9º…WG«Tt~ŠZü 9ÚQB„ìx+‚¹â³ «We"­_t‚§t}ýǔŨÐܬöV‹‡Å”ýح̵O·—ïo>~ûé÷ŸþøÛï¾ýÍ·ßýöÛw¿ûîýïß}úî£m¸[Ùp“ëñìnº˜ÌWþ^‚OVi^ãN5³ £ÇÑï÷â…ñ"rg,2ßÄüds £MœöŸÜ+R¨+»‡¢H_ÍI0»©*ÕôÀ ­òyh8EÄ3‰€Û|1A{¾æÆâ•,~¾¿œ‰ËÙRÅ_-°áüð‚§oeÛÚ{ÅÕÑ™h¢¬ó¬Â¸o™ZÝ×F|o¯Ë o\e"O}¥‘HЏ4È„ ­c!*wg‚h'­Iäá-ô~ÇÓ²·4AŒ  £”©*Z3ÿ&`¤Z¼%\@.ë ÚæðàZL<©º Elt‹×·1E!µ«§áËDžd‘œª,·ÑCâñ’Ã1†XÚDü„WÎ4ðõ[U9ü@ k±ÑÄFH#:Zíš±@ë“hÖ#³TMÚº5p„TÇ#D󵕯To¯ä4/ñ³xܹÔä"©î=”£Éh Mˈ´—ÉëpÁ#ðIÐ…\öÆ–¬yY,yUæ#w|ùu)QÖžk2Ò˜p*’Äü§¦êÇÂU ¢ss·3gº¢Ftðÿ8Kç>2)nHP€G;TßO²Tmi’ê-H'7½KŒˆÓ £NdîîwDÞsk…ÆKpìu8Ÿti DkZQŸQ2©ÀnÊS:fÂæ—’ˆî…ƆrGO9.4¯-™Q4åù">¯ÌòµÚ½Ñ¡L¶áèh8<ê÷{½a§7”5)­öX%Ô.ú6¨º¦ _„ÇÌ.ŠˆÙ[GÕ¥ðy™Yº¬°àþ\š6Hÿüªó’h»T~Tìˆü¬·Òö†»ûSÃyeÿ³ý ˜Û9¥ãUOÿ¬{ûZd—«‡•§ÛÂ`ÐÐxàd[oïhÐi;Ä'Ë9ñaÉ1¦ª»Ý/#ð ìŠ,çóTù¿;l½íï.¨±v_lxIÈ¢"#xù°š­“Õân1½žŽ¯¦ãÓÛ÷·7ïonßßÝ}¸4}¸™\ÝÎî&‹Él5]l–+ÖáU¦G9ã9¦&;R@esU”éqWÜÏ âÛûû½®+ö²­²Ê8m%)Æï¥ãEÀ¨´¾s¨ñÕâË}ÐŽ1wÍpëûõ’µGq±k*z·%àšÁt⨇«ï\ñðmY]fTˆítw¿ÐáÏ]ÍÏ”³iM芪vÛšÏÆ#´#„ÆkDJe<Ù‘êXÃúÅ’¿§Y ¨`ßµÏ^ÈÐ)±…ŒPyP‹|ӿʉã 4 ³¨®BÅéNG dß÷†í—f]lŒ æ|fŠ€f»%º,}×È”FÔ¿B*"»@½ˆØ“<$K¼ò háIC Á¦#7â?Å/…m³%ä=Ð*Åÿø…`%¿mV#»…b&ͧjd#(AA6v™Ø¹LÊ@IÓ"Hh¤öL<øä§w™ü Q‡¿ýÀ8öQf¤¹Ñ*I’v{›L Ùl1ÊÅ%n¿Ô¾“9÷¸| °ä ª²Ól6ØÛ¬—÷«ùz1c›ˆ\ù‘Ð{ m™Jš&â©&]L¶{ªI*^®¦ÎaZÉJTMkt-!¥^ åÈ ¸¯…¯·šoæÓ•Ž÷ë½õêþêÓÍÕåõx<žÍ§j‰£ãÃãBG2àû~¡I·§i˦[L>ª^õfõdS‰£ö¨jJu-=졚|P©ú!·n›”ÌmIy ɲ튃ê·ÞwS6ˆÂ%Å0òæQ­ŠD¬; •Q²5ц …Wp¤X%™³ ’nx|  4³iž¢ iá.!e×dždˆT®(d{ìˆ/îo!˜[©‚2+:©íÞñÊýÓRV:4ϨB¥Ÿ—7ײx[ÆSj÷²Øö7›ŽÌ†ùr3_¬g~êQ›Öý½M·s?èî ûûLJ½£aoÈs}Œ¢4(KžHà¾g­—œ-È‘cRlì6žôîR¨ý9g[N9ZAŽgš/y¶cK¾ENÛ[8!Çîs%Ò£9º§tawãþÎ4q¯jÜ߬÷V³ÕbºžÞÌÇ—Óñåäæýíõ»›¿ÿtù‡ËËo¡«o/oÞ]‹î>ÜŒ?ÝM¯Ç‹Ét£Úçqøç=fI ÷#;NsÐg‰Ö`õˆgít’|V¿sp/÷pÐã tE²ä2üu”Ù¥DªAM=h¾\°¾ßÛpÆ'@©\ÌjÌøžÙ€'‚|¹ :æ"F—œZ­ëÕœ—€HK™Wšë43nya›ê(eæ ƒ¤ŠqW±oÅcÞ‘ÒÔ€-6¯ }ˆûÛîÀZ°¯¦i%)Tö„ÓLb,+ìc“Ê*ãGbÍ9Ó¦9 CèäùMf°gôG$«ÒJXç1Õ…bžg|™œÒötÁ\£È¦í’Ȥ!há5áª0Iq¹$_b‘ Õ9Ý•ê8«$'œ•‡f”î^Xiú$u϶yÆNú—ñ"¡Œ2 áÞB(ƲwD»áÆÃß%ͺùd'ËS%2¡˜xmxÈAW°†¾±I˽V8¾,IVœ–aªÒ„•§Ò¼üj‘4ÚÝÉ=ئèh9^¸D>9eÂ&ñY” á¤ÈÂf“ ÆçÉ0ŒZU"²»ñhágí÷VƒF©ö›NݪT%q4Sа”-~x¥T“-œBk…¸áÝöÑSªã9´ãP„”¦ŸÝé¬ÈT*ºwQͯZIÌ5ÍáÖ"gSTˆ9Ëmå*ŒÚhÿØŸHÖj!#ŽÙ„®^w¦hºŽ(ZÂî”ð*Ce´ÂM"3k3à"Õ·1p\ƒšÖ?mi•\´â‰®ÓâÛEèÕPvâÏx%© ,TòüÇ@nAŠî‘å@U¥gOêÔsپϴ=,׋–ƒì6nX.Ùj`·í ú<—0ìw‡}Mî*)e¥q­)Ì‘ûht¤’oÌAÅîÇ”üíš,}3Ý[Þä•!J]’$sIÒŽM*OR•CZ¹£o:¤ê¾D~‡¹Œ6®kðRÉùf9_Ï&Ëùx9»]Ìnæ³ë™i>¿–[4^O¦7“Ùíl1ž-§‹5æÎJ&6«(à ¯¯¬…˜W„D€Í9È \¹—d{ExzÍ}örÎE£–³®E¶(O‚@—“bg=¸ð,SAшž%Ä"©^E7܉éæoÉÓ«B;îF‚蜣8ŠâœNùèŒ^ú#?¤*õ,zÓA,Ľ9duF_k¶bùeƒ8ßýæ‹À´Zb†nf9×I=6d)É µ|xe* ÊÑ3SÉ=OÅ *mYãp—çL©`rExpfg³¿AäU^ÈyÝ\DËä]*+ò²×G´EŠ“Ä2 Cv“šÐ­ŒAãVÄ­>g œTì’F-or–’’œ3X÷ Al˜Ž 9Àœò)?KoC‘ÒžBˆ2Áù43»HÞÙÆ'n´F®V+â÷ŸÿôIDAT«ßïÉP;;;žŸH-• (Fˆ*Ì™—ª•/û‹ ¹’JLÑÑ‚äeR yÙ6"náq¸+dn¦h ânPcÃÑÄES¦t€-d$´)zÍÚ,»pènxQ¢˜úB—çDUZÛÛrÃ,‰1‹AÔ? ªú€ú¡—®FyªJÔ¥D²9xôf³\m˵Èýq¥a§Íª µA¿+ê÷Ô±™ÚSp¹ã¨ÑÁÈŠÈßxÕŽ o›jÔ÷¢L˜õ›L³E*ì¨X>‡à„œ°„yXE £)¦m¾¹uy¿\lV6Ý Ùj9YqWêò~3ßÈ!ZMWÜÍ6[®æ¢ÕF¶ÎŠ“ 6Óøgr‹…2à“"i‚i¾ã’gÛÁý:.uä‰ý˜/•ëޢ†Ódª²nÇ¡0YZ(Á^Lq3fv2©#hw¡Gõ‚ÊuHˆqHÁ‘6’WwRØ N¨!‡Ôf°Kç”I×´8”¤á§ˆü»ìq~ÈG¬‡Y0“ ç©°Ë9ÓåE·Àk@ÁŒÓF„Óu 2Í3H¦"XF†g$¶ÕÙE&Q=W!wÛ+´½í,]mMd4BßArì"ºÖ¶Ð'åÅðGÛ%¬A&(Èü…–b÷ŠÈ).5?f€¼”YäZ«+³‚ZÓ"€ÉÜÚÅ2!rôœcyŽ¡…˜Ù×€ûL{²Îúýîp4ÉnëkÁéú„U6;]Yµ¢qîù"æAÎÈj:èh}õM¤írÖÎW ãò‚7ma½I—¸A’ýeÜ ´N» V€@±Øl´u÷¹0Í̾Ò̾\—eMµP®×KMOƒAÿèhtqq&:??==92ÿ¤¸ŠìVhBœèDP¥ 9!8!š'»Œ‰ÀF‚Žžc\û¦›(áå—TL»aŽ8ø+e—ð­ö¹[QûÉÊRÕ6)‘UŒ ©[‚9¹à‚‹"H“wy4$Š–±"q ÉlQ½U~DíxÛ!;üá­æŠÏ&ÜñV„w‡¨†\¹FS{TjÔªDã‹«ÿ›û%O’r9o‚]-5ÈT5Ã~o8èêèSÐn ‰¨ws;ÂT‹-ÈS:@vm÷cÚ‰ÝIø´—7ò­UxÒœBDµCvðÚ`µ¹bap.ɱ"¬¿›»oÖmV‹´Û8­îûô7K™tþˆØ|Éû³Åb¾XÍ+YÊL Ú¢VxrbæËÉ×¹8¨l5ßLÎmeŠ1à`®”jÉÇY|Œã}|²Sr*-˜Ka×`ºQx‰F-ý£TŠJ-³Ñµ£cÓêTJ¨|¹iÃÏnâ}L~nËÓwR-J¡â (פ¨ÄÄõ&ßÓÖ÷õ:ÛЉÞrJ»íšÚAT21èÝï[ð’PáI>‰yTÛõ %§^LåüADQÞ:4ºUXè6¥!•ªei(ºÞN`Öá8°H}{‹––…ï©Láw…¸ô͵\µ¢ønU·0ü4…+\ð¦ À}N,èåªÝª[ÖBæ.‚9àj dȈGÒB^:RºÐ³h›Ç)®€ø(]x£íJv³Ü„Z(CC6“†Wáöò9Çp·Ê@4me$d*SDòD“Šè)\ºëršXÞ]ÄÉïGB枼؆6 ¥0",B©d;P€ì4tZ’‰B] f*ÅiÔ™¼£ôç+¶ž ‘Xé©åe0 ò„c]FÇõ4Á¶•í*3 Ï¢rªÌ{f.æÇkߌ4½òD‚ò”­[½ƒ}QËï~»„´Êñ2…æ-úw “gFéT#’ ~n|ñKüÚ¶™L¶»»»ñôNEЄ:ôNNŽNÏNÞ¼yõæÍëW¯.d¸F#ßïKÕÚå "ßyМY•E©l¢j ìG¤b(3!E3åeC>7µG-•JŽI’€_É#›”ƒnÉGh+­{¤Š÷ ×±˜Àfk¢–®Š–Pí©ø¯Ê‡£ÄAã’¹k ¥¬ ÍmŠXÓ.Z<!­BÞ¢cx;^A!í´ÿÕ» êÕšËò¸§[®ØHðh³¶¼øyµR×ÐÐæˆvŽ´bX¸×ùÉ8Ì÷š¸çƒJ¬5ÓF­éÊóc!òªEŒyÒœ¢ï…´8ö¹á¡†ðN-c²ÛxOÄ[Üdc•i¢Êë‰+?Ã.`Xeåx®c`¨$ÜJöú µbN‰¾QGYFur® ‹M.ß|' rÅ;†³Å|:ŸgÓ»éøF3Ídv7g2ËMž÷¼ßß0x W^ýŒNBcnC|á ¡·Ñ§¢\ßnm—¸ØÜt¸•±U²1˼BI_’ Êl=³,.ºIræ!T!ÉLg”PtLÍäŒ$|¡›þ‚µëz6Y¾Û+ˆ*2Õ~•]ÃëCeµ±ãR²û†ÖÛ¸ Ò¡­rÑÅšqŠîÊ$ÄÛ‘î-Ê´À©ôëb¨Žè»m¸Ü@nXœwD¥WqQUîTo ;þ'y ÑÁS‘Ñ?*B¨æ O@‡iå—M%ÓK#žÓlò((º{Pœºóu…$ÍuÞ ÞKwº`”º(ú¯„EÍØXrÊS–à†Á¥„Á7mR§‘*ÓŠ”¯o$º÷~{¡u2›ÌçSnOÙ¿ïö†£¾f§³óãÓ³£ÓcÐï÷©R‰ôù? Ë;Dü\ª"Ôa1Õ¹à‰^VÈFLZ¬XéMœV)Õ‹ð¶ª5ê ž6gHHïvÙEͲøsÜxÞdQŽíp?‹hôGˆä ÅÐáÝ ©xõ%œá~Ù[ñ‚7ÜíØ6jì³<ѱÝLøÂàðNƇ¯ˆ(^sD_Kçp8Ä÷­úZÝŽ¤ò1ñlN[x¦5~4ìhñØ[ÑŽÚa{ Cp3?73¡y„ E5¹º—µæ«Í€—™±¯„8aágξô„áSf°¶ÄVÿŽÔÁÃB™¨Á¾Õ.Ýš‡dº-Ö‹û%µj®YΙidÆi¹\.Ö÷K¾È(žµÜ5ƒÍBœo”5¡à§ÅwOçcœ |ž=¥ÁlñDL™lål1q÷¿æ0>Lʇ°Ý¸râÈ”.íš•¥]a ‰Ê«”<îùŸŠ‘TÌ[ðFEan4¶eÈ9*ýÄ$§pï‘‘éà =Œ ÝFÆ=Š­ÕšÑ•AU(±ÒC¹ƒ†àgäÃï9@p•wâ L[¼Hˆ´ž'p›"ÖºOª$^QV‚%`Nã}‚‚ù³dæR*—ˆµkKˆ{ëŠÅ1(˜ù¥ %‹ •ÄQàRo1?…’ YxÿÔ ²#áP7gfwz 5Lƒƒò£âÔEXpžm¸º2ösxš!ù ̹ B:ÝC¿x 32@ÿ¥ é-Ô#{Îrÿ†6°¾VÊLic+Ã<Då!ÎýSÑ$ryoì{1°ßö7êt‰Òc{B Ä(ó™ ¾dµ^?,ëéd1Oo¯ïÆ·wÓ‰¦ÆyÜVÌÍÃd©ÙÓ—2¸ñeoÜ{Ú↶»ñøîîn2Ì5‰®—ýaOóÒééñÅ«Óó‹³Ó³ã““#…pVSW14ïKÍÎC··×ëòh…-³ìÑ(n-CW6•8¼_cŽ¡ÆV|¤r`FÕîŽJ¥å1£¶ —äón Dm©L(¶C ÷Âk‡HÌÊK F*{#°tßÎR4Úh^‘EõF”PyÂ[Ý"EÕHR½¢@Ûû¤{Çh{«ûxwЊUÏa°ðH)Äi,ZÜ3§7÷‰a£ {ê}²×ŽÎ¸b2 ú#wW—ªŸ\Üèô<ž*V¸Do‘Ñ⋼ÕQ½Bãv-‡P]Qv…¨·ë'f/uHκ1­ðø›lµ4aÐL‘¬pÌÎ¥Ç"ÝÚÓ¶CÉÔUŒË“¤­'¨½¶é÷Ú×uö6¿œrß'Û6Sf§ñõ§Ûï?}øîý»?|÷ÝïEßêøáïòéýÇ«—·—ד›»ùÝ”‘,VkÞ˜æ 5b¦ŠÖ€¹VPâi0uŽã»- \’Rkž)ð{ ™.•LÍrè ÛÓMÑú p,ëÍÏÕsÃ/uïÉ¡ÖGdÞP4î8EYœõ“5jçå0€è(TÇÄ X|è¤ ÎæÙýR’ô¼‹¨ÈÀ'@žm8„ðøQH#·„( Ô®€Ç†.•· Ÿ嚬¹Ä—o¤”Ì&¹·+ßu<-ÈëîÚik÷¢‡5B@`“Д„!ê ªÌŽ"«,Ê ^ ‘UžHåõ*SXüˆFš{Ô”²WÊ”EBÉùFAá}ËU¬sS¶pFz'IÉþŒ±À6=ˆ² ¼ Gظ„H~Ù,žê°kµÓÓÜXÍ6ñ*Ý“M  à´~9‰Jõ8©p£‡­c®ùxê …Éƒ²FGWüg¼´£}ð5ˆåb3›-gãùDÖ×xº˜ÍW .ìñ2ÍzˆdžÖ&Û$ÓM›[îûæž–Åd6ãum Œ¶ÕfÕp_ÝÑñðôìðä4>9do©ZW±¥·V÷gldrç#}PÞ­nSŠRÿR¸ §jh+<›=ªšJ瑹*V!qlSÉËízM¾¦•c‹‚³íµ2‚•O’2yܦvH˜)Õ[9†¹&*å+ änù-ìxŸãÌTÞ?#UØ«NhÄRJ§Lÿj_ëg$p¯ÁRk/¤¥Wñªm¿û²ÔF#­™‡‡‡ƒÁ¯vðn†¨77=ÕMDX¢d¼‹%Hm±½D1:Ó¶Î65c'*P¼Q|Ê쾪ñÈ“kûØ7`ÄÄd»-‘‰Œ–A¥HŽƒ6"=$"¦‚¸Õ{ê=-z>Ö ã·rp©S³gÚ4ᬗ›ùd¡Ùéö†O5\¸ùøîòû¢Oï>]¾¿¼|uûñšo6ÜŽçãÉr2[i6’ÝÆ‰A"ôA‘˜ Q§ i[êQôþN6ŸÊ¬ U@ýÏI…;ºPD¥ é«wýþ@=o4Òÿ€Ouôç·˜¢Q­’S¢m0øÆb&q(*͵èÚvM—úÖúD+VA^)DËÊZ¨åŠEQnW’»^—+c³­ÈZI„È4Kêt™:8+Z×o£¤É¦W2ªW9½5b­,•Œ:0‡^–HTR´°ôŠN ¡³qÊ@Úmv*8JLÅYH€i¸ô˜Rƒp¶˜Á©T0ÃÕ4R…t¶ he d´ÒõÅØ‘@|Ô˜[õ2´ñ¼nÔ‰;ž©z£º.”´*G¿ÑNDí€\LÑÆn:ý¤—R%= ±IFJΰdÞIÞ&OIâ[»4ö.T€¹Á°çFOÄ’ŠŽÝÕðöK\(@èBHªºÀÞ»ç0ÝèèÚ·jÿà{û’ünº½'ÛÖ{ËÅz>]NÇ‹»›ÉÍÕí•ç¾éÝd9›kéãué2Ý\á¥î?Ü`·­ùþãt6ŸLç2Ún'“Ùb¶~XkéNF§çÇgÇ'§£áPSUÚfÞ¦}Òšá¤Ió%MÍ(¢„ÍQ5Q-Ïe™’%‡À8î’äı‘“Â3ÐÞ §ÙZ¥Òw( ò…m÷ˆ?²NáJýˆÁÔÈ1gògª /F›b™TìØ¢ŠVH6¢é±×¹o§2¹3M÷½%Ú‰m{å~Ák ´C‚r¼0b`P*HÞ°3 ?‹àcЉAØÙ—Ñ6e±sƒß’çTG¼&ò *“+†,žÁ–>?ÈØH¿UI'o†„¢ávÔVeVwCt•X‚8gOÑ(aœ¿§=”¼ZãÆVerÏ„O`Æ (ÏNÚ͹ã”ý%Fvª¸˜Ê⌨€®È-ã¨3~üp9ÖDFÇl¡î÷æõ«³Ó㯿zý‹¯ßžœ½¾8÷–†á[òR½ÙŒ³MÜT©Õ™þØúÄ×Ê eð–ý¸²bšp¡Í&o’àÙ T$î–² ¸^ɲ·?Ö žÎ'ãÉû÷V‹Õ§Ÿ¾•UVé7š€bYLÊ+åÅ>Vüºv:c¶Jªó3vï{WICÈkžà¥“‡½'ƒ‘/ÈøýÉóÙb<™NÆc)¦öŒ§³ÉLs,L¦~¬u¾œ/ds­–KŸDÑ$›Ù íï{Þä<à”Èý¾¬CM¡ëÕæöúF¢î4•Þj*^H&ƒCzpÃÅ4¤®:ýRQ²cj¥4:j‡Îìî~ôÐÝï ôÿðêëWãÑùëó‹×¯´m8>9–nÖE)\ùy!Ò³Íd)XaŽúlÊ•} )_˜éBy~ÓãHlöú—*rÒˆò/?J¡ƒ Åd¶D'²*>µ´%¢ð6!>꼸pˆ€ä<H c#ìÄÆ/?¸Ä eFeëïi#6óÍÃÂïù‰8×½‹Òæ* ©@?Ä ƒö! r,Œ#Ü’êÔ†3#H+IéNöð¼ˆ`n'¶K¤ bl6ÞÈš ‹f쮬 i¡áÌ~; ÉÌ®2â 9KîmP ÿD,“ܦDù7N Ã!¹ÉgFðè¨;TÞý­Ž”yù4.÷Xª31¯B>OÔÙ‹·cò¡?ŸÖßà€¢³\ǧ¸ù¢GŠ¥¹„K |è~9_ϧ‹ÉÝlv;“'‡æ>n Y­´­æœÔbT‰¬A™n\*å\`ÕLÊW —<šOÿ?Ø£Q4êùj@_3-SV©|ÐUî5‰q‘”6çŠ-³W<½/Šê7{as`P„(IÖ1õŽÙ"'—jMË@¼I<©dQ‰T¾8-ã2Å rí¿x¢%\CÎJïî”ÌÙf¢ÂüC©ô’¨:ˆÀ†ûE$g)~ªÖFi»¹)šBmo¸Ã[Ý;Þ6g¸w¼án…©Éý1àîé%õ@³4·¼iðÎWNi,iX©Ù9ô:ý¸J5Ô–dàA¡ñ\î_ϳn"¦éV2"ß  š²‚vázV©Õ dÕnJDlq+ü¥öj¼Åí`&YsÒ&žN÷KUüv÷¸á ;,–0OÆ&ÉrCU¡š˜ÃˆÂZµÄ;»Qê–mb£MäF löüò]?²z¿˜­æÓÕl¼šÞ1YÝÝLï®'ã«ñøêN4¹O®u¼›ÞŽg·“ÙíÝân²Oenúœvõ*~ïÒ§êžp$‚IŸOÛÊ0Åætq™ ¤œ ¸SF'*@KŸ2û}!äDå`DÆÂã¾ÇbÀ¢'ÒlÂ’H½*ðâáuPLBª+:«ÙPAê$Èmm+`VÓl§0lU·ÿáQ}ëì5P¥¯Þȉ•,gÒpk‘ÛRºÄ²U*Õ‡^V­$¥ ðØ"Äkô%S·*¸oZ¬™ÄKQHØL)-E@’÷Ó‘J,Õ'RB¦ggå’l±¥QÔnemxúÏr„d(’„ƒêBrZŽà(GÈÙ‚„EI^¦Ê2¿*/³E[Û—i‡íqœ^õü¬ö¨±dÖÑ}b+PõÛBVhÜ Ãc'64M`¦Ì:Éðà”ü¶ÉR Ù/}H‰ì~ Ü2bátátE³jló!]ž}[ÆÇص©Q;½®Ö™>« O”v{ý}Yoê8t·€fÞµ´ZÏW«Ùj½X¯—÷÷+Å«[s7“ú2úœµEWÝÛ[-׋ùj|7»¹º»äêÃõÇW?~ºút¥çäîn5Ÿ?,¹§[óŠßó+““¡Ü¯÷æ$œßi’¼½»½¹›L§óùLœ£CÎ ¾~{ñúí«×oÎ/^žxî@Ìë¡ê±Ï3ñýîAÿÀŸÞsëÑ€Ö*z:ä@.^Ö° qee p:0z„ÈÏj¯š¨dYlõzíà{¯~ô+ÅZjB"kós á–¿K5¼òøyÒ 47:ë6Ûc´cƒ¢¤Ïa'ö1óËÞ ¨CH++„o¬-¦‹éxzcÌü h ¸4urzzqvvqv~vz~rxÌw"#!FEHølÅþ%!Jš…­u#dµÞp}”·aÄegÙm²ŠYGc)¢Ó j ‰H0<˜ßrºf† #EÙ8µŒ!M{1Ã{mM ys…”ãk ˯ü]L–³»ùÔ4f“ÛÉøúîîÓíÍÇ«Ë÷Ÿ>}÷ÑôéÓ»OŸÞ_ßÎ&Sí*¹aÍZW4¥EY+µÙ»÷ë?x’¿±!ëßi¬¯€Â¶ïðh‚èªØž Tpmþúþ°ß×Vöxtx4ÒnÖO3k4oX¹9Tme ÆT³Ó#刧µÛˆ(f‰ƒÍ9 ‡±ØÅJ‡dVD P…°4æšØ i™r(6¨Î‚œù ô‘§*ÝRªpÞÕÒœÅØ My.Gk)åõ¥å¥XÍ›ARl@õ"™Œûu Ί-Tž¦ðˆ Ç @C+¹[‘¯à|>#0$/Kô b¨†–kbwPÕH&gÇD¬øÃMž*B O#´¢$wPEˆHOCv·à1 a‚µ%ÄPKO b4íæEÁ˜´ØÐù5o óYvE‰]½ƒ £æ€JبÚCø%àR+//òÓðÚ'ûÞ{Î1¨íÙΡ@è€ù‚¡Àcö›õþZ3#oÔÔ^v9çš«¥/5ñ*5¢´ó¥¸!A¹r¿ðbdf.e'.y%=q¾sOnýÎè°xÔòq‡^_MTíle/íU’x¸³ÀgWµŠ3ml½P¼$f~›ª•Ú±ØXNR6»Íœ!ƒÈÔ±bΧ"HÍè\`ã;«‘”±04”•™"}BxÍÈ•lN ¡˜â2’/’?GE¾©ªQÈP÷‰Ù›+>®:ÛJØæly½Bz Ì`A ºÖQxì­ná±·ì•{Ë[J¢ÐÐ;œšç9ɶæe°ôawL -MêŒê&^©“C©YÕ…âLPJóÊ‘Ç2RèÇBÉhížp´½íX¡zÛG¡†'šŠ ¢³ìþ–¢,'M.A¾Û ÄÝm>mŧ°”¢v(zªFÃ.ÄÍÀ šÌ±”·´ij×1žÿÒ¢ãE$Ú+Þ/eTÉ4ç=À›t/ZÞk[/6kív§Ë•,´Ù|5›/§óÅd¾˜ÊÜóMŽšVm)ëÚꢬ Œ/¬¯|׮ϷÅ)7Wl$6¼U(æræ8 ®dT‘VÕŠ¬/ÄñÒ.C‹–— ¸OU(yÔUÙmõKˆSH‘8øSZÌ3sLkdòÌÉ|%¹°“ŠJb‚} …Áé3<;`i4Òÿ}àʵAܶÞj=E9Z’›(¡„“wѰ£R$‰ºwÕ¦€à5OqgF´ˆŠŽ¨¦¥ ì®Þ@i!Â3(ݕȈ|3»ê}r´Õ(ˆ#²;Ôjc'¬åE¸UMÍt¬ 6T=V,¤EØŽFœU*ÀV¹B«Œy ‚ž0% D‘H;“¾‹óÔ§‰OÃÛåLŒzícýbKÎ¸é ¯Š§ÜÙš ];â:©Tóð!uL9¾EXćã‹A½£ãÑñ±vvÃoßÐ*Å´!nzþ®³¯%iN›N“É|“¤Ó©f:¿ 7ž/5;²AU%3P¹6ÊËÓç³%oiOnoÇ·wmegó¹”Ñ„4:½zsñúõùù9¶::ÆCîäúp/e鄚Áxغ'MU>lÌ8ÅUl¤úÈ'á Π Ji“ÜP‘Kx£kËK½79Úœ…ˆª±v·c#¤R†?±±@CY/po ¯¸>Åä\Âé/5U‹¿R†—¼SHxÎ+ªb5¼í~ÒxÁî—½_äU!ýëáã@v<÷ÚKpÕ~®%[O‹ùz½Òܯ1ö5"Žõtt8â¡¥U=Û.ÑÒë /Ù …~R¼Kª _è ´½Õ]C„&Ä“Ón hÞà E¿?ކÃáh4â}ÅU8 ‡ý!ß ãEY\ëË - §ˆ «ÌšÑ9#ƒ<ÙV]0Ék“P¿˜à^¯‹>ômæ .ÃÄü ÃN󓯥òmƒ¥L7¾¿šÉtS'àaR¿Œwå×°ñ£¨#3ŒÊØBõacAâ¢Ç: >ºHÅTȽ¤Bn;Ý1Sðg»5Uk¾ëu†£þ»GT‹ñÍj¥THÔVŒ@Ïb![†ÁbShŸM™+Q‘;T,¿RH8žåÉÍâK´Õ–±â¨L ŸEã‰A³™ÈÉ].“YAW `x™P:T7SEõ’ªPÍH?±ê¥½lÈÍ-;Ž r*ʤºI#Ñ’-;d¨ ¬##x"#DE (Ì‘Þp+0Ô®j”$k;¼âC•¹M:ø_G)à•G¥€²s$q0̈ZŒp%-"-Ì @ ÕŽ(!„( îVÚn´Ž´hî kbU*SÆ,nB;hq&"ä1jT°•a‘Æz¡'ÑDå$UöU ›[>(¯‰BÓ…ì¶%Z,šŽÆy{qúçÜ›ñBU~éÔáÚhw0´ÝÆÇ@™ZåœptHµ'“݆oÔ¬¹TºŒ×WÎtœiÊRæ~{ÂZû\¯fäÇŽYrý 3O#Œ§²ÛÆã)o£_,T MðšÍ/^‰ò…m|à޽q¦ ©¨î\o [ÍæZ·_N§³étº\,î7ku¿~_ûŸÞááðèHö÷h3e!rÛK^ðé<ÿ\Ø©ö÷—{w@¬à9–.ª ¨nQt'mÆl¶õe³i*¡îd°Én;Ò&MŠ°ÝÆ=ôˆjÈÏÔmùÄ‘e,%5QœUÃí†àß>3Å-°~?ˆÈÓçÅûpœ“ógèïï—›ÍbÍ'í\~xÅÍmØ^!›AÂÕ,YÐ0Ýl·ùvÝEl\y&} ¥Ò8YE†¹ãìZÜ}Æý–**º¤Ï·yƒ_äeWÚ^ÆÝܹŴ’Ì’:¨b7<Ä c.ov‘µÇ3[š&Ô¯åðøøèðøcqÐCqµã|C/b в´¬T†l·ùÒ¤âéq¹á(_IR)B*=(ŠpAÕLeµˆY,ì<Ù^xåîF+ÀÚ7¢=¦6¨-\d9©yÄ:•d[|+¡B2‡½ÜP“ü)R”Stzƒ¿í®Þp‹c‡óeo¸EñrÂo¸w¼r«Š*³'Tu%HNßQ„fªçò¡·U~y)ϲì=ð%µÎ~|’)Sý Ùe† Ü%¹ Íjâs¼þQk «zÚÞΗ½‚IY„1éŠüÆ1NØÇY>s|¨£²ØÊÝ?®OIð`O ¢–Õ b|8˜9/ÑB¸¤MJ"n(w…úI†xµ›d„³Ù×.”»L|âía%û+ Bz¡Z’±å+Ŷ†Ö 7¼½Í¯ýãi$ÄtíZ1óóp±é†yUöùrÌÞþ½_Ä»—w»H My¹–Q]ðIR9s³ˆ×æ'*ÕòC®/«\èÓ¶yT•F5õDum@§“-v» !â=R¨©ˆ¼ÂÁï© ¨KC“¸[!¶@úÔ¢ Š‘=}‹D²å¢ö—†·J!Á© ³&4ƒÍ±.]Ü À–TbU\£˜‡Nzq»¦©nb2/ Ý<øƒÇ©"yjN ´ãb†ÛÊ›2Ä(›«p2ÈÊ‚@í,¶½ÈÔFáLÕ)&áÞ§å¸àTªGW“ 6º¯Ž&õü˜FL†ó,³íÜRÙ”’ß ú€(jºQT~I‰Ø‚”àžª¿K³ƒ&D67ºjD[åEñ/õ9ÏfhÚP§‘0gȃlj»ù©8ŸðåúEW¶8vÂm€ÏÎO_½~õæÍ›_þò›¿ú«_¼}Ë5ËÓÓÓ—9F2®Tek›¯Îno&××w××·77ã»[0à£1kéÅF±Ë½Ûôˆõú^¶Úd2çå§ë?}üøñúúzÁ»WýÛ›·¯õ×õWõË‹‹siÒïkªUIUhÎ$F…KšÏ±a®uödQúÝ/›Ê«êð¶CUmçÓròDSdkw;D΂Xz)©VrÇ|üÜ€eddÛª¢ÜªÞÜ·ÅB$w†‘#­XÉ¥°Áç^¦ÞÁ½ÆÁm8˜ÎH.¾;­z—¥™XÏ@¦/Z±`ÇûY|_þ?/×¥ Ì"»Ut°Ãîð&÷°F™Üñj?7¡~lŠÑÓ¢Q1BšAaàñs)š:Ô·¸5Öq™r}âÉ¿¨eÕÌî °•*v¼Íiêš*ÃÉ(!¯¥‘kEÈèࡎԡ) ´yƒ™_†å7Ù…V£Âƒ3 3.¡¾DKyÀ£öêWMÁ)*ø‚£b«J36, #DT ¯  ÙŽªh»Ÿµ•Ní}9Å“h‰iÁˆVWÇbî¨Õ§ ÏFU:+q¯#·ÅÕ ¯ã«#3S•2ÁS¡vЂè¬‚Ø÷ô¤Þ'oBv:w* Õ!D¾ùcíSu¡:žÁSñÊ<ºkúÛ ¬dÑäò‘¼R ‰Ùÿo¢z¬QS)O)Þ6íàåØï‹¶: ~,}*ž”¶£mð”^ú¸$E¿é¶?“„;ÐvÿyŠýyõÁF©†Šfí\+ò™¢öܰƒ'a”­4Æ—#ä>+º×-ÇË£´AHhMkm„Ì*6°ãirÍ%?É)m“†ÝD6åÄW=Œ÷z—œ 9»pànQJn…3§Ù¹…]¿áÀ-fåÑBU_Ãú§!D=Ý@Í:sÆ[±å}¤gÄV††³ 2=‡¨æðFÈ“QO"¢2ö3 Ò6^jÔø¹~DÖÏå›±ÿÛûo" ,jýzª±©ï9G¶Œf¢0z;~/‡ªÈÖ"³TØ:é¥Ö± #;%d£ØOµ›·±L¢£H¬£$,';i ßúþ©?^Ù6Ê`íûÉæÓÙíÍ­ö{—>jo*ƒk0œœ¾zuqþúâõW¯NzCmÙl‰s?ió,t¿/s©st|tr||qqöFxûZé¾úê«ÓÓÓÁ`¨ ¹k{Åi¶Ùl9óž¶?þáݧW¿ýÝÞ÷áúúæêêz½âm½£a÷èp¤m÷þ¾¨Ëzyaþí·ï¯®nÞ}ü þÅr‰>ƒ_ýõ/¾úúõ¯ý«¿ýÛ¿>9= µ©ä Vœîâ¡x±pþÌ;‚<åÏÝ*\ù¥¶¼™õ~›J•5‰âdX†cE×pQ™–Û!ð2Ê Õ8¦ #$‹ÄUˆ?ePxìM7Þ ÷Õ dWñ ‡ÒY`(®*À ÒßîÑâ Kz…)4 åçBªôƒð9=[©Al¨"N ˆ° ÔWëÍÕÍͧO—“éô·¿ù­vÍ÷›²8:ýâ«7§§ÇÿâïÿN£ãp4Ôp¹Ø0ŽÈQû(J6µ»mùb-ÜÒâ'E¬b•~ì«R9Fù¹+ãƒyŠ‹¤ýÁááá7®ž~õæí›×oÞ¼z%Çk]\ ¹•S˜›ÍZõè ´OlÜsnbÄêÏÙìíñ]§®¦‚è9ªu*œ©à€ÓIT¶‚Ô4L›\VTÕûr·­7‘Ú…¶@?£åÕœª}ãááèèøP“áÙùéðpôÕ/¾¾xýjtrÔ ÈÞ}o9=šP‹—úJßÙdzýéj9úðqÁÓWÓÅtÊó¤›{)¡¾TôˆrYS qI£¯è@->ŒŽxtãèdôöë׃Qï—¿úæøäðäìøøô˜‰;hÍL©s‚"”“`W—ÄÉŸWÎ0‹G.ëDeÄHàOerˆŽ ¡j ƒC<;¡å›œ{„ÈC‘lºÊATE4¡E9‘‘?t.@™ŒupœTua ÚÎMW5§)ý/h¹È.ÐåîÉ`æGDUë€]`<„Yˆ B,]T9 Õ¢ÈR¬ª}¹HÒÑš–@„).Ó¸Ú„R$²Vãè¿TºYÍ’EðnO*5¼ jÞå±Ò¡·½äˆÊöêhùð¥G#‚¥°‹Á'š[7‘¤¶$"•¼:º¤)¶Ê¬ÐX^¯ó]˜œ‰(A!Á ™JB—ZòåŠØÖ1ÜîÒˆP° ^žH§Ò÷( ¦ íM¥•¯HîbÅ&9¥i„O¹è¨4nT•–ªˆb*húe sP)ôSª¦†(Ì2³p¸P$•Çų2â$–ÀuR_D+BèÒýnÐùAMU'¯Î_quôìôìÔo J€EÆ×öÔ›Õr=_¬xŒt2è:åº$¬\FÍT¼ k¹ØÌç<¦ÀwfÖ$ÔÚ8Ÿi6›Îgb_lÖ+Õ“Êv¢Y’ e7j†Q·6É4×À ¢0æ³J 슫ò$_›üOl†(M‰Ú Q@… Uú2HK( rÝþ’}œ£…7ÔBfȲUÎŒ jfæ’$G•òCà”¥»V¼¤Ã?~ìTH:²~£%yžTƒ†Ëgêåë{¹HJ÷{РGùx ô ßíh¦Xy¨J#I$aÎ#dS]r1˜ñƯŽ$ùéQ;CÅOÚ|™v{¸&Ùm£Ã‘ÆöÙى쵷oµ'LzûõÛ×o_ko9Òoï1fX·õUW 1Žh-Ï]®ÝÌdArÅ(,c‘¢4½rM›‡ fmßé«ÅÀ^w©9ÆÒ=] lgy”xÀM¾HȲ4súÒè‘æÇú®]/-Rˆ5CÂ=¬ZÕV)Ã/Ø4âeLl_{X“RÅä÷‡¥EÀ Ñ•”¤Aäžë¨Uñ@¶GßQ¡.]¯Ÿzì´9 ÌÅ¡Dá]ž òòeV'l JuJî¦!Ê1@.+·JÛ¢ç`±iVÉAê8¬wŒÆ4Ч…'‘œ¶FÂ1¦á×â$fꂉ¶ä—J°$uF÷[ <Ô8Ñ>†Â”cHȱ”4±è“¯EIù ‘@h1GB„MG¦g¹Œèõr§|9,=C`[H”%¥¤—SäÂĉ’’ÑÄ#ný“@ýɈÞ.þH^!b…G6•§%7]̰†!*Ž) ´ü‡'¡öуZJ$H5Iœh™ŸG¶¬,€i%ªHŽ\¼Ó€Zšˆ5?Äí_Zf‡ 7Rô¢(¡¡ce؉x\NûÞ¡'Þ|+:<::ðÆ] ^• ‹M†×sm<žÞǼƣ<ñn5QIZ˜ó~±Ü`ºÍ–²ÓÆwÓÛ›ñÍe·Icå®9Q›¬µs¿Ñôp4,Ð.RiWPRÔKÖÿ™ÊÑ9Q4˜£2]²%AR7r¶@òdG#‡X̨ÞT íE²ï äæ!~¡g‘BÛâ-ý”>`w¡Ší¶œ6×?ed¥²@—2 %›M=˜W¥òæAˆñ´ææ6Õ˜¦nN^ÙV6nY’â%Ò+ÝnQ gênñ3a§ü¤×B“Kk¬eH85åò`x¯+ãlÈOº\BeÉŒ:.}•¸ EuCOnbeR÷zÇ<§ÖÊWŠÈm¯ÌDzE‰¶bŠa¢¡Ëu‡hÍå7W.t0õi!Æ‹hçYQU¤±ÍÏ»ðè9LÈ ¤¯ÑÝ`ƒjƒÒdAv6"™ŽÒ•Wë¦*бåT¬4uTH9¢‰Ž~ªa³·Zï­¡‡BÜhÌÑÉú\ ß³‘’$—LNu|K6D µà4c,YJˆEý^zSGÊÅŠâà2"TÿÐg•šÒR\…«%@,H¹v2¢P^B’5R•´ÈlywxmžÉRSp%^sÒ(`QÔÝ—¡¨Zôp†5°íŽtaM>Ft7[PUB<jv$e+^§LOþYî’yÉŠ:ç™ô2ú)jȈdQÎ/„$)IËÆ ’,KÜVÚŽVvZnð‘žs‚aâA¦uÔœò§..‰*‰ ÚÆEÁbÓD©ùTÓfÐÕ*[íää˜ó^g§ççg‡|<›õJ’4iÈ>ã¦wãËË+ѧOŸ®®¯dÂÍ—óÕš7H?¦ î ^Ïæ«éTÛâövz}u÷éãÕ»wÞ}÷ŽTWWëõRYŽÞ¾yõõ×o¿ùúkÑÙéI(Ê B è4žÇ4?T¸>h†ÜpwÖ› æïIÌ…!Ó5-%*š˜ÆD%<½OæXSí„·¨ùm3óX¡0’Á‘ÈãñT‘ÇInµ–“€L’"¿3hó3ŒUej+Çý€iƧçïy¥ÂFÓÈŠÉa¹¾çb)Pà"·šW] yM‰÷ØrÐE,#ÖÏ¢Fú¡HèÃ^Ï;ÄÔ,JQêJÇ6DRáq”qÛ!rW$d§Y í;"m¢ÏÊTŸ£œ!ùÒá¬E5Ÿðæ”mRžÉF+$ÃSÔŠr{5”±9m3ïÒ Q;ô2gàK¼»ÞV‡—ãI¥‚A’¢2V:¦§("ÔÕ);¼oFû Zi¡€~íB’ú§z4Oú9 ZÑk õIµšçgC-#Ê=ã~™v8+Ú[ä Á(ŠÇ–Âá'3Ý¡]I9°£‹ûÄNÖ¢…¤ ¨°: QwÅá–©‹¿Z0Ÿj¹’—Ú¤~ÎnM.ÜjìßwxmL‹HrÍ…Z‚eº­#×*’¬êáqZºÆCõ:6D)8‰ˆl·@2†yLÚ‘6‡læ¨[,~@lõ°á¤ò`¬)Ü¢UËÄ êV›ýÕæ`õÄû×óõ#y ™k¬rø¼¥•wø:³¼ž‚äõZi ¥¶fh¡p(årÁL.¸‹AœQC\Eá¥V‰*”LQé…¶‘¦ åÄýØ µzšÂ9¶«6@ªÔÄÊMm(YD%#öI(<2 æÂéæŒþ]¢ý„Jm´ýÑÍ‚\çƒÚQ"¥Š+šœÎ5oå9üqBWŽë'À¸qàÍ:@¨–Ñ^×pºM’\½M‰J׈0Í$Q>Æ€‚ÇCç¿þïþÏq‚MºÙÚd?‡-Z´µ(æ¼ê¼¶Að„«dS1 öúЪD!3 QcœR,5)"‚x"a%ÃÉÏÇww×—W‹ÙìæêJ ´wÕnöüììõ›W‡'‡Úãöòí¦@Ä„$gAa¹¯Ëp| ïpx¨ ²u`’ZòeÁûËË«»»é»w¾ýã·—Ÿ®¾ûöÝd‹sµÑÂXç’«F.÷d é=ïÚÜï'“›»ñ»÷ÿðíw>|¼¼¹Rž™8=’nÿÏþîõëWûë_]¼:Žztf(*Aý©?EÍØ$­²{P Þ0úô˜QʨJsJ}>ÅFÈvh¬Á³¢*žãx!åKQU½]¦Æ/WPÁëK^Wiº¢W´êC®(uà³Þжû1ÛNÌ;Þ@pV¤—Ó ín£&Œî‹žÂþÁæþѬ7>\ÞÝßøøÝ»÷ãñÝå§÷÷ëÓãóÓã7¯Ïÿþïþæôdô‹o¾FýžÆ÷‰új£Ãy”¦#»Æ+S¯v0š#ÙTòOŽvFrïxÛuõØ[Ñv òî„lCÅ¥.¢¨Éɤê\ÊÕÒ¸U«s°?ŸM7ëÕt2YÎgË¥¦®Yœ¸âÌ B\Ë)òñ¼jÛÚó¸¦Í]½}Ùq­Óéʃï 9×Ѥ6èuM¦µEë•ð@S»ùýOö^÷èäøäìäôìôÍWoN.ÎÎ4/xѬ'Ö2éSOÅs¦M垎'ÓéìöêæÃ»÷Óñô»?~»˜Ì³Åz±ô)Wæ'wצªq±á¦tžï.ƒ°)P>ŒŽyHëøäè«o¾Rtô{ÔÙ亮|iVXn–ÓÅl<[Lçã›±t˜Þ‰&“ñx¢¿ÛÛ»›Û;>­ÃþXÍ8'‹ùbƽóé|µXJÞj±PæÚv³&ââ(i‡8YÙ9èq]Ù ¥™}ŒöŠÿ¸+G\ÿª•L’|H¨óØ|‘“ب‹€i+Çä••Ÿ"ZáÑñkÑ@ VºäV}»‡ê1–Ž@ËäÖÐ¥%Ù; ’µ°(Åx®zÁBB= Ü>®.Ò‘Ï!¢t¬ÃÛîJ6 ¬b)¹@îyÛˆÀ¢­gN2 œS,®žÒªNãP†iF¸Z¡Œh"¨ebjþ¥´(fÕ2ÔÎe·£â`¯› ‰xB£z¢À‚d<‰ˆ ðþïƒÒŸOeSŠþ°å~Qb HvÁ=•Cü:Ð5ÈzRó6RN ‘5/ñØóݯÜaªbFç¾Hq êæ4¼ÏœAKN±ó5¾b¥ CM¡j¶Ô|×ïtý%-M*¹¶|bž-îg³•fƒÙt©Ùû†øJ7ÕÒéîóHDŸ šcy¹œæôÌØJ£r1ÔPš™Œ–Ê“„ÔÑ|$Ù:ò%…î²sƒO† ç»Üä|vuŸ 'óלZÑ=?rG$wáÖ‘™É½RYÕ 8í„•ó1¬?Ùn b¹Hì©óœ¯5Ü9ɇPï›ûÅšo äÐNë-wÜkàú‹žâ^Še§ ²‡ÈÉËFùÙÊÛÎ(êÿ¹F ζ·Í¹ƒý+§.®á¹™žI†i.º×SèÊš6œÔ¹»¹YLç·7·Óñx6™NîÆk¦ëGsG,3ªV*:$±%ExÇõ\Ŷétøs·{|z<8žŸŽG£“£ÃìÐïÆ‘ºƒ^o «œg¸«Ì_J=äQ)^´qñ–׌ŽÅfë- Ì:Cq5‹ïIáûÍÃx<–Át{}ûñý9>¾ÏçM}™ª€Å›Í—'/êÅO¹’uÝDG——jÔôxÄûGŽŽÞ¾}£Ò]\\HW±kvUNÇþºól.Çíõͧ—w×w·—·×W7·W··—×7W·7×7×܇|ssy}u%‡¡[ñ\ßj±ßNÄ<¹ÜÝÜNÜc5Är%ÇrÅ]žËåŠbµqs0?££"æã8P6QÚÇÛäÿ^˜©ÂœÒ?JXŽ ”DœH¥Z"ŒJ‹áËTìÉØ#–$d”žš* rèH§j܈L‡(š&ˆMw¬çJ¢X4f2Žô‚Xˆ2…¤*§:EÇLmoá!‡æèŸr D` qª„,ê$:ZpÉ=óoÒŒ(Q 5y áí£ ÷°¤uøuË‹R¨U&ÞË,énh‡D,láuTÈ” Ð‹–Dv+¾ó_ÿÛSDçøñYkz)é¥-B¶h’9#¼þ… @-OâVHh’¥âèÁ 9 ‰â<ñÅ1#ˆÛ»\ý¶Û${>Ÿ¯–Ëéd¢¡«a6¾‘ݶ7Än; »mt4ÔäÅ֓˲A‘§z§RB5J•–¬k[«{ûþòÂZëÚÝön«wï?ŒoÇû××7þÌÁªÛé }s1V›fÀƒ‰Õ\MÜr%ñËß³šÍ˜^æ+¶¢Ã‘L¼þëך‚ÎÏ/ξúêõp48>ue¶Io ~Ùƒjï€oD•GU¬;©íê‰%žh“@ËYÂKsÐæoA¡æÌX~jã>™$ÂÚ1r»V]´,‰PݦäƒäZhÄOzR«mÀ[ãŸÆãTÖÌQIŽ»ÉªIA>flü$s”èI>‹/çÜBÖÛ³´[Ã(ÇQª’£Š¬?õÑé »íÝ»ÚY|ütùéòr!̵'yxõúôììøâüô׿þÕ¨ß;;=êÇÕ!ÉBÆAŽc žÄ”ÌóKŒ2eåPs4•óÚµñ%ü_‚9mou·óÝÁ³QŽÐÁ+1'}©aJÝ'Â!€6Ûø¶€¬‡Ålv{s3¹»›ÊnO´ÝÓÌ¡ƒù­LúJê©8*0ÅÇX’\YZŠîv{Øm¼·ƒ £Çç§ýÃÁÉéÉñé‰ ¯Ñ)_ÏãzÇCjÜ 2ìÈHöd“ñ~/^‘ÔÁnësT©d·½ÒŽ÷øHöŸ¹®Z2wrQöøzÍú~|w7ŸÎd}úðq>]\~ü¸Z¬dè<ðh«>I¡¬Qt?¥Ò¿¦{÷¬Yg—kj=>:Æn;蜞êH-ɤš-&wÓ™6Ô²Ûî&7—²Û®4?ß]k!¸ãÂèÍ–™~e¢ÝÜŠdÃé¨pÞÝŽÅ<¹“™6ߤÝ<ÓÖz&sp¢÷t:åä³griªµFúDÅKYÃU BxLéú1÷v:È!DƸÈ0—=ËŠßëºÃÍZ…9$ 9¼ã%º yLÑ`^ÂHRJ@D%Ö¢ðrdÙ5›}È%§"Ü\Å&Ф‘ŽÐpiQŒŸçÕÖ"%… ŒªŒ džn $˜„aýZoñ9CÌʯôA)ܘ-é%² ±‡Äî„Q.ü‘~³Q¬í³à„;£ÙÆÍ¹Aïìâ¬?œœŸqâmxxrij«Ç|U†®»>Ä<è û²ä0æxQÄã®§ÇJröêBBú£~Üþ.VA剖KÓãÞæa|Çù¶ÉÍøêã'YlWŸ>møw¶¹Ó‘¬ÑßÛ2b&±ÝæbiëËBàRëpxtÈ ðF#ms%itx¨^»\,eΦ Ù^:Ît¸›ÞÝŒo¯îfnV+F糩l: ;Þ®9[ÈÁý*sß±¢Ý ™®¸7n¶ØÌW«¹vÙjËùB3¸˜7+¾«(HÓÕb©9œë/Ü£¿u,D4²®˜(”Cˆ*GW,K?¯gõmPêÆAÊâNOÛm ±“$2„ÇÆ@$–´½>d¿gÄšÈ ¸ºí·0˵Jú×Á‘"Ì.ÄaÓ˜—ÄGþaúp‹—¼Žªåç¥d€8Â4•‘Þ¬‚HˆÃY82õÁºÌxˆ—爗ÞhXý˜SõK&L¿¹(­¬˜Ô܉œi â¨NÏÅ1ÔvhPÈ\|2€å<Í@’pWGËË?ƒ¨%$¢Ú±ûÿïÿÏÏ©&ÆÏ]k*–=¢ùÀ…R ²ùÍÃm…½KK£Û7ÉÊi$ЙGÚmD5E³Ùa;Õ7Çj~°±b(P ­xõ÷ صì%lG…lî5ÀdÝ\_OÇãOï?þá7¿Ÿ§ßþöýýƒóÓ³·o^ÿò—¿üÿòŸž_œ ŽúÚ8jsIò½},+O+ÊOÚ:ÃŽûºh{°w ûl1—Ñ6þã¿Û¬÷þý¿ÿ‡éd¦½Úd2UõhJÞ¼ysxx¨TÏ2ï.?|ô;B.Ç·wš 5IkÞQMÊD;uz|<üÕ¯þêødô‹_|ýêÕÅÉ©ö‘¯»ý !+QÙßu ô*êÎ ë†Ô/%áżâpÍë?ᤄ¨<é.°—bò^×vx« h´)ˆn’ }¢iÓKŽèV½üÛWIså©þ-1¸,gŸ(UNžÈ^¿q{ hÊ—™fÆŠ¶ØŸ”Ί9 d׊Yk5^…Ëüê°„ ¦_[Z[ÎãSØIø;Â+NÑâ&›û“Ùòý‡ëåâþúŸþÝõõí·ß½ûã·ßmîW÷ëÅÞþúŸÿó¿þÅ7ß|õú?ÿ×ÿ»ÞþÞÅÙq¯×uãk¤p#ÁÞ^ßõ\Y¼ÄŸ (7x1å¹2=ž©¨ì/AÒCoq~–ùi¸ßÔ‡±O6ŸP›/ ΄56…P£~<œ>M÷šÇ•LħPí<׋åb:›ÞŽÿð›ßNoî¾ûݯd4_ß\}¼¤â—>ߦ5c£qFª<ýD–®E¦GçæñyÐë‰K[ǃngÀ§Žeýêo~Ýõ/^¿:>=Ù—…6Ð}²dÆÓér¹œNÇkA–ˆà‡ä­áþÉññÙùééÙÉ/~ùÍèx0:öìx](Š¥"HÓèê^3¤:Ôwß¾»»¾ûøÝ‡ßü»ÿ°˜,~û³™óœæÞšÞ²µô[6lH€JÆþ›ûà\‡œcbÁÁfëò>“®_¡Fa}ÎïðôÕÉßüý¯Õ8çoκû|>w6“9uuu}¿‘í(#xÉ 2¯n”çRåáFvÏ>s©Í½šIyÓ£Õ|êÁ6¢¨§ü}wñok ¡Ýµ"µ'çƒ Ã“ó3UïÉù©¢5ïóØÇ +SxŸ'9âÖ;ÍÂ4–V”M .Íþ¬ü@%1:ª ?ðÝI ¹ÏÀƒ·=a mA„„;Œ°ˆpº‡¦£¬¿ªZn%b*ÊšW"bHZ 8w‡¦|Áâ¨rˆ-ñU-mê/ßf1#L"õzÊ­z)a4 ­¿Ê èê,ŽdȈSÅÔª‘ŒŠ•ŸÕ‰>¥(%I>{ pC .q2Y2œ¶Æ(—BˆÊJyÒˆ.ÖýÚ#B݈úê˪|\>*“Ãàs[Ä ŠPÿƒ“^ Å"ñQZŠA¡‘áR3…—1@‡¨{džáI|TA8O´AiCz‰àâå›YlÒüذáüd‹‡DRË‘ÞGÛ‘ôHj9’¾º_wåàî+ ÿïoæq/YÕ=Ã&ŸÁ×ÝÜÜÜÜ|³ðØz:»íùcõíî ÕîkaSëzªUã¶u:Kb_ÿÓíµ:¿#ˆ!SôqÃXý«µHêÚÕm^NW/GîæéŠ2YBb «Í›I©o£†Ì&Š \Fñ‹ŒMhæŠ0X‘”³*ØL`­’jtË–hèPK8Ç,ª Í&øKᢔ‹h@€M¸HVpAob pþË* Ð®p$sÚÛ´y§÷´ieª¡r~çï‡l¹4DÑné‚çŠÔ4ìßë]5Æ }‘¿â—Œy_þðòÊí©‡ª§²'\+Æ[ktÔ9 ao““Ì“•j³Å.h$§Öã; † ~3Ëd¹5({“r|/å6£œôÒ’¦hÕk!†è‡Šaš¾4ïì÷;.à­¶_¿|Ù,×Ï\'Ýúñ%ö.^¼§Y]`u‹`¨7‚)‘~¯ö`›çªÛ“uÝt‡¾ÂüË?ûÃp:ºÿô0»¿N†ã›ñ`Ôï=Xr†ÙNƒépÂKÆ'Ó›™~Û¸÷·35ù”W ¸HªéI D­PHµÁ9“ûy}úöü§?þ:z~úö4”;%7k»ßì·.‰î6œeË¡òV"'%<êÊö¢Ât}™úE«ž³ØŽ¼˜×o àëª[-(›Í†W‰ð®í|þ,²"‹å‚î¶Òö@NîÄ—E¨—+ÁPí¨’-ÇnŒ€Ú‘ .ŽL< î;¹Æ®ƒehÁbå3à#{LîˆSÿ!ŽØp´ü–’3”ˆ’x¢DÕÊ‘€êX Ôã.’+¦ž ('bŽ á>Ê8„ 8GÍ©4¼Ën°ÆôSôDs9,PB#l€Z YfÍïð'ÕcOÎÕtœfÔQU#]&1¨U«#t‹’E",°µH e*PRÕ|Á™ œQü\‚ØÌ‰®5KºÃKëÿüÿ‘ßæ<¶ˆØäÒ„NÉg€¢ÔÁI&“ß92cÑ’˜-% ˜]ÀdE¢x@D×LSD8K5#‚ÒÑð“ßæg‹ä·=kÖX>ÛoëäKMo¦?vºòÛØg}‘·haÖû¶Ô"¶» #÷Ûž^Ÿu†µzž/þôë—ýîðü¼ÐW3ùÒž&9yc·÷7ã‰Î^{ý~ßb9q–kwÒÚõÂ…®o™NÇw÷·77“OŸîǼk$­×ë z=ΘÆj2_TŸå]}L¤Ç†¬7˼ÈðÙ˜•9‰S#þ[:aœ?ϯ—`ÅÂP `)PI P”âL³ZÎA£k"J©ÑYÌY@„F™„€ý³ rÔ/u€ƒÍ"­;D‹†sT¾*y#^UžïD#,‘D£.^ÎP¢%cÆKô94¨• *lß‹^@ȱaÅpú¹\Á*öò²Þ잟כýŸþøy¹\û¹é­˜‡ƒn§sýóO겓édøóOÕEýÚ¬¨„û'Ï4Ô5‚¸Rï"| Å1¸…½š‘úüu , ˆBßVú„ÅšÑ ÞÍÃiSДltÙ‡pvµ_¯ZãñÛäèüo½ýöõëÞ·óËî;SXkÙ=wîèŒä ©QzP *M¼R3ŒÎK»ƒþp2îô:?ÿÍÏÝAwz;ÍÆí^Û÷¨µ™ÛBÞÙÆçØòçöµn¿«é‹ùkÈg1£a_8 †}¿üE-ëâ]¾‹Åocª<¾È§Ñlùôø´^Éo[>}{”·$îõ(wVnÊ>!å;tÄPŒ{ÿ±d¸UÍüC—ÑA¹(ï bilµö{>W#w>_.æ<ɱxZòöµµ\­Ãq+ËêLþåà#'%\°4ª}ÜJ.¿Ñ7åˆsÃÖ3èÍç¸xÌFÚ gî q'•£úÊ«“k'Êéå¨r|@Ü@ê&õi.¦pj5qMÕ>žãíÓ¥^Ï.€µÍ`°O¡°>ç %˜+0KRô“¶Íúæä X@ü‰\ñ”ƒ™I1˜êßràWÿ¡Œ ²‚87¦V˜°· %øòHÞ¨ÁÔàõ¿’<ýgÈ ¨˜0qôgÉU"ÒýG½L ™9)¢p’¨ƒ×Z"IÍ‘Yéƒú—’Uyî¹ä]£y%Þ¹ôçYnýFõ ÂQ…A…Ê¡L×RÁÎzá$“»Æ‹Öÿéÿý¿¢·Í\ø†) ­(qN"P@Å;êÒM6“ÙÌNZB4´3+ñ…ý¶ƒA㞌—WùÙ"ü6 3ùm!^NÆ7³éǼ͈»lyzgµÊ­ƒŠóÝ#®ã ·Ùzëû¤“¶ãþøõË·'?-þù3ç‘ÛíNšj‚Žä° oooF“áÍÝ _2eâë"ƒªè|‘ד_«ÈV‹¯Ž‡·w³‡÷·wÓùy£þx,DzÓí´ú½…Ûè¬ûîjj:D¬ŽÙìw:!ö²â†h{ž-!‡C²DL ÓñSI5 ¥Uj´Ñ‚L †’xŽ—ù2žÉM šÁ¢æ b9Xb1 `@ z Eëfy†0+ˆÅ]HÁk-¨¢B²8Z¢ ŠÝœ¨ª^d¼ˆ^€;dBp^C ƒ)ä+(zŽº'S‰Î)Ø\8V«Í—¯ZtwÄo[ÉyØíwZ^¦ÓQ§Ûúåç‡Û[ùm£Ÿ>=´®?ðÄ35”2lŠø¾JnDJszy38æÎêšQÖ\çý+@ÓU‰ïF¿™Q¡çÐ Ô¶ŒÚHs˜¹š²örÛÖkáã—¯Û¯«e¿m³•ßVV cJÕŒ‡"Êîa@Lÿ‘ÈÌË]SWä„É'ë ûãé¨Ýïüô‡ŸÚýöøfÜ®5ÁtäÛÅ}6Ý5÷‘ñð©Ÿ?åÈ]rã8ÿÄ{#Üá)S+î>LC7•Ïjrääv±XjN~||\/ÖËç…8õªåB~3Ò㜇¼¸fŠq<Á{i“ÁIÝ|’­ւͳ½¦ßõË-¼Ow³æšéQݱ£æç®å¥9€»æè­;êì¾Wõ?ˆ¶)“(×-¢Ï¢rkeÀ{ÓêsL8ä°q´ã7ÌH€¸uÞr‹ü¡¾Ð5q©n<‚¾ñË^žêÇŸÀ1ލ† ÀB0(5™ßPñÔÌþWRF‘Ò‘¬ß E4ÓP ¡!ïôE‘,ÉüpÍ‚ðoVÉ <F¼ h‘‡$G ”îdüQ ºX‚±BÖõŠAðEÖ Í_U<I¤â&X tî`#-;‘³2P‰S7™†'R]˜ä*êHŠqyüpx¢¦ÑÍ`vCëÿðÿú·™"÷;UrÕXá‰'„F*b¨*VF¹ÙÍRnÙœ„R§Ô “O~2³æ MÂ+7î ó×v­·{Í}ÏO¾Nú¼rÃÁ`:ÍnfŸ>=´uÒÈfÛµ Žß&YŒ4ûmšÄtPX¥hLêdx¿Ûóf ÝáOúõññùùyñåó×xe®Î>å²Íf\½¿¿e¿íöFá>ó]O©~ÎA œŠlóÈV»5™Œ&“áýÃí§Ÿînng÷w³Ñ¨;ä68Þµ¤ÙQFS¥l_uáœ2“ž´…v!Xu|Vßrl5l’‰9¯C6»H…'‘²Lvl…RqÆ:#J šfz“ÙÅч¡‡¢ÍÔst^ÙÃaæWçÍ|˜ÂäH…Wº”ÃE¶` ñKG5sòךø'Ã’‘!@_Lfn”d™$%!~FVÀÑÌjÁ!Œÿ¨)é–cÎ΢Ai ª(]…>¥ŽÎÒvâ»í~¾\þõQ‹àÿø«–Ãív{<äŽÝÞL{½ë_~¾çá™Éð§‡õi»m¥†ŒVÕ¸{\뢈ôSª]”•°TˆL%cl¤Ôõ<åH”è·Cã/Ž~/I|“bÿÓ |\Ëo;EŸ ‡{3½XÆÈ¼ŒþñÕjÝVŠÐŒäç{Tøë¹›Åb¥£ÎÖ÷gûJèÑÚ4s« •eŽpKÄ9Q´h1ŽÖM蛄½ÆHIýjž§~T°Ÿ6•¿¶×¨áªÖ†7:‹—c¹FãD#¹•D±®M«Éo£HŠÉ²ÐÂG˜"` O#O0;Ÿm•@ÿ:8Í"|!¾L­x@ *±„âà´PÆhê‹;ÓBQñ#(×vŽ¡Œ£ É4ˆáˆ(Ü>fÆ,+F984r "$ŸÐ¹Ûªú ë²~S¬#!¬¢D´*Á¹Qbã¬0 Zó¬¨nÇ8! *8°å–JIžY E[ÿÇðÛ 1YkÐÇ”ùYC• qJÕ¸AK—Žjê^YÍWj±Øì͈ÅMÍ[°%#g?%I):-…mQWãÙoDä+%ÛƒNøæóÓî¸z^¶¯¯‡ƒ¾¼¥ÙlúéÓG¶½ì·yåáäAÊñõiâûqÐö…]wM»Ãj¹Ñ$ûùË—ùœ·~,æs1èì³Ónó¼Õl6 ¦73•2ŒCÍzrÓ®9I;žx~Éu5¼ð1éQov3¾½›N'i%­×‡Ÿ{¿Ûm,I—¥š¥ö˜· ¦aZÛ#¢˜„—h{z&d”é#ì×D)TG•@áá`™MÌ$Àa—KSVÍ¢60ý¬¡’VB2Îé GÔ£I‡Ðo ¦AHõ?”¤XÈQŒþÝë‰Kú‡¨€sG d®ÍpÈ‚š¹˜%J|a[ T* 4'|7è»À€ k»ÜDf²KŒ–ÒÏëŽ×Rcá[.¶Ÿ??.×›?þéórµÜíùμ‚»Ù¤ÓúðÓ§ûÙt4önoX÷¤Zê—›8ó‘?õU©-œP Å8 ±2ΨCSxk=Óͪ“ÎUT €˜³¸r(ÑÛ¨”›Ç*p­0TEK£ÂœÍh•J¡U”9ò[…’˜#¯¯ZöO‡ãv³áóJë­ÜM8:Ïܬ6¼œb» ^ú%‹ŒÅ¼¥Gð,¿{‰lªYͯ7ê ú­NK~Ûh6jõÚùØéw“~·ßAœïï·&VDEàɨ銤Tš pÞI«Rób ç5¿}š“<M/Ǘǯª‚gàç—Ãq³ZsTâÄËlÁ2 ¹B” ÆX,B®%6§ºƒj¦z~ˆ ˜¯ê´~kæiï÷uœx9\l§ifç««¾$ê¹— h¯c›Q¢$Ás¼3wà-bf•BNñ|ìåXõË‘0ŠLŦ\°©²¾0å«7°'2³AZ³¤©²ñ HûT  â(cE*Yd&%Ñ–aÈÌKan±²| ñoF"/h V0S\­k‚èn>r“¯”„"%A•s„3³KˆvÑ·&ND h¡ ³f' TjiAº™Q6F€ŽèäŒì ÒÝágç˜T{&¡ýƯ|gÛêOúãj1?ìw//ûÖÕËÃÝm»õâÙx4èßÞÌR³pÔ0“m_'µß L<àìJñír+F·’â'*D¬ |¢^ß㡦Tÿ‹¨ˆ€€ÙÞÜ +xÖŠÖÜnâM“Ûõ‚ï,}ýÓW…çOów¾+aÇçAƒ°rŒv‰± %×Ú1Eá·]è » ô'òÛÆ­^ëã/ŸtÔ¹e·ß• od\Rjí¨&H¼6“™Ý”1ÜË`d2çµm~%íþÀ©òáôõË×Õ\g·îû<¡[j\à”‹Éâè|ÌÃvH¸ši¨åQN­¼Yÿ<Ê …h5.™"ÛãX&ľ¤>%UP­@1,@\tSa¨SÈ@[`¤h£[pkXn„3 y‚Ž<ó»TWÉP ÈÖò}À ª;fJˆ‹ª¦CˆKÝ­¡”ƒBpAŠî@Q3,ïPfœÄ7àÕ8ÅA°()ʈšùìÁó`« ˆ,•pbYÞüÊΙâˆ0„Lìs":o­JC åÙUCZ„ ©×9×YO8G•Ë~›;À÷Q21ÄMÇ€EªŠAC’iÅN•‚Ž:Õå2î (•jšŽM-0ŠS²Sù}ym~öÐßݺ~áÕ?J-°sÉøM¯á¤êE£Wäv½ßoŽ›åvñ´<^6ËU§u=öýÊÐáíÝTç£×ÝÎU»Åõéo°“‡Ä4¡ÓÇ—ãëzÍ;5ŸŸæš!¾|þ²X,÷»Z¢Õ¾¾™MåºÝ7ÃAov3éõ¸ÂÐn«N/öcÙ”—7Öéð(~·Ûêõ[“Io4îMgƒñt0öpòØœÃĪ«5'GýSßbWè'¾ È´"4ÑÖ FLisšit çµ²}óNç0;a{W4*,p©r½©Pt™ ¡KœÈh½8W ‘fE¬SEL!јüÍêDA•µ„+do²ÙÁ ¤ÖYœœº™¯ÕN”s ùͤ¬QPê$)`9¬«AÉ"\OäJ—Ô’÷;è¶CˆWö "0ô±ñô¯°‚¡¥¢Îã@GÙA€Sÿ:÷¤hÓúµ5(Ëfµz}Ùkþp¥“õv·X­¿=>ív;-½Ûíêõõ¨J¨÷þíßüÔtþðË'9nòÛf³©FŠ›ÕEÜÖ& ¢QTA燱Ò3†sщh‹Vb´•(¨¯À•ü'‰­$½1#u)(ѨC%™êÓ; —6ú½È0<£„ÝÞ bõ«RüÜÑå1E ™‡1åŠÑBp3cOòÕ»=[SK>”ùå_vëíšïÊïyÅëþ¨‰Š»,²ÝÓdû¾kÚ§Õl,ËÊciu5w¾öFÝ«nk0îOn'í~ûÓ~j÷ÚýQ¿Óï”ý&ä)ífíÀ ¸‘áÖŒy‰*kýÐÌ©%Ii\”ós8ÍŸ/Ç_¾ÉÝ,7rãädí7{z ŠƲF8ìF©.KV›bY<~ã-7܉¬°ˆ¯¾'LbpÆ|ä6’ÐE[qiBDÙˆTÄ»ZdG‚€&пkâçWA’\[•½G˜n®èñƒÁms—c™Õ“—ó ˆ·îE±òY;IUâéG1Œ˜«¸ó¸y]%WœÖJÄ‹ßYB`p.«â^éÊÂ`a$UZGñD"«õ0?i’ çÚºpË7ª±($*W¬’KÓbš«(¢Ä@Kp’xzJðñÇpJe¬+aà‡Ž°¨Õ³‚–Yt•‡`íá1EÉÒFTë„LL Mïâ>БȔ2©/™ù‘zBZ:zˆ%[¬é V(:ú5UåÙ«q€0D´á4ƒHÕR4y½ FíZÿî?ÉoWcøI%E†®m. ‘‚(Bi¢‘T¢Q'O<ÂÐM ‰(›á:I2aÞ,À4c”êä5[4¢[Ü'MœÅqÖu”ßv8lOëÅnþ´|‘ß¶^uÛømã18»™^uZ­^WG)ˆÅÅ¢d†Ìë•ï4=­W›•¦ÔõöñÛ£NŽ9\ðú\>­ÝnÝßÝGûû[vÚFƒÙlÌ+uyàÉ.¯^ã~‘~¿3èóF·á¨'¿m8îŽ'ƒÑ¸ßó›ÞÚ]žÒR]U7ÙP'tV$œÕYŒ‡@ÌD‚Œâ5lÕÑO&(èv·Õ©¥²»—’êyÊõ.#a2B´í]tȱJV‚ÏÈt–(+T2†@iâ‘@@œTA(Ás±³XùèšJ¢š’Å2-ßœ•†FIV’™KF€!§.ô«„H ±–åGgÉh)"èJˆ$rv+¼Ño=Ä8+k˜—@P… (E#Ÿ.ˆB p#bEqe-У úÉ*{D”{ÉI&ã[¹ÄêVq\µ—¼u»\®Ÿžæ‡Ýîññëv³ÖT§ŽÙë¶ÿþ_þs™üáçO·3n ‡ÖŠá¯#«)Ëge%v_,ÛN]ÉTTGq™Ó5+•U{@ µ NÕÕ™"j¹CB…Ä"즳„:õ-TŠ Éḻ"#D…Ju”c†qO¨µévU\m7–ê‚PEq)x>ýEîÚÁ/!Û,ÖòrþôÇ_÷ÛÝv½9n¼?ìÈÁÝð4«*…ÅoS_Vw “óõu‡+½aOÁt8{˜ñ\Â/uÞØö۽֙¶Tt-w&Ÿ92CÖü2Usí0.Þ—ºƒTv’ß&mu’üô8—æ_þôeõ¼â£Orãp@eQ¬ÈÂéñíÒýÔ"Ê’è0—•¬Õ{ñxœ V·¥€Ó¦FRÙñŠq¥²6±×«ŒtER= ”SçÍòʸº‚±?Í ”klÑpT¥0Ê¢íl4*z…ba*YÓÝ„ji,ÙUEaûU²ÉI\xlÜ£µAÛÙ*±ãÅ c”(FŠ¢—b.ë`swIò“çè.äJZ?[NÆ¿™àâ iT5€­÷‹#ƒ˜¹‚3Â9 ÕG„ƒAq»$ºÏ£ r«B(+dÒšÚÂdG‚ÄíAînbî„ÅEBŠ€›q^wã0$¡Cð[ºCë/rls ã—²æ~gÂ\[5PÜ&¸7IC7œÁ)õQüh&[èæ^Ìxézš.5º7„$Ø6K0SÍÖ¿ûÿÚ2=ˆØ§ÒO++FI kz|*p’¨9ÅÅЗtÚ*J’ÁùÕªÒ“e0&Dkä•(ŠBºrJM;~›Öø‰ü¶•ý¶åvþ¸Ð°‘ßÖi]†Ýñ¨7f·¼@¼Í[°[®jË*ù|™¦=½n·ÛÃî¸\¬xÂ|½þöå›ü¶ùüY«l ¥«×é<<ÜûA„ÙÍíLž™\7ïEJœ‘òµÍÇ미w­£ãU§{ÝՌڻîõ[Ý^»Ó¹nwx[Ö’ :&½bâGŠ{®Y]%„¦j.±˜#垸Ž"Ó{¼ækQ »ƒÞ |üúø²?á·Í—ª—Ž>9°ß&­ã‚íœ`n\BiäÂf§-VƒèùÊC3S÷f—ÃNe€XuÊEd>ócQQQõéRsG¡ ’uàQŽ]Üle« š £:ùHqŠ—Ãiá‘<^?åº)§K¬ø0cÁl !5Bn¥ž „Å@†@r¹AMÀF¼“ýg \qyt7÷§ˆuZìËFܼ âõ½N÷þãýpÄ·êGã!'SšÑ× ‰êŒÒþZ½Sí€à“NE?Ù~дÐâ~bImìZEùT!6 ­FmMmX.ÂÑdd ¶ŠƒßÄ]Ncg3aâd + £ÀbC°3ò“I !DôÈD@Hqd…GP‚iQ¦ÙàaÏÌ3ÙÄ(|LµM3õpšvÇˈìÒ‚G¸”šÀfb°Uy &4t&CCòDg¯ùÂkd8‹WT‹p¾ ¦fuNªØÌÚÈ yÌhÑaDqÁE a Ë,ê”:ÙÙŸ^7‡—íáôø¼xš¯æóÅã7¢l¿~Ýï6Ƽ›¦Ûþû¿ûçýNë æQ§Óôä64¹Žë:FÌ?nM<6#ôP’#µ°ÅR0ê$g`ð;’4§¢E¡‘n(&Š1$ÿ-„€õ±þ%#Q÷Õ¨«e“¯9ë"ÐÐÝYÃÜ3ŠÎ%¹CÍi¤Æíórq4“èTs5—ß¶_-ðo6«õ·ÏßN»Ón³;îö„Ž8^–\¼Ê`"”(]dÕ‡ ]c”Ô|ÒÁoŒrÔ†ÓÑônÚî¶>Ý_ë±×–CÓXC]Ë€0€É剙9RQbÎÅ‘åƒyJäJ>ëyÐù­ªðåóg¹¤»¦Þ•ŸÊ¢?S@vû¾T ’u‰bø#ÅÕbÝñ¡RÙ¤¦sŶ™ý0šÑ6N=.r1Òªew‰í3 ]+—NùvÎÐIÔ… lêÏ*EÚ8 jÙ(’3¸:ÑÍ–±\~³”ȯâbh1®_ÛÛu×2«Ö ersˆD‚ÿ>bï*a,›¤¨t§•¹7$ÑbRFsÛ329BLF PšÂ¹‚A'è‹ÊŽÆ>ù¬³µµ©µ2;˜Ô¾‹:"w'Ài¶¾Ã>GOM °ÈJ0Vq¢˜µM ¡@ÑÚ€00š_G1XMWßU¨¥zñ±LgŠYXÉ7@pBJ4R¨t4p]LI ³•r‘¦ƒj£þª  ƒãKøm1ŠÂ€ÙŒ XKˆUÀtt1¨1 ŒÆ€L•™ÌGÅ\Xþ9Y?/šÞd{ZW§ýëëñz»Æo[/·Ë§ÅËá°Y.[­×a¿=uG“þÍí-ï)êö^¯ZîÁŒ±ÈC”çÖÅ‚»LæÏÏOO›ÕJ‹Ùf»UuÚ­ö ×›Œ'½žü¶¾Î<Ž4Kò,½ú.'Bôw é&Ý=%!Ç,Û›Þ”Em!‚ªîÞ ªbn5‰rs6ìe+éG<–V @RȯT"Ä}Œ@AºhôÔh3…lòŸIK!ñPd¶M«ÜþUè@È 0­ˆ‘óSަd" \ú€a˜4±ü®,d(ÎÈLañæNDù` <Á&D3R ®Ðyj²PÅÏÁ©œÇ¤Àwò&ÄP½Y;.eAuFmŠáÇ5µ‘øw‚¢fl…žyWËÈÔj³ƒü¶ÃëzÜì‹ççå|¾|~|Üo6ê÷ûíV=´ßí úõ/ÿ®Û寀ÉhØéðr¯J3¹¥¢³Ð—PI}€ ”ÊM@÷!ƒ5‹  Äü± „øObÅW·WaÏ®Q‹•"¢4JêoE©D`Ò‘WiĈDXÿ:ú†BŠd˜Çp…ÊsÀigö²œ/÷ÛƒN ùûjûøõ›¼ŸÃvÜ8=í(–¬±}1©eY2AAÊ«Vçêµõ¡?¶zíÑt8»Ÿ^w¯ïñÛZšöä·É"(za½¬?Ö—íA,;Ú˜ØS'Á‰6 ú„(ÊÝäDT¨â’`ÓTAÀQ·½,°§*Ã"ðçŠ?fu­g(Ø^Ñ/h4 ú§ÎZ’8—=ª÷¨uÅâVÛ·Ú\Û•;)7Z?ö‰Ô"¹ HfðÔ릎ŽD·X6™õ$LšÁl¡• Ä vÃÑIñ TLêlŠRa?Iå\2R)^Š/ÂIu `€ A”Å˶dª<3!Oõ‹ÞþžûG0:zÑvù!lNÅtD`ejbÊS>‹µÛ+@Iµýš€œ0²-•Á lªLŽZbM/B(ñ§1.Ïtkˆ\j:o +ÒÈùÄ}Q)Cæ©r!ì¢'Ýc DŠC„ýï ¦:ΚY DÔ¥‡ùÂ꥞˜ t–7J792Ç—#ïT™1)à=¨Ò,Èx±³þ<Âí´¹H †Cëã–ñWäýì¹ÖÄÈGG‰ ©îtßIÖr`d¶ã2¶vä–Ô (ͦ5Þ·ÿÓô|ÖÚˆ!‰€­£¨—ÓÐ9áJ~F fÒÌÃäsT5üéõ«E]”Iܘ"×Oy6¿,™oÀÕf …ñ…dE6¶?¼[<Áüê›ù®:W×Ý–ü¶¶¦a6‡{½Îôu:<ê÷ŒÝQ¿öÚÃN{Ðiõ;Wökûútýáxõ*<É’Þ½;CÖ™:- ¤±‰PÝÏÕ_Ô˜¼CÔ/×Y/×+¹æóÕŠÇ­4ÆŽ»½˜$ŽŠ1ÑCÞ[И۫c…5¢Ñ¤ž8j©¨ F`:×8) «ã1ÿ©BŒ#u6_äñq_HâÄJh[Ô›0øæLf,´*¾IÌ~ Å’y4žAƒUx<1n2!²ÙÓ’Z ³U  GýŸ )áŸBu @@'’ǽ±6„º¥[X /’$´þ·ÿ×ÿ¹} NsâÌ/‡ž# Cœ°%¨¯{ðUåYœŽ”V ³ Ët£ëAàÑbQPƒ ‹`_K¶VßPÓIwy™s­ýöxÚóöÝûmÇízѹþ0tÇãþd2¸»»å-jÝþ‡ë¶ú‰Å!O}ˆ-6Ýnv_— ^ÔÆcù.È| a2Ç···r×îîïäÃu{ÍÔ‚q-Y6ÆðÙ¡xX)ìèÝôÌ—$ìe (ê°#­«uNjªX‰2÷&¤åK*`º Šñ*EB€JR¼\‰"Á!’â—Ó>à¬J§“— 9pÆÈy •YèŽI²A”lN) V°–& †DZ i†HJ ÀlCŠ!LA…³æd^ÁSEp‰ï`¤:{ká(±öÖ#ø ¯c$*ÂZÂX CÃ¥dQwÐ §Iøp|Ý_Vk­¹Çoóç§Åòy¹x~Þï¶r'4¼&£ÁÍl: ÿgÿ÷½^g6¨¿3ø™`³”&(Ñ›æ ˆýAW$xòN+MmS`B‚BØSCPJq ƒ ˜I‘!¯eJ½Š(CÌH„§þ«, /Ù%Q’-›ÌáV³÷¦2Žšb¼jö2ï-çžKк¾Ü¯7ÏßÙfÛ^¬£·Êl—+J–„T>˹€oBÖ”v_¸šÜL»ƒÞx6¹¹¿iuÛ7w7-¾ˆÐ¾n]Ûù°ÄØ•£¶H42TPt²_5 ×@i‡O5nW›Ýz»Ûì¾üúå¸;|ó{wÛ½ÎuÅŸ•ZñœŽl74PÃPzvP×”ª„Ó×:ýÕ–*øA¾yµî û^·7ì ÆÃÁd0¹&£Él2šŽ‡“8øûªƒ>JúòÞúƒž,Óô:}äou;ry¯:-;˜Ò5îŠÃ*¶±4eURè¥#X BÒUš;¢ÉöŠÌ®¯ð›9áá4IêðY_.’ò Ù«ëƒ,‰9hì aq4°Åâ(ÈdC\,fÍ£ÓÑ$êÇÉ­àˆŽ–~Køp±n„1mãNBiQRIòÄ$9žoã?£ ‡\œ¯(ìGf-–Œf£(:¨2”Š€õ5)Y>ª[Q˜f²¦2cp›D0 NR± ˜_b\TU^ ‰½ßLWûXC'˶½…§™œb03àÄSkÉæ€S#w%ªŠùY¾AîNp ð¤êʈN[Ç9DjB’³T ¨0Ù|õ/?¢£lQ*loë3Œj²¦zîôɯéjE¤ÏUu&qÚ÷»ƒ¿s·Z.ä¶-uî(§MŽ|›]ö.}häóÅeM|³¯Ë»× m=Œ]84k` ¢a ˜ÝS{‘ZÍG·8ƒ4jÚÕ!“ ŠNA|â…OK¼Áö=€ç gEÄToóí©v„²jÉ#QÈC# "%šBèPå½Já¢õLË@•øc ‡óù!Í„ïȬúM@†/3&](þ  ! *“šXAÈ ,ã6’êê#XËa[%ðõx|åΪÝ!¾‘}<èˆÇ߸ôdà“Gì+ëŽ&ŠNAb~¢‚U4AE¹ÿxÀM]>*¤‚6o313;`}¢Ð‹"jûSF d×-Ù  =ÕTÑd0/ôÐð}åÅ…³pˆäîÜQŠ)KyÊÈ8²ÍÆ m/G6<Š,g˼±‘”…0Á1Á°ÙÖ TH.޼?ùb¨+&Ⱥ  ­K$Y!ÛÓ#8ÿÍú{Ûð°ß©P\DX1° Èb"ø#M@jt%ý[½VKç ½ÖU—«¢×Ýk(½VwØëù&Äôn:»ŸÝº»ûéîþçûû_tTXx+ütwóé|¸™}¼™=ÜLnÆw³Ñítx3êMØk{­^§ÕkhqÛ\îö¡Ž]6€ÐêÁMu¶7ë Ùü´NiñHâh%eŸƒV–ýv³Õ₃»ÞòP-,:s’­©jV{Ÿ&ü`%Ž4б‚ÐÍ ÁÄ/É™ŒqM(Îáül¹t…ò—„Ê'B×l½òí[¹¨ ©ÜzëÕaQ‚X’Øu;c{Ï“ƒ˜ÒíéSÊF,nLFÞ¢£ÿ©Ï”Ô€Ô?A˜Œb'`0S\X¥!ŒaÕ³jI¡ H~ÜÙkˆµUëYòœƒs¼ÉaH’!£‘p1Ù‚â®G–sˆÚªkþN°pç PøBjÍvn&‹ {Ç$C4t´Ø4YÉÀIÑŠd8mì ãHhP]éxâ"8mÛÍnµâ6asytÇGH%ŠKEZ¾¸>:à´õ{ƒ¾œ9Ï‰êØ¥¶¥`¿Wˆ"/ è8ÃYÜaÑ£œñDíŠ]©?¿ÉÌp…é Øq+‚š2Ï¡$ÕÒ¿ f…°²UçXÕ!!y ÿ%DÆ·†D4½.±ñ“P¤—ÿ^€‰fOpDDJi*.Þ0%˜‘@Ÿƒ’æ‚?„ß`‰ŠºkF#C”ç0Á¤,éÉ’Ù¬mÝÚÓÙ%Ð?Ø;ÈW;ÈuÓé¿7ž¯yrF+Gîšz¾oÂkc_Ê3ËfAQf¥SÄ2â•/äŒ:lju¥¢Á -™’5(™xIMz•åGB²Oõ½‚DÔ?ÊTsº=B¬‚%ñˆ†æ :JÄ3=:ŽåËòGÆ'WF}mTÛlæah”òkpNC„E—×UYT#§ ÏÍ»k‰í¶ö3b>^& ÏC¥¹™pô¸:~€K§éi}Ï1áºq¥ŠË£|”‰¬@]m™…ÑB£PjZ¶D{|ênþ¼³ðCûƒŽ\íµ»ÃnwÐL†ƒéh|3™ÜϦ÷7···ïn>ê(íVþÙì_ üèèýØä´‰_8¾› oǃ٠?tÇ\Bmº”Õææ9» <âu0\1¡\7¾‹âԃɀ§ŒÇ¼‡²rqe—òfý `yo;¾ÈÓ'2ñHb1E…n÷ ¬ ‘³3‰J·â<ËÔ²g&ÿÌ^Wuå”;f'YýÁ½Îêäx™S®˜SqøäwîÅÃ+ àxzÝã¨á«ùê*Ž Ñ®Ð—¾£WyF‰cÞf–ªŠxV¥Ð?B£+òûHþÈ Dgs³9À!ûeƒ™Œ!†R Í4ƒ»Cœ%5AÃ3CLçlÊnCƒoá- =Ñ&b­ÿÝÿíÑâ^ ¶y…¨UÕÏa¶âhmбQB„Ýù&+*ÔÀ \3úÈ!Ù9FU,OGk™Mj3*Øâíî¾NzÜŸ¶«íòyñzoÀVv«ûrÕ §IæpÂO[­çóù—/ŸŸŸŸŸžVË•’TûN§ÍHƒŸ~þéæF“Äxv3ít;Ãñ¿›!PF“®S”I2Ì¥ªahQeªÐ°:*–D’k¤Ô Oጠâ 6Ë/ö[ýÚhÅŽÎR0õð~Ö3[V•Ñ!xâ hðZ@pE 8KÔåÓ²hÆx¢îêH@0E¥2ÄÙD3c`¢~ü.ÕPjd&sq þ“îH¶ ‰!‚@ü¸5S^‚ª€M2“½9ÝΓȒÁ•GZÌúG,ˆ“m)[4h‚Èâ#Ϩ)OP_ÔJˆ0w^v»—ÅŠWO|ýúüôôÌË¥Ü7îón·no§÷·ãÑð_ü‹ÖëutÂÒå–€7&KS*QŠñ,Д›åª: U „U ¸B%×ï„K¹€¤Ss¤ëº;ç”dªµSãTQÈäîS©醰yƒ #¿’Ntÿ‘…µÊ),2€ ®ßpÁ»Xeñ×ãëóãón»[-–š©ö›Ýòi°S?fw64só@l:y”«æÿk¾I:ÈóÓñ±„Ùý¬ÕmgS¥{× mQË2¤þ Dœ:ÈvTéAVí<ÛÆ>›Ùo÷Òy³ÚnWrJö_>y9¼Ìç»-/:ÑZ.Áš••>Ǥ„«¬¸ê¢ò(2ÿ=V¬å1üéNr¡ä¨ñ5.^uýMÀÞ°?™MzÃÞݧãÛÉÍÇ»»‡û©¼²OŸ&7ÓÉíl<ã:)úOF£éÄÇñp:–“7œŒ‡ã¡¦îþhÐãf¸—û¸k~n££Õ@f²’ì(©®VÍÔLTSÓ2´=Ô̧9•^JåTÿ(Üj·»ýžÛ¸OL}Åš°7-*o´~È…/fÈÂPÐ#ZN™q†T/›Fcµf!]³grÚÔvÇÎ%wQÐoÁð59zW•UáÎGÓñÞ¼yŒ(nÓ&ÆžV49mVW(“èȪíBQÆû™®’-E­pݲFâÚfZ‰ÉÌã‹Ð*å ùÈ„|ô¨Ð1?-¤¸Ç…( Nm–ô2Eí¨>ኅÔìÉT&äYTI¡¹ÀÂO41’`®‘|úw…j@fŠr ;þׂï›ìÏÙÇÓ«ÀGµ!w™¸ f"0°ÏÏÇy<Ê•Š,v-o:ô½÷À#K×ZÓ:Ý44ÆbZ¶`hÿ‚küW…ªSÎ_¹^ÿ­Be†ÙCiêÙ:‚/^4Ͳ÷¬@ uaN«x¹V³v»ÃgR4ñT=ÛY3æ ßÿÚCáGºý¡¡†-ÈËzXóÈh1™nýG &åA ~œ=9N Y“¾±Àý¢ŸTàh!Ô¿T…Øg‹Mþ¢üe%¤$jw™“j‚¼Ö:_-·««îu«ßn :ýQo0êF6Þ&òæxaÀ=m¹eƒq_X=‘àg|œˆ[wÔ+)ˆaвßö¡ï ©UvG¿P2(¾Là¤X_4²¯¯^€ðÂ{¦ìÉ­9hŠ ¿ ~g_x.rF4¬Ë¦"n\¼º‡vÌn‰Î±…æ]4W!¶ÐDü ål­½â•BÜ-+ :×FyXm9aì·q9U¥Øƒ¤hwƒ !Z1ÂVøö)¤þïÌRóaÔÿ¶ y­ÿî¿g¿-öÞÿŒ²xŽp 9§%© BdÔ?§+œ^ˆ=MÅ[œÛ—4òš %ÛËŽƒ¯xôœÈ]ŸŽj·Öns\+ÿñøªS^Áü‰¯Å?=?=>>®–˃?Q/_mløé§ŸÇÓñO?šÝÌx””·råHµ ³áž(-U%{ðõ}é¥ÚFœ<:qñvµ)Öpͨeñ*`Áf{A4—”À€!ÈÂjžÂtAD$`æç1òF,)ME¨TiŒ@é¤;ÍÇP\ ˆ²»+±‰à%y¤ 8ƒ‹\—*ÌçÁ+ŒN¯C@1@ w‚o I²X #dŒ\UÍjöH `b¥p®ÀÁÙjõ)Óå2Ãh%íþ Â\&OÇVÇy¬w ‹`ÑM‹v@D­ÎZ„HÊÕ¿ËNíjPÔj'\D߃жɤ°ê…®iu¼ž `pÝxŠJQtüåä¢kÙ~þö¸[oyäi±ßî—óŵֶh½0°¢\Of ýV 9Ö 'ÍÐò²{ádØê¶î?Ý'£Éídz7½î¶5_1 ùæ «Ê;5WHµiPT”Ž A:°ï‚’ô³Óåª"¾X±Qøëç¯J]Ì—GöÛxD1Om%4' ê" Pv„tS”…†[MØ©j_½¶~m÷;×ÛfãÑøfúéç£Éø§¿ùyvss;»› §ãÑd×O;ùîîu¼D½—‡}¥ö}gwÐku;ñZ€Vˆn÷x<ª§3ž(^*s…&AoZpÄ1³žb R{ v„h1sQõÈ«ÊiÁá–èÖu·×Õãñ¾ÜsM/Í`!Gý¯$ LÑsQÎë"­›IÍÐjµ(W'>Åãèú:©S<°½pWâþ°ÛìÔ-7«Ír±Ø,×Ëù’çaË¥Èçùây®ùBÇÅ|¡k„a¹„‡/í®ý½Ýín³æÓÞ§·å¸ÅïÀ7%¼Ÿ§¢uô­lîRCVóòF_Æîr¹?’ú`‰¨96ŒJêŸ5_•´EÌáŸxAÔ/Añ; 5 ]CŒ¬ŒjÆsHVªÚù !ÑС¤ ‰¤ˆyá× ˜±B¬Ö!ÏT-ÉU@ p–AÄôï@2½É‘ ¨HÑémsƒÒ¿_œÔÛ¹"'t·C0œý_¹³5ìÈ Ü7º]o÷Û/%R—úð¡ÝÖ°â¾ìÑoM{àÇZ¾áWÍà<ÑzÓ·š(š¤1ô3””Ú“(ˆèdZ$‚.Î¥4DžYšàìg¬HΠ!–b΄ R„KWÎUuêdÞR~7„b¿7ø~jXhDßâÿbhd¯ÄDy‘Fñ©IOÌ$h¾¦#ŽË¦HÐêÁm-§ÜO¥fu~ýczÕ¼7¢irió®«EËtã},®N#ª.µRз;”MwúŸ.þp×þNSÿ24jÇjoõP$ñÕohàŽ¶¸-L®´Ÿá;9Ó@š_Êú,`š‰VH™aY×–™åX·¸Üç/(ó}=N¹aªMW ¾€ÈLþ(Üâ8j‰š"¨&;ù/|V`M´¹°DMÍ]#tÏó‹RUŒ¤ùr‡™N ÔU}1On\çªÛïðôè¨/N'ÒãÙ8Õ¹ÅXçåá´uä¿êXã ÓÊ;ã½n½!ÏŸvG=và&ƒþ”;äðùnÆ£Û‰ýá@l­^W6”õÂÒŠaQêá ù*jÖ!ÀÚ ]}Öš¸ª££<¿’îù‚Y¼¯8ÄE¥SÄïê}°®‰ nŽW.ÁǦ>$Î fÙúÕ'ý„ùi»?h\o¶ËÕv¹^ËÊ?{šWÂgÑÁÕób-\¬„[ãÆ¸[­y´œûíáè[úØ“+÷ÏÅó yÓ:ðô‡,NýdA6çÜÏœºÞ®VM@?r‹ŠzneÑa²ˆF¦:ÉÌž«¾[Còü׃P#« ˆ$«AÑü^B“-ƒµ‰$ˆùK ҚЌV»D(GEôwZ«JÈFa6A{´§0NtºÀ™Ÿ¼Ì—#÷·±ß¶;­WÛùÓ\Nýf5×ùÌ ßzãñhvsË·—Û]õá£zéá¸^otfðüü¼Xè´bµÙl4‘j­Ò‰Ñd2½¹™M¦ã‡‡;ùl ‡Cnüá¶6¹ÕÒt+t%3žSU ç—KNêSiíè…Š§Ã4š5¶$²ÚÏ©Œá`¶\Ž!pj ¦QFò‚^D%= 89€fÔé £€4Vg/ÄøMh¯rËÂ=Ä”SíF,&sŠþTb-‹p § Äe‚ ©p%*~ ɓЄh(A¿À ›³ADPó*Ç9(w25’¾WbÊâ™ `á”ÌË#Æ®™=Tl`6ۼ߶ݞ6ÛÃׯ‹Å|ýøõi1_îv[ §ë/7ÓÉpл¿><ÜŽ†ý_~ùÔn]ã¿élEBÝŽÜcÙôèZ%*ÜxA5…t÷Bâpæ88±`i5œÍhÃ1RÕ“dìÏ€ª ,¸MI ¨PêðÕ¥0…VµÉaÏ£‡Ãq³ZËE–ÍwZŸËçù‘̯s­ÒÜTÙÔb¨…ºJ©¥TÛF]û²^g4™\÷Z÷Ÿú£Áp:œÌ&¼/£ß÷zÚâU"Œ¥±¤0z!,YX£mUïß0tñÑ>ìÖ[U„ý••Îxß>“²š/»=/¯ôΊ ÅMQ”lvÅ\¼omÒÑ:е¼_Ѿ¶¯¦Ùš‡I“A»Û¹¹½Õl<žMTAyo7÷·¼æcØï zš“yû.v¸âKô±]§^Åç%Ð÷Ùù(…0—¢rkýñuyÇÍn{ß'/´uÕR%ªß*”Îø±aŠl Ù @‰Ñæ£ëbZØSmÒ¸äðª“ÿN·Ý Æãñu§Ýíuy‚5Ía†ÈKc5CKŽ} "îZt@ˆ©Œ/â)w-o¿¹¬ùÊ+iüq˜Øî6›=·Z®Ô!W ¾ºÆKæ ^R#ïmÅ÷sEÁ㙽•Ž-•ÜרãZ h ¢{ïÕIÚV2yl–2xE¡¦?«îóÃÓ~·çº=OlèüÅ%îüØUg1¨'Bš!lé°+ÆÁ° œ¦>£Ñà¥è[da2#Gr…8IAXa(P‡-© äÓO¬§©Fá7C7$’?" º@Ä:Kœ9“Ä1=KÅÐ9K­ÃJV¥õïþã¿¥$Fyñ#B’]^ŠNA-k8×,"êKôZ÷O*4kB{lâ…¥™Õ¼>wð”@œ³¡Ö++Žü6¹ör×òým›Å‚ï\ :£¡ü¶áü6¿;\çqrÚÔc‹¥àéI~Û\NWH__‡#yh|áþánªiâán8L&“~OiÐI˜ÐY…£‰•ä–µ%cã×r¾’â5‘¡,;©D7‰ªÊÊ“ ÞÞÍVdÊñd­®e(è–̃¸Äœ“Idø1Xrf­²`üøåGÄ —@üºž'ÁOF¤ÙF0Q¨¨Fª¢¾¼ À{¿°¼¤XZBX# Io¡('ŽRz”ô Ö b¨¤º á1•I™Ò/Ñ}0*›}5éšI…Ὤªxji–|¡@púPÞôÛ”@_É…KÚsÔŸª¥éQK‘fÎíö(§Mçß}|ž/¿}{^.–ÇÝîÚ¯»¿½÷7éù½Ÿ?=ð*î p/ia˜¥*ß«X¶VC[`¬yÈa¦`­ŽÖ¬M<çE©0ÎÈi5 Œ–¯\”? œµ† äÑ”_PR3ÙZGq®k-L²W¬XÇýa½Ü¼_¾~ù¦uNNÛüñù¸ÛkÉä#é]:‚$é'&“¬dSUü69!rn:-9“›©¼œ‡Ÿ>Æ.•ÎÆAÏqå>ˆCdÅ­\i&Ë1Ë¢d[OQó?«)çÉÜîñzú° ¿m±Ù,7ûÍþÛûm‹õiwÀ?8ªCª8Ë1 å<È䩸›EÒ©—ë†'Úò“¤ùN]ÞH×ïÞ?ÜÏf³éíôãÏå·ÍngòÛx[¯£I‹ørOù²>•Tm^åa%‘÷½c4<9|;9…Læm®ZvÚ\>U—'1è x¤ºÅç ÷û2ªÙ˜l#Àî…ëAÕ\niXÕU*@õB +n`×J4èt:ƒÁ`4kòÚöÛ¢âß`éÕ±2aÖ JŽu\´Èf †Øáf"»n¬™±íç½®ãqÇv믔ÇÃWÛ,žæ›åjþô@óÕr¹x^¬æsMåªèÂ×L¹6º^àÕqUNžû}„«Íš$uiÞé½VßØÊ«ãMC¼ewÔ­$ßPžƒBþ1úz“¾êCŸ0¨ŸõppmdQ\cR=7ÁãN8+1è¤æ)íb‘ú“Ìê 93Þ@çu±â‘J)[¨!Ž4 šâÞª„›Å5À¤Xå1ëè¶d,ѶB‘Ë"7 º›¸C‘y™š±7ÐÌ“¬  Ò`Í@'Òd…7åÞQI-ãqÈN¬ŽÌštxk¸N€uÊƨïäÕ ^–È–[WÅ+ÀÃô~í8§n›è%.iÍY¼‡ê…f?“¼®O "ªuƒ'Ißši%•Lh­b•ýÅhóe´ŠóCŽ 4Áýâ/C‘¿š¬ ƒ ¨ãuÞƒÌhLagrþLø½yK‘9T}5 ¤©¦¢¸}‚ü>(ñt& '1Q]µ^^¯q!bâã¼–oŸñrÊ++1ªÿËIˆ.PjÊ°Ž€q‹èAçÄ)ŹΒÿé ˆx«ZÅ~GyE½Âwyað0“ Faò5ÙazvA^|‘4Pþ{©@bk@`TýGM`Mqæ¼:pJ¨U‚ˆ•2o‘Y ²‘vˆ£ZÐEú? ªÌoLÄT§N5gD³{HDŠô4­yH ɇ€ó­¸–¯‘´;=¹W:vÚ½V»ï—ºµñûâÙsʼnýëÕ‰‹½-)qzm½¼È S€kr/:LJ“Œryy7¼Ãv¿ËDz„Ìú:½g/S.jñ}ôO|DÁ“ .A¥x…àöd:x&QX þu¿;½›Êùô˧a¾c|Í5@öT &(†')¦9TÝݦS$LèzèOœø—šªN¯ò5å…lVkUm9_­Uíéëãëñu³X±cïD“eU†ªLÎðAâWúD>;jò9;òÉZ½a8áÉлOw£ñè§_~º½¿ÞÎîîûƒþ`8hwT=:õ]=öƒ­³å‡õ¢"Ñ,Fß¿¢Ù˜Û^ÂO붯;:±×BqØ岩²ÛÍV¿Û¡§'¦òdiìŽÁàb6£1“Q]©„2¡u÷€\©¼î +/n8«ñ´$ÑäÊ K¤E"*ˆ2Ô2;Í`5Û0¶\ôOcQ‰]Ïã‹ZDÇ =¹²¹zšëøå3/½úöùËç_??~yT‡T ~ýüUÇçoOÏ\ƒâV6¾‡±’÷&wk³õwðvÛ½‘ÑÅÚvÃ…QáfÅÖšì¶fy].žçOOêðZgÙ½ÌÛõvñ4÷ûí¹ê*¹¥! a<ÂÀ»¿Oê2v.S¬.êêúUøŸYc¬âN#nLÌ«0sbà ‹­C.Rà$ý{0½ÍåBk `ŽVáõ5ÎL„^ˆªÁâ ‘7 ÝÖ'DØÚºÜ+¹²ÑÅÌPe( ÎìCo™I8‡L;ÑCƒ.+› ½ ù’ƒý-ì^ e WÑ8‡Q²41ëÊ}™„HŒþrÏŸmŸòÂ#ˆ)Qÿ`;ÛR€I¢*œHëGQQ: 憨¼¾\õCÈLD‰”ñßæ·*o‹1ñ œäã9ü@ÝÌå|Ì~ă\d8]fÂRßF“×p‘¥Ž2r .•ј[3IJ&ý}4؃¬-ठ’ç»ÐdøMæ @Ûê%º¬I©Ã8Zšä²ß‡·”í)Kx U'?£2èúX¦hæ{¯˜]e ­YªË-„fóáÉÕ BÀàrzÄkcP’½ÈÊh¦G’ÀáV'g¨Ë ¦à Ê9†)j —h[­¢-b+h0WñwrM@q»:3K½§´°¿!#ÏO£¬* ‰4¡.PÜøA¶+$At™‹öK•œ9Á”„:ì ÁSEU4™j=q:­ÐE–ƒtüÇ*¿“€¦VY>@ ú±ë¹’߀ ƣͯ¸ÔE0L–‡YA››‚”$~Æ™JáAŽ(B^cG.Wôd»¤7RˆRª[³Êç>­šÍJºÌø=@Hˆú=‚¨% Í£º]Ó÷ü"ƒ×_·ßŽû×Íj·x^œŽG ^_½t»×½^«ßï F#u¿ÓˇÕfûô<||ž?Ïå÷ŸNG)££c5ÿéçŸonoîïïuŽú]^ÉÈm¿¾ ˜'µÝ›P©2Ê@ŘnrW {EUq™…tPÖ2&©™mƹŸjªLª4æ+$تÎ'æà·8(dòɶ¦S˜-FŠB5ûéüÔó|¦¹ rc†),Û¤RÞÂ#RÕ‹P±• ŒÇ¼«0š$h}Ð<ϼq±"4OQ€ƒQQf‡è(¥Tš ËàqÑ „|ÎÇœ% ~†Î.’Ñ'íU’ŽUT5‹&³yjsÁ†Ø\•FôÄ ¨èghþ3Œèa)ˆPAza†Å‰ªQt0åb€¥]gˆW1÷ú1ÿýj½]­¶Ëåú×?}}zšëdZçrê#^çŸýáçÛÛÉÏ?=üòóO“ÉPcBF¤OØ©‘i¥g¶\£’bŠ‚P¾w¢…"*¦ X'¥¯Øˆ)J„ P6 ^P1º;W,ǰ¿3:Š9Ì`“T—å°Ñža„¿¢XÏ(4Õ<:ø’Y„uŒBcµw‡cOGG‘Eô­K··)=¼=DX±y¸‘Z(¿M¤ö~«žÊs ó'ü¶õR~Û©×»î÷yÕh<ÒøÓ,ºÞîä·=?ÏÕe¶»Ä¨òöÛFƒáàãÇ“édv3LÇÝoH’*\'•gˆ®h+1¡­¢š;82¶­|‚:ŒÎ ¥¿1Zȉ¨­üŒ@F›1«}Ë„éLðVäȈ{×`&94 sfé|šYlæ mla1ÀœµIo’°kE ²Ê²ê¿ɼB[…ìJ‹Á¢BC8 ³fèJ õ¯U“?Ä›R0 ¬¡]ƒK÷`%p–«T“ú')yr s¦’ƒhÉ%ËP¹(‚ÜäwÃEôRËs ”K°´ X°cÅŸt)pd2¿%ÁêI½ñgÔîíx[,;¾³+;^.­Ž/×íó¯‹ùJ“¦¸å· ûÝ^§õ7øéf:þôñîÓ§ûÁ€·Mkø¥$‰÷ŠˆÂdd_-‘p˜ÚG›”*8bõpZ¡ƒ’PÕ+š +…$Û$£`IzE1ŽÄ˜P›Px@Cê ˜µÏSY|£„FÈúùÀåiò#ÁRx–\2y†ÎOÒ=~{:Nß~ý÷v{7ÕKv?U@ Š,ÊÖ+T+×Wr×äpJÙÅ{“sÃs Ÿ>òõá`8šÓ[C,rXIÇÐÓPs”`$F] V~›ÖTt­ýømÏܨ~Øî¿|{9¾ªFZ²ÕYT)wå?X%™@U¤6Œy&%õ(×êê¯ìözòÛâ¹òAùÛ?ŒÆCMËÓÙ´7àƒ¹LEÑßb#‰«Ñø^•ØétTŠ4Uñ”Ë"Ò7mK­ˆú‰2>Èo“ï§âåƒJÿÝn·Y­•}µœ»*¥ü:• Y;MrCS1MkòÆâ f”޶ߦ5HSõÀŸ|hõ:ãÙäZ^µ/ +— €…†¬ JØcP?æ0*ÉG†Œ¬”ÒÊgl'¶»ä„ä"w‡õób»\oü¬èn³{üúÈåLyN«õn³çÃ)8V{ylj_œ0fÆ=;[áoxÇÅ"lŸˆ8«}7ÿÉnH‡&²­[!Ì‚†N¥Äˆ:œyÎZä,‘·äJQ%k•”e5R«pFƒÁ<p–z !Déï$œéó&Zeóy ®„¼–­¸ƒÛ1´*Ù“È»Å5îÊI%ı<:ŠÑMˆ¥¶%“Z]}§œÐzóŒŒúqŸGX,Ä…Î’*,ÉΤ¸3sa¶ÿˆ4ªÄ¥´ìGI§FÊȃŽ*ÚÖ)²-:J€hŠ×Ìj±«.]y¤|³ fvƒT7»¯ædÀ^%™ªc/¥$\DÔ =L•›)wË"BŠeJ–¡í{`QþuüèZE­ìn@'ˆ.™Î@Õ)ºZÈã§HÎÄ ñaý}÷ãþt’Æ)OìVëír%-^äÁ[<Ö¼­CÈUËszzOþƒ{¦[:û'OT€¤JóŠNqrŒã={0ø:itlß’äŠs!•>C·òd;WQå/ò¶ÞÅj5ç›oBžHÎW¼n±ä‹á‹åvµÞ¯7§íž'Øœöƒ%FlƒÉ0¨ÂÑ"Sßo´l륨 m;§ÙÿPÖ߀d¬ tÿ&„VQàjSj b^'Í΋êNÌh1¼ Àó@¨K¬¤["!¼ÈEOÏB€F(»úp06iÒ☧g’æI¶ýrl]½´wÛ—ãáe½Ú=?/N‡ýóóÓËëUúúE§r°u^±ÚîÔC|?~­. þÞçÁì‘Nænoou&tÿñ~< ‡Ã¾Ö/ùÄšãDF†eph ”2h+¬*SôÆ$û( o€3}w±J…"ªc“.¨¢*ñ˜Õÿî›¶w‹¾>§7“*A=T!ñŠMg ’áš1ãQé’uŒ"HÒœšÖ‰ %­ ›üU®›(¢éE=MIº16S•bÐUòS^øŠØˆZ‚ M¬è&JN_Åc­ˆì9#(³/J&Z#!Ž•@+Œ(ˤ)®ÈL±ghioÐâà[ÕˆÆ,q·´ ,mËÅ7ZV 9–w8¼¼ò–¥Õv±XÏŸWógÞ²Z­åÀi6m·®&ãQ¿×ùçû77³Éííìf6ÖI<8™[’£ï¹Š*åZ§¨.NƒAƒ‡¼g¨ëŽz™ü@Å~MÖ°®*Ô}3¨(‰™ « Í©€ùŒf´æ¦"õ º0jŽÅ=§…ç"kc~M@:e|yY.W:]Ü,×ß¾|{Ù¿üúõÀEk¾ìÉŒâ¥ÈûÊ<’ïòP™Y¸ÀT¦CÛíqÝOmö»Ãáðîá^'œ?}ä[OC¾åj›GG@ˈSeÁ˜Š@T" × AÒ¼‹Ê; ¿>=>í·‡§oÏó§ù~»üú¬:{¿Mk­µD* EØvÊ” —P•‘ ¥…( ó¨ZvûÝñŒ¯>Œ¦Ã??ô½ÙÍt0r>ÁãÔ«…ç†Ö‘OÙ€`Rä5ØNÉ`n«TæAêÉöEÜ ê¸Íj«ŠlÖëÅ|®öó~s)Móí$uñZ°«„È­tÛh|ÈÛĵ¤p99 ¨‚¥ Þ'7ät‡ÓñU§=½»i÷ø ‰2I9$ÛÍ/Q²ŸÖZŒ Æ3^±m;×:úë|Œ›ÒØB[oÏóçǧÅãó×?ý:žùõ Ï<>ÏŸWò…žyD@}RÎÓËgÈ'ÑkÝQG{cAü°X2ˆ¹Š¾G^ÂëÀ‰·#/’\8µ€Ù1~›Sý‡|ã=4ȱ䡅…¼4¹qJå]"\BåE%Z©ÙoÙlyI5­@cª7©µ ØÇ š Ù|I3Ѡ©™”¨~crxT‡yâ¼È‡Ê5H\¢Ä*`ÇΤJ=úH’>ç2x’›¢G×OÕËoNQ€®óׇbü?¨^ $ÉÝ1øè3µ?CC,±î°÷ÂÀ‰ÜxÎŒ{Êþ[…?W»ï1ÿ¹ô<üy’ÅýV%dTø.*üsám–Š¢@³É¼×½³ÑGcÖNFÓh$‰äÉ!ʰbÏ S ‘NÞ€"¹I×1”Œèû üµ ”ù+”XônqM á23¿å<'7Úð-0Ÿg0€þGƒ[ Í6ªùLÊܽ„ ^ÁûªEjˆâ¨•3l-¢*B©<¡¦×¸SIôñ,«ÂU´ _scæÞ!Õ`e~hÿïÀ»RXÔŸ ’–ë!Í"gÄÅä(úÀw ò fÐÕÿð^ (XÇüU£kTPúYæP´Â*J(ÌM O ™'tVª…Ü>„õA:¿ø…søò©ªÃ©gÖ. qFó?EÈžmhR"ü=ø1C½ßî¥ÏY,TÿD#&7OLèXRƒéÌ\ JÊS$Ÿ£ˆÅ‚«Nºþ]MçIÑèq^EÃqÿkçË"Ã^ýëv½_Ì×§Ãáùùñåeÿú*<ÐÈW–ëíœw®åã‡N¯ÝôoooxéÇÃýÇoînnnoFãá`ØÓ9б9ïÝùèb ŠR=îLˆó»Š}ë–ª> Ö¤6À¡‘„MK}3 câùá¿Á&Q•@ì:Š‹ó©tyD€Ð§kÁ‰âÊŒACˆÒ|2é ÁÂÑž±“ ùã8òÙ}©x{Qq,ˆ>©| 8Aë¹8 2•r“_™K4°d¨òª“ˆ(&x©šB‘×›C™D*•3(HƘ€„ž%²&®$g¾Ü±' ]Ò2»S¤c¢S+žG«Œ’‡p_á* ø%ÄäqÄNÙ Åù¤N.#£NÃN\Îx],7óÅúéqþõÛÓ7‹Ïç»íö÷Œ¿ z݇û›É¸ÿ¯þþïîïïîn'“ɨݡ¯Hj¶! Ì÷eUˆ¡¢îQSñ\ûrªúÏ_t3Íñ?#K±Xê~F ´‰üô@qM§XÔKl&5èUô_/°J‚™²1Q…Zr^¯6«õ~»ß®w_ŸN‡ã·¯ÇÝá¸åRÏÍÙoS;…´¬’‡Ö® û ¦L6Þ\ê°[sÍ{ÂGƒñdôñ§OýaÿãOíú½~[¬7½Z‘ý‰MÐj¾<Ťc ÂÕ+Ÿë¼~9²ƒ¨ãó·§Ãî8š/Ÿ—‡íaþø|¥…õpº~Qì„h=P÷aÚòó´Cèœ*Ä][d°Y‹Oô¸ñk2ê šŠo?ÞNn'ª‘ê2™Ný™ÁöuŽ4:$Ö1xrdÊ•U¼)Mu’TðäFŠk $”ªò®^®®^®?¼è´½·ä¾½ãz½Z,žu¦¿œ?Óß5”4ŠÔËcæ~ŒMÙ)P%ýsmU\GNŒØrã {íò­Ö@u3m÷º7w­~÷ºÓæ%Ö‚Ô?DU’ÛO. Dr+›úßÄxò œ7ž{ù´øöùë×ÏŸŸ¾>þúÇ?Οž¾>óY*­}«5ŸåÞn{\:—CA¥WÄ8·•¢j²n„eQš­à4ÿ`o3ƒþá)B'Kš[Z£ÉE—ü¸ìóÂ}|SgvÞj“¶ü+¸÷q쌽¨ÌkìÈ¥ßJKsAQšÁš€VÇÍP*BÄ $mȬ\ð•TAÈCš…dQˆq”ÌÎËÃEX‹6K¢ªŸE‡äÀX‡àIK§4ˆÁ n#~‹kû1Ð¥2eg&÷_•¡3 ˆw!“ó€1ø1Ñ@õ£9=Í¢—¼fç€Ape ·Ô$œuœø¤ÕŽ— z³u»ckøtÐPPêvÛý~o0ì3Ùq?/÷fóñn@ù?´ J”Å X¥ÚƄÜ©ú_ )¢.õÔ–M¥°ÚÑÜ/J…¸ò3Lá Œì‘%jü>úÙrº¨Ž„ä­¡ÉPs¾ƒØ5ŒDEž HÊ5Q à(“fp¥$W̒㤠GÔÊ(깘Ð@º‚™‹ÌfØX$ S`äª3¾ƒ¥è‚uqê»V¸$9*%ÂüUà zz·*çÃõëËÕéÄížÞ÷w _$¢ÕúÐë\óÑí~GG.º‡Žª‰"¢pAF#+žœ‘l!Áêø˜ºÃo"œ–©c-+”)¥á/G hPa3êu—õ‘¨z`銅áðš!(Qa%9 ø VÒVãN -Nq5*—õz¦‹æ̦”~a0D(*¦VÒÔú\CÌ»Áh;ú$¬È‘X†•ë¬&ëU,D-`ɸóÚm0‘ª!C2µ‚úFbtHËlZÀ}ȪVÕÉ á`]ÄË,ê“y’íñCŽ®—Ä|«ctG7¼Ѓ¹‰N5¦zBæo†1ÉÑ#t,ú6à,FƒElêdÍ]J[*iãóƒÚ™[P‚Éó  Iàˆþ HAœNöϸG(¢³¸…ïá³î²¿ ™+°=+Î`aN=²jåøØì~µ¨ß‹ê#ìhtŒÀ$šno5‘@Ú=ûý¢tÖt"·íøv~nÖ¨.ù([ä5«ç=Õ!£&gŠŸÆL¢I‡o»ôºœxo‘P³òH’-Jºf's»¤æˆEÕÝà"ɹ+¦ôœ—ÜÙ>ÈOyáƒ'4×ã`–@Û!åTõ,L.§€çUæRU@Uê÷ú:Ÿö·¡Jré™]@Iȉ¬¡œ×¬h©X¤ê$£Ë>—cùv¸ìР78"1Ë•ÏìäÁÃK¼ ‡G¥ûÌ>–– j$´ƒ;TbÉx­![œZøœKýh:l»õ†‡|ë}ù<_Ï›Õâ'§EåáR"•}N׈•RUA´¡¿–º„ŒNq1–í|/œ€”ág 륱­¹ëÅÏB÷'£?±Ÿ7ºi@0(?Çm¡'×…7úòÈ‚–ííf±æÁPðÅ25UŽä¨âZãñ´¾x¸ °ÉÕ%Iîfÿ Шú+)U[¢†”h™– ¾+Óì5%’Áß…`D®¤”$œ<‚Öÿþÿñ¿&ݾ‡ *M@ Ô)õ)Ñ@.y€*š1‹w„!,̉6‡†RJVXÉ4Þ=­Œô§zÉë‹&Óö~Ï–›Ínþ´<ß¿ž»ãi£ó ;öW¼CI]Ìöû|än:›Þ¼¿½»ÝLÆÓ±&ŠO0©Ã©]è1Öq'C «CÅ­¹F 5 ƒ’ÖR\ ì»q¡“äc4ö¤­a ›Á0¨úZè9H]—ÏsÐר>­?‡ÝŠ„ö¦TÕIV/¹€Bwùpš®’54E´€u•gŠ„J2ÅE˜F6¿1š»¦X¦Ù‚’IÎnSÐ¥ƒ*RIQtSŽ1r)IÕ¿Hj  fté–i×$ 2­Àh_-WbFY,¬h|¿h+fˆ p:¥[”Å2&D,Pÿ:Æ‚aRäõ4*ÔÄê©çOgׇӇùbõ<_|ûöøøíqþ¼ÐÑizÇ~Ût2úåo~šMÇ÷/þööæf0èi„8—B!–µI4&e oæ)ªcTÄš›huaN ɦc`3ü–‚¤œl›Gĺu’ø`8Çʵ4Ý,G£¹Ýâ ¸:f(@òJ³Œ–þz›k¦ ?¿xµ\¬vò•W›¯_¾¾^ž¿ù:©_|þ¶B¬r!¡1€$™›ÓÔ¸_3O‹«ŠíÖd:G£Éèᧇޠw{ëo xs7°2Q1×1¶›HuiX;JI«ã› äˆ) 3Vz½’—¦õõøáëç¯:˜?Ηϫã¯ØAôßÐ;+"1¬ïRUüÏ ¨3ïM¨Óéõûíng<›ö†½›ûê2Nn&ÝÓµêL›„¥­/ÿÖ9€yXö1 Õå2 J ÎF}œw“-Ÿkµ‹æ–ù·çÃn¿\,žŸž^OG$H®‡ìÁy€mfÝÃ|n êèZªÊXWfÇ«¢lF _’UÛ©]xÞb:RÕº£þôþ¶ÝïÊ›»â;únÙT‘.Á&SÁÑúaÃ!{¯7«®¸â(G‡¯H­ëå³þ—ÏO«¹\·çå|¹]måèÈ·Ž-†qè‚l1¤Ö” ÑMâVq±¶É1€4§ÌVECãU™ÛüdÄU,š²ß¬)áî¥ÌQ$¿ØŒŽ".PòåI8m'H<…6W×/§×N»£ -ç™ÊŽBÝèP¢ ÐÑËjÂPR«X{} ÙÎÁ$Y%SËEôJ¸ÁQý×IÎ@– ÖG3T’tæM>¨R%PFŠpEŠß÷¥nFÝ?DëÇ=2dI„V008Áˆæ©è€ƒd¤ТBT:SU$™S=oÔ¥ðı‰?†[èl¤u ¢ ­ÄdGØ< „!@Xš~+…$-*x*=ð‚^¡ K«’Ý£`3ªpõœ¬\îuðmF°°54h©ª¢Tـݙ8³ôf[¬cA4#à"Cg".†@£`•IkMÙÃa‡m§æÔ As”¶ÀJgôºŽÞ'?†0Ý<¨˜×_o¶iye…¥:\©‹º \{‡’FFg§ËRÐ%„Z^þðJ}å‚o¾ûªJË›þÔ¤•$ýŸ«V%è0Åñ ˜MÀô«ˆ‹¨|âŠw„…^N‡ß£“^P¡§ûnÆP±’,v+QÁEª âÊ'7O/¼á–×\ñâ¾LµÙÖÛãöàoɯäí>´^ª[ZÝm%½8CklGßî5Ý!üŸÇ´j!:Vè*£}Sœ9¾ª1S)+‚¯¢rÍ4ë¡~ÈŽõ[¾©?Õ•¨jî¶[®ùòø…|XJ寀ÕP-¢5 D4ŽZä€Q7ÐÒch”ù]ªŽào‚™’tN%’4Ž!Jvcð†à· J¦Ê?¨uÔ̆ŒIÁ4c ~OäI‡R,Ô¤èâ©=FyèB㨮⑚aœ6ÞSµ£?ï–ëÅáxPWêzÓéøîþæþþîááîöîf:›ê„u ?ŽOÈÑÒx}œžhµÊ‘–£Ž²Ü]íQ =Ùj2Ûfõ©ŒÑC•X”1P!¯hlwmÈÄ û$Df–´Y( Që(-UÔš™¹¤U”•Ö#òƒoOƶs\Ùt¬Œj좹Ö(U]Y¡8ÛWí ëì †Š­)P‰ zÔ5+ƒ•jâ;t/ØM9ßÃw RÀ Õñ­V5¡üÅ¥¿'!úÙ÷ ÇlSä”V«N"xƒß¬É ¿áÎdÍ…û——½Ú ×k †Éd8™ê<¦ÛíqSTjBtc".ݯæ¼à‚9´ú.¢¿±AŒ\ÕñÇ€g†R ìžhÕDºÛ¹ù •‚ãñ(—”Y“ÊsÔ¢hÿ”m“ Ô€Üœ å£iÎ`.Ôj⋾ªNÈ-,|¬c2îöúí^ïªÕÑü„šQ¯˜!ÝÉ3Ñì36&”h²Ìå@aö æZÇ yÛ† P¢›ã·àÊ3TÙ¶gY‘5ðRÉ÷,!œ¶P2p¾aˆ¨ZÜm˜%.à;œ5$©À»DA-…áÕú= öÛ¡ÉÊPöÈ` ®y` …×é­jb€~QÄ:TãGqÍ\šÄË@ÊX8 šä„`ÉÁï€ú^F…1¥’”ú-‘Ë…6ëâo¡FŠVJ8è„ðÈeôè­£¿‰a‡J¾ÃF C%¥Ð98\’" þ*\C°|õ_ˬˆ>ÖŠ%1GkDiJB¥”¨HÓ²Šñ”³Üê_aÃÄ·©¯¯_5ßvº­N— ‡±’%©,æµRV +Ÿ •™}ÉB h¦3jÊ£ú"(o`s~‰,¨õXÁýUß4ѦÂUßè%\ Ž–Tg¬Á”šÓE"îŒTRfVeIò[Iµ z½.u¦ïµvzŒ(:WÐ 3(ã‡U!‰®hÍq—ºžóÔ¬w1šŒõœP¡kbpÿyñÝì–)PìNí5¨kÉ›mYV°&î(5ð>ÛÈ¿‰: ”9°RêTLI+• ¦ þ(‹¥†n3Vvæ’$™‘Q\ tÑÜãùK°è,ü\©dÌyÏM„ÊzÏ¿x±¦TO:èäË;mþÁa³Ùm6Çíþ¸U;»®ˆ²°•X5nÈâx bP³¤gé™›vòɃs»/’DPÜçí¢¤6€7óJÖÕ‡¶ÏKËIb™¯ÚI±/ÿÃä µ¦Ê~I¸qÜ÷¶ßl¹io½ç£#ªõ–¯ ¦q TƒQ@ôûüMhÔH>ƒ"Íxr|*&³7¡¦8ý2­€(2dF¾L&‚ñ=pr4Kxr–6:³úeæ¦tXÓm.6‹JVƒRƒÔ"9Ô£¡Ý-™s††C£ß¯åh0úÐë÷Fãñäfrs;»½¿™ÝÎ&ÓÉpÈ­¯ê‹R‚‡ª[¯ž£TühÍTŒ>(  è"9âʃÜýF¿±å ¨/3K é‹Â¤~·¨AÝQY…39BÁo{§ºôV© úÒgì™b5 uäVw›â±¡šõ{¢{É`€{Å`)µÆîÅæ²ÛñíPš«Ûk±Wß¹ñÇìêÑ^¾þï&#;y qöNç¢LlÄ‘Qï0ª*Á]='!‹\·ãq{8lw¼£Îõ]/Ëy™Óyég×W ~n×Ûp2›Ìn'7÷7wï>}üôÓ'ïîïn'þi»ÛÖ„oa–ÇFwŒÆÞUÚØ$(ž³Ö06Lâ@¦ ^úK5‹°:o¯ ².ÖQàfBª]1ï®±ƒ•åx“üÚ7¢8ƒf44QbÊWñŒóDêêü*×j†ü 9ÆÔBFqHT ÈUØêé7Ø„"­–:rò‰™QÕÚBÌm<ë&ŒÍwŸn»….Tu@Ï–ž Lä²(JÏb 4u‹Êf‰†3%f \²e’mnŒ""Z™ˆŠD“yÞ`Ñ€ DR•Ú šá÷ *[f¼·Ü¤±Ää²ä]€}N;n‡Ý^tª ƒ2k°²Ç> Ëp)úgÁ2µ©ê•ðr¸²È+'íôø~¢CÌØ™¡ ±…O¶K)1C‰ ,šl³ñRû£À×¥áºOYZ4hbè!úråqbŒbÇ“· Ú-N¹å xˉŸmÖäžÃ×JF—Ð/½ÉdžªºJBº‘u P(Î:TéªrbÆ!b/±®®„íárœÿl딃 %œ@¥c±÷.U‚’Ïõ «\–‚î gõ!¿Sf½äKÛs®>é¸Z,7ë5ßñä>ÖÜõ´†Ò"YFBJÉóSqXðLu§kžoáõõšd£™ÚÝ––˶\µáÐêކ“‚ZNÇœ†¼¦­8;pöáT 7TÈ¡Ê)>€<{Põ¢UÖ ÙµµtÚrtÐÿQÜÌ·Ù®¼Öèùñéñ«þŸäÁúË œ‰WNú7 e­Ð$ƒh‚hDÈ­m)PJ¸´n¦$h¼d7d5bÌRRôƒBUD†ÅÂU/J~šÍƒ$v‘X$›Ò\r $8óŸYæÊd÷"Ÿ1¡%œ0o£?—DëÌCAñ8K§{Ýí_wÁ¸7â¹x­îdz;ßLt¬~ÀzáU' w'¼ôÖ€œ’Ì4ôúF²‚gÌšïÂEZøQ†4ѹ)~ªJš÷mèîT—é^I.ü^Á¿Ã 54•ÿ.ü—ªÕÕü'€?W>}UÕZdOŒÅسîêlWéš}¸5ªßô{C_—xäÿÀ^Ñ8¿¡Øi»üÁ…šÍèou—ï§kø±3…Àû_íè쵚G^=ªÅJK–V£zj 8[4ªß‹Âç Išù<Öá˜ÃÓ¶8.Å_B%¹ ï\8|š6\¡¸ìw¹±ŽÆuSu3M,V:P“L8=ÖBºÖºáE4tý Õ³«N Z\Ò\O/šù5`2CÆ ”Ð;"Þ{q{»ÅM‘Ào‰w6¡iֲʊïÝÑ6/.ø @µäõ+¾æûç|Z`³U€ïñF ÷Žu!gz5Zã2C9/‘¯ÖëöG}-šƒñ@ÎÙøv2¹› g7ÂÛ‡››‡ÛÛ‡»Ûw ¼™ÞO'â¼™yL}Òº^§|ÕÕ"­spŠA#JQ–‡"¿ÿÝ¥’Jr~Ï¥„ñÆü0•f0#®w[9«rX—›Ýz·[Ùþ,„F /APÝ?|z¸»¿ŸÝLdzñp:ê‡|ÐG=©­Ó/ôJ#»UâL$Î0”¤ziª‰™—–T¾=JÛ¡‚Õ õ}‚g!¨&Jž(}Š)ñ€et> È`þ„4•Ù¬¯¬’í`”=KC(Ó³§º¬­5Dö§E˜z…´âmeØ.íîì`n¸»õUꉲQ¢ ÑCÞt¿„¢vFÍ7¼GûÕS·g﨎ëaj!‰å7xùø|Ó|[½¨A ‘%‚ÕÇ4¾ŽœúUW”ÏÇU®øµ¸L"ÈO\ESqú?¦6]Q1˜–E R‡Åü2ý£C”m]&`¢s{©}/rüÊö|ä¼rŽÝvkÀæt<Ž'ƒ?k©5%²'”šU›èXš¨Ä­ˆÇ¤[°¦WZ%Þf*i%U+@ŠD©':â).Qll]REÑÚ¹pQæ  "F²ÕàÄ&Éu`âÉxdáã=¡¥Šg2ßÅ絕‹7;¾2´ß²¨°Ù¹ÛÛÝal!RBhU!ÇO| TÆ ÇcHýå*wn5g²?Ò¾Ž[ùÅ ¬›Õæ±<³r!×Óé ”h¼³•UÎQøZŽîB ®#¢lÊ+\Ðð;÷/ò;uäÝ÷\–r_Ž„¨é$^ºÅ sÔ2«YO3&þ k6F¤ÑäNQ-\ëïšÐ<ëî£T ;{¼äU»¢[*á0”ͨ#6Pý飪Ät·bI‹†¹¡¡µ"“è‘×ñ+_™—Êt °èHѬ‹«%.£ÒÜæ·pOì) ÃÖýGÃäR±Ô—ÙÕ‘¶ëízµáû|j«èŽtJ¦Êئ¾#MŠ^îBn>•k¼FU`K]5ŒåUÈZ%v.ÙtZrÚF³ñh6ߎ'w“ÙýT¾ÚÝ'ðþçû‡?<<üñÿðIøðËLJ¿ùtÿóÃͧ[áì^>Ül8÷&ÃθÝÓ"ÝÑ‚ý¢e·}ýrÝâÓâ~Azý˜+ãØÛËOö£«£âê‚W~mu’{¶äF7Þ$þô¼xâUÃ+ÈàQÓãv÷zà½nð{öbNƒ¹åˆE¥¿£àN1cšUK‚™‹/86$½]ê¾cŒÈ’j`=5Ý2ž+µ' yM ,>ßÒg)g`(Ñí£§ $\¥Tpm ÜãÅIÿ¦!£‘TÀìÖMàŠüé©T û4ál¦Ä¸³%5¼’V”D¯Ë2e1ïî^ùH®ò¢N÷µÓ»ŒZ³Ûþíýðç?Üýò·?ÿÍÇOøxÿéîæŽH§wS7´{š!T V¦ßvx'’B5tÔˆÚVf& •ÅD;F[Šƒ~¹Îç!ý™U… `aU÷°eô‰êˆè()ä1Ê¢ß$* H9nÂä*X3$tD÷$¡S£T‰p.6—W‹ $ú4®›PäE²†³´s(uL®ìï¨Ë[´ŠM,`G—¤îP*tÛ5 Êœõ 6E£0ñ”•VKAdäŠB½ìyA,Õ`:ddp9òÛNf¾ˆZzF Èl¬Àydþd+œd§É8íiªF˜Á©)nÏÛ¶ä6à5(Ä™è ÞÇÄËpƒñx4º]Ñ¢_Û¦©Â¹2.G%—KMê‡ –ss@´€Ð£ä¬~aUÄþƒ°¡8]½uM«pbØÙI’[E›I (-ƒ5Ql¹ë¨_´b0Öˆ®ÐiÇÌ%åݱÑ)m ñS få“Îdñ–w‡Ó^·x!;+ÓY¢Ü¦ ÍŠX›+3·x±ñ\c¼ÃåÚåhRT‡“Ë¡µNyÕGuúÍí’b¯0F0P,¬žPœ#¥ãÜ( R+›=ÇÃþ…€Í~¿•zÀ¿A¬Rã PŽÃ ä£.pÕ¤[ƒÏ(*~ˆÊ,VE_-éqÁOT¨)™þ˜# tYÊâ™ Œ"tL Nfn0˜ÖD ÚK$u‘§½å;˜\ËY&¦K»ÕÈèì6!ñh2wüHÉ$µZ¬î ú°Fàìe‚×y”Hó @j†dÖB|¬pÚ>Ⱥ§Ýq¿Þm«åóbõÄW­6«Ía+·š,TKù$!ÀZ•¤Þcwé•ÅϨÂh%²ÈjqS/’åuJ×k]kBè·»£nÒÞŒpÚ¦7ŸnnÞg7?ÍnE1ñîç[ð—»»ŸïäÆ}úÛOø8ýĶÜä~6¾Ÿ´øÞŽ7ãö¨wÕÇ{;És’3ftweÆôø KXmwÐ/¦š¾;~â)Ÿý~³Ù®Ö²ÆâñI¸åÉ YC~QA®iÚ†Z#ž¾E¯bl¸%Ü£ ÐâÆHa4påí(yS"ÒR‘ž@ËÉÊ*@n(è—ær84!e˜NwŒ¹Å“Iè#ÑO5Zß(]Ðú÷ÿÏÿ%®Q\Çe÷)lÈ–‘…Úër©’ª£Î(`Áw7÷«"ê€xJ€!ê$»½ØóUK5Ñ?Ì™—TJ ûéøKæ–âÝáþúÚÁ‡n÷ª?h‡íÉÍ`:NfÃÑt8œ &3^2ô[Þªõ Rwàt0®zKÅ€K¿¨kuÀP‹B :EDÇueÝT©°ÁÑB±9ÜCŽÁ%SxN@¶n(%Íï`Ð"DÆH·Yœ&bf@(jFºnÒ-7mÙÒÌkkãTG]ñ˜4-R ‘ÉiFÓBtᕊ:VœçXA†õ²FWÇT°¼ÉÖ$Ô j•pÁÖ¤—°Ä6$S4…RStA„ƒP%BÉH¡}7êÉ%bͦ°ì»— ›ÈgP¨<²k±‘¨Z|¶ûýj½žÏߟžŸ l7›Óq¯ÉûNsñ¸÷ËÏ?}¼×Íd2ît:ѵb¬ºþÑPŒ5 t ·æñ1UgtO-‚ÿ>V `6Á š,ŠUùJ‘Íð»ÑK¨¨g•,ÎÌŸ’› nmèÕ ^0³âšÝ`Še«àu9_½_¾}þºž¯vë½VY­—/ûƒ[LÖÂyõ$ç‘ iv‘LËzçC“ reò‘=Ÿg^O¦#¹8÷·w÷·£Éh4èL–Å] Œ„µÚQ1 A<*‰¤–”áU é «"…JyÙ»Fu…í´]íÖ‡ãî´^¬Ÿ¾>íÖ»_ÿôy¿ÝmÖkÖH¹§û½UªƒÊž]ñ{p¿T=uG/“øZÒ|“X¹·ªÓê zÓÙ¸?êÝ>ÜrUn2ìínÛ¦¡M ÊMÝç Z5M´jpªÂ*\Œ”œxýp<ä qr³9È-øãÿðÇÕ|¹š/:Ã9ÒRäÕŸ2R‚*²-Éšï½^`nâ¶4Vn1*΢¦&Óq2÷‡= ¹ñl*—¨3ì]µãî12æ¶r|ó¾õuT˜M¦W>¿;òîùjþíéñË×çoÏóǧÝÒŸ Àõ”~˜š,(†Îøeƒ±{h³º@ˆ^8½…Ô¾–Ó&³_w¯[½vg苤ãÁ`2`Ëíf,ÝŒ†³áp:ìûýq¯Wp0§ÎWTG}îu_¯_{ª©š¸×i÷»ÚW^w¯þHËidh°È–ÒÑ:HSú#Ë—´²ßaõX €[Éê8<'HUÙcüð¡Óëì¶Û^¿'£·[m‰Š³Óé²bÓÑAÆ@jOëÚj€„‰¨ÍÄ%úH±÷n~¦)‹sÀ]QÕé$ÃŒöÉ©\a~A†U}²[7Ô Péx¥lÉp™,9“–Ω p·£ó¸­cB![ C¦éb[ÇGû·V=<5x³Ïè¨ÑÓ¢(Š€-ЫS¢Pý–9EZuUÈþŽ¥wX_¯[§vûÔé¼ôWãiwvÛ»ûiúðóìþçÙݧÙü}u¸ép0túNLéæ’¦~£)Ž»DÅ4I¹NØÉF¶å0¹B†øÍ¦ Åg~TŒZ‹XÎÂÖa1ƒ’,¾¦ "ó (ª:0ídã ¡yQYbqC©Uãˆq†j$–eT²y²0+Û•(Ùϴ䤶§h×·ªu˜MÉæEÿÂa˯Ù“S&1™ ¡‹h;ÊÆ+” f¡ "`Sƒf޲³Œ‚yþÅ1*[Ei;kžV£¸&f¹ ³PÁF­#É”€¦bÆf´ GTh}uÈ(Ø,”“R·é‘sO|!Œ,!Ô.ã̉G6zxO?÷1¯W:5ÕZ{:¥¦ú;7·Å–o]èé¼%æ*¯?æ…¬]TE¿Ö‚îà†+ݤô}WÈX#¥_\pßûý¼iv·Þvå¢Çˆ0Š CTRÄKÜš¨èݦ·õÙ³`>UL­ÐïôF½ÉÍxz7½ùxs÷éîöãÍÍýlz7ߎF7\¿êOú½I¿;éuÇaoÔéŽÚÂö°Õ¶;£Ž°;îg\ÝN'w3ãt|7ÝL„ýé¸;¶‡ýëN[&’+t ˜NÆP«„eè:Ñ a_ú»*¬d;ê<3¿ç?¹o«õbµY®d¢íz}Üí4 ò*;ñÄR> *“ÚP€K*ÑÆ SÊÔÉ%1µk Dƒ«¯ú!ংSÙs°TÊ5À,@iÕ÷¡ r·y4ûw Õ“ÎRüBß’ ¸ÓÔTg³&DM¸Ë•'™ÔÅ­“¦lÎkÜéØ~mw>tºÂ«n—‡æâiyõH±1Ùöü{°„R©Ë»ð>YTꬣaõ¯qÓUsí*¸DVgÿ.ü éûðn¦(=míJó*5 Ù2V׋ªy®ª%Ç•Ë/YœË4 èo±ÊE€¬ihƒ9ʪRkú÷ñ-Ûÿ$ ¡°lžfoÔ:‰ ÁÚ ª'3Ïœo5ƒqóZsýN3ý†ÿpÕ¹¾ò»–4,83,ÓÈ¡.7 j Z&;Â÷àœÿ¿8^À[Jͤ‹¼ß©QØ¡¶àœ/1‘Ø1•‰†5"ž â¶›äþü0‘bYXØ.¹h;åÕ0ÉÌvÜ"WÒšªÔzæÏº!*kåù`Vc d³-r¼Ìz.÷ ‡Ú^c®y(¡uÝñ‹Ü¸E'ÒšÂ~€4Ã5‰TÀ-[i/~¹Gá³^Þ—ó€WS¯Ö¹f'B @¬E@-D). ïdµÛoö{;m|½Î«¡×4Áw nv‰lT‹>„'!…B+iÙjuºÝn¿;˜ dzÉ—KîÚ¼ËãáÐQ¯7ìu‡Ý8v‡ý‘n§ßm÷ÚÂΠÓ´ÅÌëîg™w0 gãÁt8˜Xΰ×îò©V6’=\èlöÖË( ™ZA„EL”ïýâï.ïå½í×e¢fÀ×ÃIئe» °CTß1&¡Í2.ámw4-Õ¾€H¨CÂÒôŒÃ j¾ Tiªd/…vPBv¡BñÛðì@N~hïDí#dûP.÷ÃyÒ(‰T0).)êVëlІZ*ÔFOMlq_äºöWªÚ|ƒ8>¹È›xЇUÈÈå„XÀTjIÙŒqŒ4™MJX~”l)ðûà:elQ9Á† K‚ [àD$hªK¼).L†ÕªT5Ž ­ÊU¥ä‘ªÿ3”s†Rš:D5a50;ž”ZÉôÞ4ÛÓ‰Q(çæœOS’LÃCÁ.‚¹œË)ð-M§ð§—+:~`èè̈Né¬ÎÂTa+ c$ Mw’¥:vÔúûðnF‘RÏ34“’Ü 0Ið-fs[ž‘ªh¶-×[“fu•mï‚DCP(ÈnE-ŠnjT@Q&1_Po–ßVÞ͹\,›&¶½úvëúºßí ôé´é††ì’ *×½Pe+ûÈòì§\U¨*БlC¥“‹Îs䆪5TL`ÝϪÌU4843 @äÂD ”R‹‹ ¶˜Ëªã>ÜàÚÔÍjT53TAÔ“¼='Åâ]œcý7":óBrV6“„Q–‘8x®ÁÓëU§ÕÖÙ¨Ž\± ÕI‘ÊQ¡Ø±2ºî®²w›Œ¡ÙyÝ&oôøÅ;¾†oàEt{‡òÞN*Ä"d£G˜×†@THŽë8(d]}[U~õAs5ó´7½$¥bþM‹ž›áTb”¯±€$DîÀ¨“@r©YtzÃá¡„]ÔNgíh‹÷¡V CD@JG³i ‚ÞKԱͅ3.Jži(['(¢ƒkMLÅÆÂ$}4x¥âjÁ×6«5_êÜïÕ:¶?ÓÀ±â°Œž/=qÁ. á î¾WR*ñŠ5ž“”åûÁ°?Mnno?~úøðéþæn6™MÆÓÑ`4ìpͪsÝñû³´–¶®|ω›TetuõN%u®ÚZ|{ÝÁh ô»Tg7w7Â[îȼ»½¿¿}¸¿½¿ÝN‡“aoÐçk¥†è‹jšhx yô4[GÓ“ZíŽÇý†ý¶õr½ŠOGxÊ“‰üˆ‰%¨å1S`+gIÙ9pÞ:@²ˆ™@Ä q¤ °•UVFTÕ0—ÉÎeõñ9ÜÃù…ÔÊQˆ´„,4"‚ëH··usQ û|p1A|ÖIIV-2 °ŠXg壧e§3˜nÞ2õ„|¥¸ô”SRY¹Üy8[c6yúä b–¥£‰zGvA%ÖllM'¿ÖÉö¥¹èžKŠîÖS`ªOg•bÐ8OiBÔ'$EçúMpe@ñ£n5)ÈD›H&Ð*X/™gÌDË•Íp³ˆbï-ø›ÌUØSO«JR”%*o¨îE¢¢Dõ}í_M ’_Z’±(À)ç垣›×Zq60AiÁ_Â5¥Æ*Z¥źß$‘»5µm3\¢P"š¨«æVP©íþWÕ[Y0¯ûôÀÈ®C \’^ÑÉr«É i_ó¿D]kâõ+[ÃcÓ¤MoLéqäW*¹&2`@Ø&ô£q¾žN#Š!YÅáA7DBB…P C@À”¤ehÈg•«ÎS5 –*Ò‚"Ìhò¦4GCšªãá­cÅBJ´Ê›àbœì…Þó sLÂ\öa`(§%Yt´â¸AE6+â¤S+7#°Ƈ¡¸F“ˆg¡˜.$/æ{FKðbÑdb ÏîŠ>Ù `¡ö´À^î›z­”ìMÅŠbõµ^ãP–ìÖÙˆú*1+‹žBßt³£'knâi3¿¦U³µÈTÝš">ôuA?ì*-çV+%,f¤ºªÑ”‹dUn¿ç ¶Ý¸ ì…SÍ•4wÅFΟuªh.(À Ìõ‚êFõÉðó£ƒØ£ƒ3š"ýS:Jp c™›ðä7ûrQ®€ÑòŹ0ùŒA `a§bg‹nĽ’pg!ÓB_NÚt4½MgÓÑxÌû¸}¾ˆÀ{tñ;+Å1¢¥Ðií ßý~§?À{ó£3#Þï-œMyFp:OÆÃñ¨×çí÷Ò‡Nèþ-,÷ç0·@)`[E ÁMsÖÁ{[s}a³– ž&¢w{Tý9E@ñ7¶röX=Óº™¨šábÌ£3Y»$”>`¢R£Õ…ÉèN˜rÏèEN6; j¦L NS\‡1"_u%D)0ëíüލˆu˜Ñ ÈFTÏ"ì•6s 0¡!GI Dbæ7„½JöZ€ÀYÕŠ¥6ŽE¥Ø¬.Nš˜ i¦ÒêN ×¹PúrS©QÖ ¨•MõÈOß!ð;Etˆ\H¤ÌŠ˜ˆ !Ž^HÈhÅ<M¢½O¬ý#ÈÌÑ. Q³Ð†ÑdÁy°zµ9v;»m64éK‚æÝ~¯§¹XÀ‹é5{ ê.Obiî•J†`,mgýCŸ ÑŸ@Ô®b¨¢Páf´ Iß‹^eYç( ë±JrEªnãBhŠ"HȲ”VÉo,ˆ³Ž…Ÿý5ߟJ¼K-`ƒ³lG N©’è&TK‡ßD­4^yc E/2Ü<ÆÜâ—¤¥QòáQ8XUŵ ä 5˜)Úc©ÔAÀ9ÀŽËîûíNG°(Ú …iÒ§WÀQËÍbLp­ÓͰCãû¸ÙöáU4,øø8¨‹>à%¸.þ•P!åYE±0¹h .ˆ*”¨6:x7Ñß´`[4¸Ý%j¨¤Æ¥¹æ A”FB¨Ÿ€wíúv{ÚØÉ*]@tý;M½ÈÚ©¸³Ícy·Å%ÙpÞ8¹$ý£fm€“>HÒÑ3-N„‹‘«¤èL:—ë¶u"§™A>–¼«ÉlŠ_Å'ðxÓŒ\+·NήE–ê»5]¹ †¢qñÅyk]·Ï´ÓOäÀMåÞÜè6Uh·Ï èø™^0#;³)å‚•e0¹¯¾Ðo¶ÛlV›µoTT z:h@Ú 1 aÙHŒJ"TÅ«dжœ*Ñ“Ÿ¥AG—„º)=©TXSœJ–*»K`6ÙoîÑ>ü”ÅûÚ¹ºŽ KrG?WHýLbÀÈo¡% 2ïg‘K¸ VL&¢_d€âaÀNiQB¤,—R••àÕRB-9rUü5Zzd h¤’X/mpçäO/1ÅÔSJ«g¥Þƒ¨CÑRbáÌäß ÈFBST ”s¼ó ›Õ3Cè]‡Ì.v‰ †7á¨pAUݦ‰ v5Ý]I‡:;[ü±TêȾZxbD¥j3xÁSa)4¯]¤kåÀ&ýœÈ¡”™?a«›³Q*† a§¸¥²EŒV»Â†B—èNUéJ8ÎÕ8O÷Z†üâ6 oµ+­ÓÖIp4âZœ¯I1¨Šmë"„êÜúË5îRb$ý.–º8Oú+ v Ó%ëUõØBq]ÔYJ5=k—©¢À„4§ dŽª±H“ÉÔ˹Ì« áùÃù˜‚ðs´`*K ß@Æ@­xuŽ£<*§Múªe¸ )ÔŠÌe†ðçüŒš÷çÌ_aöš“J8鲆*¡®´7piÿæÈ÷5_q«D uµ œ~;B=ü¯‚…&"_›€ #áÙèÏàʟŤ9l¶ \@ÐADYã°V2™h`%ÁÕ‰£êIJ¼rŽ'-޼–zSüQo% ¬¦­â"jˆ »šµM#àÑ©Ÿ ¶y/ƒM`& ‹~5Dݬ*OMr•Tç_8n:Óp–;bç²(A³Æ10@&ñrÍ(Æ<òÇÕ;xN"úŽæb¿l™M'¾z×ô£áp<5GÈi”OŽòÊ4§s!9‹ ß»‚¨Ÿ4pç?Ò"xŒLù0OÛÃá×m6‘ÓÆ–Þd4Š‚(Å{ÿ–ÃJÿ/¾Y$Š!IãàˆñdÙÊ•œoÎ+¸p³å³Wœcp5?Ç=c¾ÅرætR¹QB¡9laë€rYaˆÐ¬š¡QZ±Ï¢M¬²³œ(;À‚éé ¿ :ש@L!\ÿ¹;N70VåÅÎff3Í¥¥ºi_®$A!Q–(†"3!Â2Se)VÐÈH n£ tsºD$9Ù æ)Â)=˜Q °8 ŠFçx‹žr¨ "UC~ By æ)Ù^Ž" ÖŸѺ˜%*ó¸®NõܦŒ,F…YG„?/2–›¿, :QjH£9¢âÑ\dÔ „h 7e°"F^™]‰.ÌÅ*®ÍqÝ6 õÜöî]–{Žð¨å\šUÕ#iˤ@gd/Òm“‰ÀÿôIDAT¢ƒ"¼((ÊáXáÛhPØZ‰Í¨Üûˆ>ç,2§þm–+aP‡ôlÏ?_YÚäMh`kÞÖôØïvuÍ‹š:ñºÍè 3ÚàØ<„RºÑMœSjŽÆqeuIªRšöi`©` Šýn4•*”¼“Zt>ç!šµË¶‹Êfv¡ ô.BH¥Ñ±k ¦@ˆ‰eµFߨ ¿]­À%7gðC|±`³Å™mºJd¬€OÞ+ z¸ÐZÇx])Q¾òè—Œhv²¾!T–ˆrYµ&¨bY¤ŽŒKueÔ•T ï¸Ù©9,Êžñl¯³5-ee0Qs”Áñdaýĵñ"‰Óæ7?]™=œ©m{^‚)1DƒAÚÉöùÔkÓ4À­kÔÂu Põ ?èõ½®|µžœ¬Ž=N¿_"Ôv/¬‡Y(`ã—Òev„Wæ£_Êc®£³Å~§§3Ç‘·ýòårÇ7ÏUî’j‘xÌ6&ÆÍ F/PyØêpÔi…\pßÜÆým‡Ã‹¿,Çæq²"œ?€‚Lpbóô–¥QiÆ8Ý•j’÷ñX cåGåêøcT÷U³ˆ³ÂŒb•– @CÓ7Ðú‡ÿô¯­;)Hýh ÿ:nb_…õ£xt2º\öÆ»»—cðû׺d0‰]0WšR¬A¿ŽY“øQ•Í¥6ÁY¡‘$‹”óB1#ˆî`Éø"{hBÈâ­õP†k©Jº †‰iäJ0ÕÚ€ž$ȉ>„¡ÔÔUÆô¶R޼æ4sUÇf à"z¨þPF§¢d’Þ±ÀU¤ùW“F¥H ‡YœN4ÑâE¨X›…z–jJOs†w]ÿÄø£tØ¢ ä§×(Nªñ$Å£6ÐbF š7“ÞÔÖðNŠªŠvÂx¡òü,UZQÏQ7ÔÄÅ“U›Ýb±|zžýòõË—¯Oß¾}SÏ’>š)of“›ÙèãGíg7:Ûíw4cÚJ•.¡¸šE‡˜IMËSí8¸ua(F º1ż b8K&RùÛˆŠ»mRa+@ Baü¬ s”´4Cí Rfˆ“smîÂ3ÙS,µÕQ$±©ŸdЪ¡ÑÌòÊNÏÏÇãëã×Çíj«åd½\{£C~˜µaÈ«‹UÊ‹ˆÔPÎqÑïòôß[­ë×~¿¯üZX•¨ÁÓíõŽÇ#³“¡P2ôg}áå§×Ê+Ö¬Ÿ÷3 eM(ÐË [†[^öòôõq9_ÍŸæªË~»}z|”'¡™ËPâí“’¡0Åy89ÔgÉÓê!OF>MØ'Ãx)úx:Ñ®ÔÔõ™+\¥*&ˆTO§úÇ õtJɧ1ì¥9•(Ïcw›Ýn}X.Ö_ý¶_¾~þºYo{®¯©Ù%Rÿª‹j%­©…êÊ)!êãbb.%“Þ+ …/wõ:£ñH~ÉÍŽG×íÖ>nA ò¶¼TÐð½A–4—sy8íóÙ¢•,?|úüë—å|¾]oåš°ƒ.ŸõdpªŸF¤é¸É•NF¯UŸ“Vti¯éÅ'ôs\þÙôv:½ïîúƒn8tqõ0”(!zE¬\”Cë»âîJ"Ò(ÛQBv ¨•êEªÂîø³ÒDç7Ê«¶ÀÓS~u*I#Z׈"ÜeÝ•©®;ƒ‡‘ÐÓ:H)%]Ãa8IOu9u:Ä^_¡8†!»;‡B4±…9¿Ë$J„L)tq›…¼ºªh­Ô0Hu…²C*j‘–õ¨Ä÷R™Œ@Ò „|”tíS:ïÀ§*ìHXCÂ$¢º$8½h ׺ÄLä¾~8Å@ é ºVt]Dt´RÐ[ saHš-8}  œëmô²š’ó·X ÐHüÑòäͺ…Lc£DÆVõ½°N#ÍUÿZèj%s~¹û°ñ-¨Ò²ÓlÌÝE‡Ð­††Žôë e±; ã<½‰ñŽÑ“XÂý-^p6£A ^yŸ§5qщxÂTÕt¡´±z\¢ûÄ´O±iS¬3ÛVYª¢UñhÃèYU¤txª‚Ì/J%ß(Âî2¡}ÈÇ®–D´ÖÄß‘4¦äUN“”Nö±ÜÉB°¦Ë@’ÀZy[+^‚ŠDÛ’×!Š‹RtdàÄsE<4 tP›9»s…à<`~ÍeÊÆöjŽ\!ìP‚?jK¢57=$PœLˆ,™1B'™àĨØê™¢V@ÖÀVïh•à.ȹWDá L®èB D‚!’ä&d¹æ¤z)\-à´n,÷°e™Ð”5“²ÿ”à5OèÔä^xÀ–ºÅQ€XKãÉéMM¨êòJöHràò†äzÌš½J%â@J®ˆD]\E¯ï£fYÏŒ©É"«iŠåWlÙÃÖ€ C VõÍåûýq³ÙmÖÛǧùÓóó7àq±X 5Uj’œL†77“››ÑÃÃl2éO'#Nžå™ÄÐh¸0¨àÁG-q½¤†>:*ÁY©EQ›ƒ)!2þÓ,‘œ¨dŽP¨Â­"FÚ¥Š!ŠhT@PÝ©5šœ+ªg»e4”Èk9’Ò¢¾ÔÝÑ (7Øn¹z¿=x¿í8\hÍ|z|Ú®Ö‡ía½\«a9»SoõI ÂP!+íX‚H ÔTÌ/ ¤9òÚ¤ÖñÝ~/yëÕFk øS´ÛífÏU5>™Ák<„Èã°õÓWøRTûTó–—?n‡_¯7‡ÝééËãòyµx^<}{ÚowËŜ͟wÈr¹È*JVÕ†*Üs°0— ©§/.A¹þÀw0;m>ŽÄÇ”xذëû«®Û\*e…õ\Ëõ? mõL‰Y9oÀ¼jè¿ù©×M>“¯íbÛýf¹ùúë×ýúðíË7nfçiͽÛH‹<ÝArø’6ÕS7Ê¥‡!cY^Y¼¸ˆÆ1\;{$½~—ÏÉ û¼ðbÄ{TÁV·ó/H Wb‘Îèóœ¢îì <‡°ZoØo{Z>/¿}[«/ÉSßûd4 FF5Ç4Å’¤ q\Çv;•„‹ßj_&ƒn¯{{w;MÆžHà².ïRv¬–vÎÅÊ?±7æÆif/h ©`uWý‰+E½ÔÇÂú\/µ¶n(® Žìzè<„u×­MI>íµ•m{{ˆQª|nTÛ÷sRaÙ^кG0ù„òÅwÝn!‡¹Õ6ö>`èï*‰ !=Ž«0k§l*ºîª6Qó pPÎm£¤ D怈VGƒ‘” "o„5œ#|­ÿ*Aÿ‰š²bÖºIT…Ü`—X4¨¡Ì{ t1d·j‰AO¤kºUÜvŒPY¢—KÆ@Z ±¡^pF¹ôÛ¢)ºÐY¬lC¦!:RU€s™ÂŸIÍTÓBààÂè¶±¥œƒ«ä,>ëi,f*íW'Eµ•©Ú$ô.—û''&[NìU®ï`n´41ÌŠ‚ôWº,Úª%m}æ,L6§¦/ÏÁ]ñ5DR\Y¢áCTX•^S˜¾ôRQÜ!’¢pl›!ߥ\pfÑ%\e4fÔ<‘7‰ç¹À’¥¢ÀÆ”ÒÈUaUNõ¶3ªz¢83Û"|Üjǧ_xüŒ{a´Z³Ar’}íF3²Osî"ŽF eÜÝJúgf$šKRT(SP©Íð&]u´Î‰2CeR£&gFMáhÕôá³h=ðÔ#,9Œ vB+žÈ[E EP,”3báKF\ƒÇC®BC–ÑÛ¢Ç'WdôvSŠ*,RVKyѡ֔;¥å|µXÍŸçÏOOÏßžž¾= Os-íËùr½·ëõn½ÞoøÒ6÷kãÓ\d‡]¦œW¬2º¢>³ DR¢HïîÙ÷#݉ Ð&V‘®b=±:ª9Æ»†®S ¸6¦)•–U¸Y^gïÖÃSË·ýl’Pçð@¨Q gvLæõZb.jRºŸT(Ó‘‹îqS<]ïJ¢™ŒKëeÒŒì”Õ#Ë*HÉhK¥%áüùûWêíîö:³Q%}AÌ}œ\n~W ‰Š¹²Ž"_aÉ2¥‚0Ú¨:9\Üx.º`¨è02”IŠÚq ¬(ٛу3óP£@ëþã¿¶Ñ Èø"'‡bþ5D°¤f9Š8×ÏóÄ “þã,“óBU@ì0ã¤+*¢yPÀH@“ˆRÜý(ÆC3êV˜‘‰ŒTÂè€Ù«Œqä¹£æI7 Í£,\VÎJæ1—A9E`ˆr7!’D<Ê Qº¨u â:Ä/G¦n%×eœApJÉc0 ¢kXG…ü: bÕOëT‡¢žär€öŒ ú#lz ]¨ ùC+jR„ £2éB¶ì$ Éœ'Ù΋¨×A'e^S25(’éÞ‡LJ¹*´””òƒè°£I3g#t’ å"5“Ì–G¢Ô¼ªW|‘—U¦ä|8_§ÖÞ5z½bR=ž4µëä|³Ù>=>/‹Ç§§ùóóvÃ;E™ûÝétt{3™ÝŒooG£ao4ì÷ú=ÍÓ^Èü¹˜:ˆÛ™1¬’:aøCF6ںŃ"嬑þlõИÔàÁ\®‹ÞCˆdl«¢™±°9§d:ŠlÏH²> «¼ŠAˆÔ*{ŠäH)ކÖaóf¸Bl£€«Ö¤G^0 —S¤ Ú[Ç—ß•WžŸž·kyKÜßFKì಑OK$rP‡ÿv®£¥ÆíÏ ÅÕÎàã†4­"JÖš wCußn÷j-ï´á±Ë±“Ÿ¥¦_m»Ýè_‹Ø‰pu¢²x®Ò5ºrEòdÀçý6älO_WóÕzÎg1µnV+õ6Ù„¡ +ðD’£ÙC?¦m*£€{¬B¹.~‰`«ÛŽù„ü`<O&Ý~·Ç‡ZîÕWÞ”ŠiŠPpTŠ*ê6A1JÀL b«L¦º9‡)/¯_8ãíµUgóíóãQÕ||’{´oêùÛDñ0¯[Ê)»_ÔP7$vÚÜ ÙMlÉ éx¿­ÏWó'¼MÃmØ¿bC±t©@ ‰ºà¸ûÄÑþÇÁúR^øúéëãf½^=/ø–?÷¤ÙÑ£,4è‚:±v‘‹ Ña‘å‰4é,·IMÐévf³©4”ïÖïõ°4çÉhA8Œè_¤%eYõlXÚ˜7°…ñƒ8äqÂX`Oñ5£ë¸ó#SœHÈsÞÔcÝ´ø:Ù^T@õ£¢.æR]Ñ+u%XÁAn·ETu¤ˆ:•j'±Ûï+‹Œc9]6¤!Îz¹ÈT2*šRó×WyºTÚ³Ñ%¢§†”°AQiè¨Ð#<³ƒÁf!nÙÌBL)Á¬!@D²6ˆ­øÿ €Ï@²ÿuD¨) ©G;Ý%¡¬Fsaö B Æv8“‰öXÛ„}h‹È>j6õæv;…&dP;§UÉM×M~w8uÀS“ëé¨ëœý[”hN8ôCoð¤óÿ§îÏ–l[–ô<,3gßd³š½÷9bˆ% Fš(H0BFÈDˆº‘I”ÝèVfº‘™@7z=ˆÞ†h@¡P§ÙÍj²mfêÿþßcÌ1såÚgW¡`<#cDxxx¸{t>ÚyPÓ‹ˆ¬ÿ("p½aåGîÁY3O]s â.a´¨Î*y%T¦ê>É;ÙFg )hG±J&pœUÚ÷P3¤JƒÒË@¯ÔX(ÈZI·Z4(Ù~°½:n$Zï_Gõ"-r’ì±®BЬøQ-÷ÇaIªˆ:4ÊJ»3ÉR‡9â™bŒ‘N$ß+‚­zõƒEV!â½X+Ozó ÁnŒýbï2ƒîøfèNþÙÍÍíýýê‡ïøüùó§OŸn¯ouš¾Ûîf³éb9{suõîÝÕÛ·WW‹ùl<ŸMt²{6àŽ=hmÅOÓGüµÃcí¦³ë> ‘ªäwŒ…lZg™m!¶R¢ŒUª¹A%[ ¥HY"ó4OªÑ]i¨„÷ý&µ‘Ÿe ÝYì÷0¾Ï§£ÓÁ‡aÒRL4)m£¼£¯Ù¢©ËCÍž÷ÚäßžÜÝÞIéëOòÛÖê‚ûÛÉ´ßff€Œ' ©Üfl Z\Pȶ¨±¢¦¼fñÐŽzìþA°’ovs}»º___ß|þ|­®ÿøéÓÝݾK~ãër×w÷7|_vk×Dlžðü¤ šÖPÖk!kWv´‰n¶Ra³Ú}üñÃýõÝÝõÝíçë½¼¿ü6 há%ŸHY‚±ØIOyr )ÚÒ–û(/-Êi˜Ÿ+,Ëñd"Gçtˆ=2¼Y±:¶ñ°CTòR_³ ñŽl.…ê6”S¹-/ÄvÃGY屩käýôý‡íÃöæÓµ¼[ß¹ëùm–×»€D‡3­°Wñt˜Šùæ,žË€ËW£Él|qy1Ïä·Í5ÙæSyòÛĽ÷8˜ú–‘Šõ%£t¦'¸s¸Ûluö%_Y³ø§~zà÷7o÷9:Œ>¹·lLÖë‰ .Â:©nV‰H”ƒXz|É*\ôâJÛ`±X ‡gŠÇ~?Iî©|([V¢0™”{²5¡3;±‰ƒí³BJµa#‹æÒ\ ˜ì¬6‡¾jBÑÁZÂÖ:·é:›Y&æj-±vÆFö9ôŠøm¾U#é/·Jd:SU›~~Ž/9OfShÀÂYíÊÌnEùHÐz¦»U–1 ƒlŒ6‘Ð4RaQÔV ”¤Qªš´KŠ1ii k¢4ο³p‹ilèOÓ–ZfF³ûšžÇ~,ªü1TsèÈR¥ ¯BáÝÄ’ ¦Kw!ðÓ%zÐÙâ!k¡/é#òHý’¤AWÚG±9´ö:t¥Þµ =<ðR£ÐVðŒ©4½ÿÕ,\=®r‡´K¹2­¢~Å^©EA3;ˉ‹œ€O?¤Ê«áeÜthp¨VáE¦Œã#ükêÖ„lqRÒ”=¨Š¿ @Ù$yQ$|×.Ì;bEê¬Ú#xªJ4‰æî–*ö¢§Õ†~pÂYÈ—lÛàu{¶bc,dK‘v¶ðÀaÔªD––®”¡Ëý’ЗáÈ\6lÁ`ÒŽ …Ë£¼@vâÿÙ"}T$‚ªr áa(ãèð¥Å ëUéqÍVœÄgªyÏ{z’¡Mv»ßm¸Ið›’›ýnÍ7TäGÚy°ÝÏákµ÷;TÞûŠ3pœ#ª¥eÄø^E6H¥>I¥c•¦hh¾fô£¢öáÕ:‚¢t3ZÞ:Æg•v_ãÐ œþÕkÆq]Ëã”WVb†vÝ€oì§ðGÀMæK™ šïeZEcjÔ·åqñ³ŠŠF®é°ùmƒçÓá³=ø°:q96©?ªzÕW3v‰Œj25ÄëpÌ8<Ä2¢,V›X‘³T 2é¸îË¢—„•í—Êy€J±eiI»zâÁPµ^€0©ÞQª›þßÿŸÿ'7ä}?^1Uk¥×±¿^Hï£Ñ¨+R¢».ežpeB„Î3ÉâÊâ.v4JPÐc¥8 !Uªó¥#aG#WÔ<`"2…ƒà€±D–àrÈ]Š÷šsDCj¨ECíV½ˆÓœAõp´«…Fúz’)©¬ïay réß-&D*ARF|†CM ÀuWÐ)«,;oããB¸Ð²ÎñÝ'_BGÿ%tEã%ì ]V±è83u,¥1•µM 8Qk³:Ìš£,úp ¦q¨cè´ÁšdßÐÀË΂7` ª›¨ŠŒcêWìQAaÒ·má1“%z(J£)&Ak¬ ÇÇG®AxŒpžlbÏ`VJsd ½ïA¡ ¯ ê×Wö{Yït½Ú­Vë››»~øéîöáÏþìÏ>}úüáÇϟ?s¹m»}óæêòêü׿úö¯ÿæWß~ûæý»óår|u¹\,g¼™>§2'½Ûéf³Õ–ÆãCæ¼&$W𗘤 p±ËüÆÐW¶ErŠcU§¨æò ŠÒá¤8™Ž!ó¨2ЛÕ\Ö42 1§ßÞåO” ìæg³ãóQÀ¢®ÕºPŒTV-›ˆ Ntu¬)'g÷›Çí£úbý°Ý­Ÿ~ûg¿=Ù=ÿ‹ÿî_|øáãÃõÿÿ~ðt²ç>×ó™ŸâòK£ð}âÊ„ºÀW8Ô ^Ÿ¢²wI‹¤0Ü/=}MNφ<Š,¢³á`>_¨ë&³ÅÙ`ˆc>>Ÿ);åv$_yà>¸ôœÎGß|÷í‚_„œÌúŸœ_ðúÙp$½éWƒÄ$ÿPçzµýôñz÷ðô»?ýíõ××?~þðÃOûõööó§§Ý^KÞPƒË!³L†‹‹Åô|þþÛwoÞ_^¾¿zûÍ»ÅOî'#ñ¸|H´gmõD:ÅÕ»¾fÑu¹¡Úí²–nãw•‹Gª<ÜÝï7O7Ÿo¸ùûáæ_ýóµ¿ÝýøÛïW«ÇÝöi·c ¹Mš“>2³¬úÌ5Snç  Ú–H§üDÔ¯{œ'%#±'µ\jú_Ýà°å;dë?~øð‡Ÿ>ÿôñ_ýó¹[mV×÷²?ÕþIƒ‡–$vB¯}®·!WÝÄn½Ûг­µÊžhw0Ž'<ÒvõîŠû¤ïÞòë³Ùb¹Wõ¿cÁ;ž~:o¤‘ÅGq1§·5 kƒ‚³zË愈¿ºþy§µ‚Á¬.—‚¢JÎífË;®ô}|Øî%åÃúöóõOøáûõ©¹yØøg9øÖ  (òM^ÎVx1ÖíKWO<ɨlž×•Ì\µ .ß]Ž'“«÷ï.ß¿Ÿ/Þ~÷^säl2RªqYZva€ ‚‡‰ÍA=î¼­º%3gœÕœRC:kËj,Ð Ù`…fMa â ˆ“(¢ žOµ€çcÐ{¿‚àÞ´µÝé;U§ÛÒ 4 ”Ió¥ÉIüà*]UM„ï1;¤…ÏtâB1S!YĤŒcÈ5VKÆVHI(;HQe´A¡x=Y~Ìþ†Fà†ªÝBj¹( 8O¸¨d% 6ÅÍü’~GXè˜ÔOø£Ù_}âÒEªÙö R².kù14ÜèÒæ5È–4›¦,!G@=zÓ;€µƒÔ± F­+À-7Œ§m„6‘Õ_ÊŠªÌ8È!ŒFw!MÀ)qX¥¼Ië‹Ye5QPÃ—Öø‰V~Õ7Èy¿¶a¹p»—/ÖŸ‹|Ú*îþeÀôƒÄ0Hl‹‘œMý”uI^=àY#SqùޏÏš–¾>Ò”¹\ÝBOt£A±³ŒØ ±†‡®gZ´cP}[ÐY! } bDhebè´þ_%X0ƒ(꽄*ëZ¹>,dA#?ƒüú­:VTm3)Œ-[ „K”‡ji¼ð;‹`”º šq‰ºÓ‡´£&Õ%Ðö‰ˆ ”dUþ¯´ðŒJö²ªN}oLJ ÕšpÎlݰ&­Æuœ¸„U5TT•6Ó‚dSêAVЕBùÐÁÁèJ‰Fãô+æ’>±è0%’+ÒÍE @¥^ ²ü D-\«y /z?Yê´ª`8¶g;ÅZs@d;P¤B‡1kÔz„RD¨ ÂÛ[5­ ‰Dü«–wâ8pò‚n ”–$ò  XçÚ&ôâœ~'h€ÀóÕ¥Ð+O‘rÔ3:áí:Ö ŽVT:¸Tɨ´r+A ŠFÒW1‚¹œÃW KÅÛ¢'›õvµÚ>sâÈ©ª˜‹Æ~]¦Nš`¶qÁƒŽŒ$˜8Â',³™:Sb+Jl:/GÊ <úÀ)h”š¾fQK§§KM.Å)%BBT€y4q{ÿª‚œ:BŸ1º  Ly¼„UãͶçàöÜ"ùÓÍFþóïù**qmnoow[ÞWX=¬µ9É€Õ>¨"WÄ“Ÿ²y)ÐÝùsïDZ=á‰)Š(h`ÄÓe¼L°—Kæý—÷ˆû.)¿NËG®åk§ '³ÉÙh0áé©ei¸žªƯ“õîöæNîà'¿—°º{XÝ?h×ßm6"¨VÅ*Ȧ=˜U#(kï.bv†¿ÉÒÞHà‚Ðp0åùJ>´»¼XÌÏóÅÂ?R9=Ý퉡ÇbŽxN}ŒTÊ(råšOt›ûŒðt²UOí­Qžoûi{¿^?¬ÝÏòæÂY5#‹+WÆäh¥X)zŸ6}åû¹»NO†“‘?k2½xs5[Ì——| dä_ùU &\KQ«<¼Äèf-áFö¿½»¾•œ7Ÿ>s=mSßÚU{nq¢¦ê9%œÒŠ­+yÇÀò–Í::ÐL]xf¿ç}~Ïx}w{÷pÿ €¯ÏOFñ¿^o·~ÍEƒY#L^šF[»læ÷lXi‘éëleÒŠ÷iV*/Œw`ù‚òMån¶kÎ1±‡×{ý|9PÝÚÍR4B)"–-{sÐ1‰øfÞx29 &ü"þDãM ´fâи'Y1QÂÑGƒåï ¶‰M ªìØžõf¥ ônFá1c’ªB¬ÿ¶ab1õîdìˆ)1 þËÿã?@O>E³äŒZÖjÄ–âÖáÞ«¬AˆŠ3Ô;ð¬}C€}¨hÑøCÏ" Í$Š©3Y/òæð1K¯¨ºÏR+ó³OÛ4G–ÿ¦q‰K¦†hJ ¥Vø@šŠF!­ŠR#•OZqµg¥ø#uÄcµÎK’¨uñ"êbFyιšÂű ÉºÂ Ú !«R } ÐРMÆ.ãˆ.U2]ÅÈ"ñ$ ’ÑM€ÔD2œµØ ŠÑQ Š3W‡ª0bKo1§«.íÁAö M¤,§Üác¢23¦2|Àjqa‘® Ѩž"²€GjU!Œ¡„L¾» Ò^h®ø¤”(‹{Àºy¡y¤˜Jˆ‰·¯„ÛA(N˜¹O*;ž¬xit+Ï€«ßÝÿý÷÷÷yÈZ&Ô yûöêÝû7Š//–Ëåìâr9_ÌõM£g1#™A-‰Ò„ì.°déK÷š´·œÄg(JTÅTDrªÃÖl’vÊÊ“h±‘a‡EÁÕ!w%«@çã¬@ü„¡YÙ*nNBÇ\˜ °RHª.ðí)Ä  ±É¤OÕâ¥öO.F‰D&E}<`TçùDߣ¿óIØ?i+Ò¨½¿»÷çàŸÕ;Ú·U`3XìÉœ•.¬m¶þ`›ƒªÈoKM¦ãér®Í¬ü6ïzQBŠâ·ÉïÜi+ÝÝ\ßnîñÛnïý³ÍjmØf£u_²Èr=II8¾í0Ì}1ÉìñCä‰, ü6ÒþrÛœö¯.Î/—‹ó¥²ãÉX[®‡=æð‡tiRE#Æé’IßÊòÁ—.ë‘Z”ðjSô_ÝR{”@×1@O[ð¢£e1·XÊ`ïáš&?4; ¤øª¸#è ”jÆ ÕDÑøï¼ŸÈÛA×\ØTæ`Ã7‚$^ˆZMvPhCר¸Hòƒ½AÔÁð¢‰#ÉçaJµ.ùsÕ§=œÐué!Ër–Q`y¨N Šyפññ„8²–¼X9ÛB¯S,—ç–¡ã“܉áPT)¦ »‰KPâPTe DF_øڙÚóôfLð‘–GZUMËÔâ©§³“‘vöNïÑ«,Ãe¯¬°¶™Z(M;LÉàáÇù Òˆ‡.N‡ƒSxwˆ–î·žÄ*L:Ëçòn%útUÒâ!Û×ÅÆ±À‘Í‚¤:è0 i«*c¥¯áÔ´;¤ ÖØ åI+ì€Í_XîÏñ•ììôéì„ßœ’üÚld"@8¡øšu#ö;{æ°­ ìÁü¤6÷§~(\ù\ûòôpå€2›êš3é¤ÌÔAÿùÌ\ lKÄ‚»ŽA+ކ£ö¡?u•ÊváMÀÜ; ŽëW&‰p¬äK8ô2O’{Hy¹Ìt²1–f´ò3L  @Âðï  ŸºŸãàw°å~û'>ù„ wEyÓe½óo}n7 yðÛûÍîŽXiyºÛ»Íî°WX9ð¼?àñ¸Ñ‰ ·V»ŸÐE~Mß\œ;kÂFHž$‘¸Š7ÕUÃvàÿ zë×!´þÈ\0O×ø tm†ÖMY„2‰~öß”,°ÖG˜/!ðÿèÿ÷#/GjË­H­‡ £•WÃÁ4”Hƒ‰\,”³ ;ÐÂÂÜÇàI `p»UÑPD’¼y5|%¡„Ñ¿°Þ¼Í ˆ_™Æ\”­"¼æ¡Tëõ‚vE_ÖÍi¬![eº*†°Ü:Ƶ²aÄ’Œ8ÚéÚŠ‰«\°7¸¤Àu-_\»’n«õS Cš (M6އhM0 RÛð¹R©Qšô2aÕÅ$rØž*IVQE™Aù´îÒ´¥$Á­’ µã()R_àê­¨zS0Óuò¨h †U@†ˆB8SÑU3¢ à;*b³j8 •òHç`¶ª‡(Uj6ëŸ Ç8J–Ù„o¢ôó—XX›ˆ÷û'îŽÞ¯înï~úéãÍÍÍï÷ûû»»Íz­q:œŽÇÃwïÞ|óþÝû÷Woß^^^]Lçßµñ¥ŸÆUÛ›næÈ€cìäìdFWäF6eC#HÖ`­ø·þËT.—¸KlêJÙm —4ü#D¢¤)%!²HÆ`µX!R–&‰S–™1z/ó<ˆ)<Å®š4 ì^ÉÒ(¡Yâ5…‰<Œ4^u²¿Ýî4òdãÝv;OvÛêhÙØî¶ª8ñsãQQ­df©aܽ±±²X±ÐäùÑ$—{,®š–ÃÁ#c>åN¯IŸ«gÝÅ'|ýu8:¿\ÎóÅùryq>Æ“©/N@IcO\¾}Ü=oý ºízwws·[ín>~^Ý=ðµ³õ–ë3|ÊDƳÎjI5H˜ %, Œ°Z,¸û'‰ðVå+žžŽƒñh4Ï/– Iñöryu>¿XÌÚ}RÉ q3:-è঒c °~¦ðѦ#‹í|t ¹ÌÈ¢…ø%­e»ýýíJNÉÝõ-÷o®?~ÞûË ˆëm‎êd¦’…AäKeoR×zMÇgc;î'§œ#¶ ‰…Dj¡%-Ýçw¿~XoVë›O×7ŸnV·7¯¹4ÅÇÿÔÇ]ó‰;ð4ðpα­®>p™O‚&€Î×ìµQ!ÆnÏË›ÍjÅ-ã•×~kåæöæšÛµ|çùÚÿŸßÜ_ß’àƒÏ77×÷w÷:<<ÈÅÛrínÃÓ–\{ö`wEéµHàÅfNÇžåÝm·ë‡ÕÃíÄ›LáÏhœLô$Ÿ~AúR]ZJ#¡3ƒ’NƒÑH–jíqw:Ÿé¬@H xì¤s'‘ÕHɨQæÉÝŠ w["]%"gÝ›ýD¤.B¿ˆÜK ‚´ÖÀŒqŶ„„­‹{þ{ìR€Á82ºŒøBÒjš?¤û¸]­^Ý£´àËl)Coµ´A ‰L“Y(°N%ŸÒ.tl”íã¿„”†Þ&¾ LýJtU^‡/ ~¾Š¥õÈþK…ÞÇDý!E8Êüt û5‚ü£ÐU|•XxŠÁGÌ ¸ÊÏõ×1ürÊWà+²Õ€é•ö[y©Se4¦om(+û„5'_>»¥‡êºpˆŽAõ¥âè®t;€ê’·c®##“ÄÅŽƒV‚®4’Ä…pIûÔØ5¬‚iÓ¨6 Ö0Cã@0ÐX¯¹ŽÉ/s¸¹°? ÀǼ) TôAMŸ^Ó^kÓrGˆ+ÁÈ’§+Ì 1rì¡hœ&¥XÁŒP'úqo(•al¢v{Ð$8êXH7&&¦žþUì¥ÉY0 ZÞÄŠ Þ ©Õ÷ïr·ÁKßã3TmuÞ{«“Þë»>êüøû~Øð ؽŽÇ£Å|òþÝ›÷y¾íê|q¾Oü[ÎZ__p+]‡[ˆ|€ˆm(µ.EŒ* Õ;fh:·‘#Yƒw £{44ÂESÐ4ŒR"膢[x9±vÂHƒWÂÆ$áØe 6ÏÿÔÌ!´:"[Úe®Y: €-d!ñHæî(—ÑäWކãýþQv †:ñžN§¼)rzö¸çã,rçDH¹x¦mQçï\&Œ.Ñ]ËiBu)P˜Qáë‘ÜÝsßùÞ¨Ÿµªpˆ7õ†ƒS54–,£ó«óÙb>_.æËå`4ä‘mÖO.Ôá÷‹ùžï6Ü&Û¬¶·Ÿo¶÷››×üÄêj½]o¸zÀ—Ïýz{šÚÊj)‘²€‹À’W9îòLÖðŒ‹m“ñx6Y\,%Æ…Gãl9ŸÌ¦Ã 1ñâ)uPíZŸøPW/h2sê Yk Ù|]1!fç.å<ܯ¶›ÝÝ5?EÀSÿ¯¹©ÇcˆÒ_šÇ"4M÷fBŠ?|ÇühÕÙ™¹ØÆR>óíŒü©T»xsIz9ã o‘«—óÜ¢ Ç$é8 žžÖ«ÍzsûùîŽWCV·×7’MUÛ´ãî/Ù¬£å!s©-€¨$‘ÁIŒ)Ë0Ö|éëay%e­ÑÉki”ò»h’„ßáà:ÜÃJសY»¿»çSÀ7w÷·wJkÙ¹¿¿¿½½ã†‡ÍÝÝýJ´w÷®ÅÕ·ðÆŸÐg|J^¤ô$µüu°r5œ¥°œùT —€9È3 cÞKG£Ùb¡§Ñ„ßøS¯ì¿â“1"ð± Šé2²‘ÙŒÞÕ”£Áˆí3‚Ëðƒ©EÙ RÕJ'›VøàH®Ø¡´‚ç£#GjPÉ “С“23Êp*–æj¶.â¹+røcÎfoV¨rÀí’Õ(;V„V¬Oðb™OL G » KL `ŒxÉ{1ÂC£ã—EªÔb‘ÀÑ=D’'WØ6º½™#ž€›§%,,©r Ų` UMP iã³ÒTAÁ'”øÌ_TW[È‹€yÓ†’¥A?]ÐØ‘Áœ8 +¤¯#^ÒÐx”*Øb Ž;ó‰…HöË€RÊÁê OO†ÓQÉÐlÅH6=ÛËôÓ‚~ZÐ ó0À²'@ǰLiè›Eg¶Únv{¾¶¥eQk ?KÊm Ounãø®GìÑlÜò†ÞÇ 4Ìü±¥„´~,C×Ì%°v´p¦ŸèJS‹lû/Âê OÙ¤MXhƒŒI¶†G ˜@˪NªÖ¸M©«zf+­.ðKÏãÔñH°TPÖØS‰ly68h_at9(Óñt>նͯðù®Åt1›Î'Ãéèl„WõägÝŸîO}¥ þ­ àÈÒÈýø|ÊSàòá–&6ôÎ{«,…ʲÊh8àU*‘,½Ÿ†¢¦âx‡²£7¹xÇ¢ªu¯Map½±ðüú÷mqnýØŸ·\•ÚÆQê%„ñVHi›?ÊwME$õâaY5ä®eJ„Ó’NÞæ@1†„ëw¬Ô3O3ÈÑk©iÆ7‡ÜG»ÌµÃ;ܨÒLÍpß@¬Ž`ˆ•š-XŸ€òZ®¤rAñ²Úʘ`S%ݬÁ É«éq¹°þ•OÜ÷­<®Õv}¿Yß­W·ë‡›Õݵ¼´û›Ïw7Ÿ¸IªpýéæúãÍÃõÇkßÞ½¾Uø|s÷™{¬÷×·òðnåêá(û]ÂfµÙ¬ð ù!ÑÝ^g¢QT&ÓI‹ç´õ|¬<ûnöut.éh<}³ð[qtOz(„­‹¸ Ò%3Ì·{âK7~’WäÕ=løXàm»|µÏ·÷Ä7wŸÈÞ*þts+WO±²~fŽoŽør-Úlð¡j€§7zGmŒ`;–ù`“%ÙiÕ:ˆSµAغb…¯Â &N ­AÌ,Èàvè€Ó$S ÜËÄ>ã.ý"û teý0ø_ý×ÿ‹Œ:\&;ÿX=à?VmÉâ­ÀëÇ. T“N¤%§Œ ” ¤°Ž•Eia$5ó ©«@ÒQ™RŽÎR—ЊÜN š -ý8*ö:ÜAUIâÐU€Ä&^ h3ls8 ³$æ>vñ 0 æTQic‹ $ŠHµ¶<`uôϦJÊ­‡¤êÀBGê¹r©Ò€&œ¥>taM€g( s-Cx!> ˜Ш30¿S‰ [ž#I Xû¯Ó–Xí ”Š,…,ø(‚ÆÙ|ZldŠ‘¦ÓKÐK¥VÏB*=²ƒðF©ÅÛûpò9%2Wþä€?ᵬ©@«'_Á䎿Yî’¿¿»½ÿôéš_)ý|#¥Ç£á|2^pOlöîíÕ»·—ççóÙ|<žŽ¾S`új‘Ä e!i«§ŠŒVg) cRYméV*±¾‚j —˜¢*€ÕºKÑîƒÓ@Ö{hh "ê@ÛàÀq\*úN]ÀŠWKÅÉ®˜ h •åG ¯nq]d_Ì…ŽÇš|jHÿjXràÄìžw›ýf­Íx}ýñ³öãÛÏ7›‡õn½}äWÀÙ %(þ£Ì ý¹µk9"µäÔÀÅb°ö.6àê“_ŒÈ}ÒÉ|2_ÊsåÇI忎¦^ÈOPŸ6èXFÄÔ€“˜)G(…#ÛPú”XPnã2.$xܵÝ#¿»ºÙÉu¸¿½ç®ßÍ=ß³Øs±GDR°††·5Í:€PRÍ–Útlà¥1ž˜Œd^¹éÒñüòbº˜Êø²¶J%‹‚ËeÆZ‰<”‘ƒ±÷ûšËÛÕæîæîáæ~·Þ¬nîp9ÕI¾IJì¡ ¿&ÊZ8Fˆ‚Ñø0T€ñêrÏbb. d^3Þ¬£:OcU~[.â"ª/ò16^>õÇåÃqÃÓAÒ>¬y;aÍË |úaÍÝÕÕZþ™bN«‡ûû•<6+n}/ŒAnlùþ!# M˜Gô*6“jèÜi#”‡>4C†±Š¼²©ïEãfnÝ©P"v¡>L)˜5»@˜!W*‰9Y]³Ñšº-P‚´*f¥!vݱaº;Ñ#G¨€& 2a<  Ð_Œ<&̺ 8€uÙ’äB•¼UOA¶ù™Òú%ï;ˆ¬é\Ö¬1~»#j‘ñöX5VŒ4Äk-•Í%R]¾mÃ:]§2Ò$5N„Œn%Ïò¬‡ùn A ²Cí¦^ss³õY~^MxÜ<=ò²Â~7¶Û­xš¯Š<¬·¼¡¼]Õ—áøý\?ù—•Z`%Û3R7 ùœá $ŽÑ\oØ»< º»€´Ʋ÷­‘®Ð Õ¿ ÔxAóãðÙe ç ^|¥ä×!45£ÝOªl™~_â¿ÌÖÀFä_õÆ—è(>˜¡à«ÌTPe©ÐeÊðÈIxT3?+uh4b3ÂØ9¿ÀJôe·<»XLç3ùvš\¾7å÷Où½Qœ¶“‘\ºÑé÷N"<­ܵÚ_3º'¶ÐÌW*|Íkt6UòŒß›ŒŽ€SþAföÕ”ý–ÇVûÝŽïÚûºZÓÊ?jñæN!þn™–¥KBø4‚K#ŦÔ„Þyo MÛÁ“LÂåZ-Aß×Uü²:·9L~ @ÿ©B´;èXphøX†J„ñvwàX7Õ_€W' ®-F Ùv»­c>?«ýDNñLÒò)âÜÍ¿.Šå•©à1S!Ä8j§§#™–Î)q«ZKh°áùUý þ™ü.¿Î¢1³º_­nnV÷Ÿïo>ÝÞ|¼ùüÓG…Ÿ~üðÓ?~øá‡Ÿ~øáGâ?þôá㇟?¾¿½Û©;üc ê6÷È ­[év4em—ÿÍ£™©ÄÁl¹Çk@ôT¶mà~Ü'Ü®JÃèûZGÀªåùkPt_tñ+(C´~5Uܵéø"22×Sì¿j˜"†È‰²s/”(Éö URý™p”¶¦âÑŽ}LŸ§Ò‡,­KNW4©øú4—³²Vhˆ—’¾äÃ2ÌÉ—tG}tŒ)Må‚®ćõÉ+'ŒcC'Q`3îÔé˜)íP`\Õ?†…™fHnS¸,w–!xÅO´R$dS¥]&àú3sØ+.ÁÊã*2_©WzâOU¶é,höü2ß/ÕŠ`SJ¶’¢ƒ˜½†ÖËHS¡ñP)ÁWÔºÒB:˜ØÈ&°“Ì•~êtÊM’LJŒ˜1åF–…,bÕf€Z4¤PµÕF¿§\ÐêÀÃd›ŽWﳦðS•þ´ eÖÚŸµmŒø€Ñи±€sÊ 3[‚n…K{ wcÇu,[—/ì  K…? hQùàTÛu¯}'ªŠièbçîî®)º _¿Ä'“HÅàt°Ô¾JBàÑ2lL.cö0zª.ÚüŒ‹¯àêÜÇ"ø­_\évÃÑt8žÊ‡›ÏÏ—‹‹óó«‹ó7—Ë+ùtçBN—óÉ|>žM¸ü¦S£Á€+\Úg†ö\æ8ãú„¼MÂ;Pýà†ýZÒV0=ì´qΣ«/™×*Q1¦0ü6v9¹n<âÆØ ¸ØsTõèQ90¥‚ÖíºÑ>¼LLhÔŽ{ÁS³GƒüaãêÀK¡²d¤ßÜ]ÞIsAQÿ\Ý*Jƒjw!C„:™T«âCš V4³aåšo^)±­Ú‡‘‰]««ö´¨ ÌBGÉÀ‹+¯VVÕq›4]MÖ"ïIBÖg®¬MH-®ò2²y…ÙÁ ߤUðÉ%gÙF{MÜ8œ3¾Âå,U8=}<åÛÊîžžu"¹}Úç5Ryf«?ç»Ûq¥m˽U_oÃcu—Ð7…KÓ–”†=íB×Y‹ÉÒ ³T‰FŸ}nG]~€Ž Õb¯»Ÿ…ÔDò€³¥³pUþ_Ü“F±:£²¹kCé_ºã¾'Òýa*€(|z¡øh=*ª—àòxT 1èÎPfö„>6/Ê)ªl U‰ÔˆÔÖWô:¨a+ÞÌ®Õ ó“…‰õM±Š²°“x; ˆuÀ[Úá(8˜Ú ý:;Õ …qi@¸#þm÷*Eœ&¤±VDi+ ˜CôÊjÞø€ D—rÔºôÁ- Ÿ.Øv %ÀkS÷Êknɚ̰’À2Ü”@‰èBZÔ›H°ÕI¤ÎyCñT;ÇdÌ/î,fÓÙl2UJÎÛHû v£Ž 'áUHÛ¢³ÍmHÝË®÷@"pÏÿ 5sÂvH ¤t| TTD–>BìºyèÒj5@è@!uнRPFT©ú R%µÃJ ^’T :?”ç£mNHí‰gÚ¾‡?ù4^^,/®.ß¼óþ»o¿ùî»_ýæ×ßýæ×ßþê»wß½¿zÿVžÜââr²X¨ÛcUÓù$‹¤·ëg¿jZîšïŒq¥svÖFQœùs8ÆXV„åÂËp<ð»´\r³²„²†æš«g\Ùióõå…/ÌQçfMól0˜A5îæ¡ÉªÈ5ûp"Xœ®ãØx² !$v·¯@›¥8s´„TÁ1å.BAnÊqEEó%Cª7ôÔH-ý«áà P„6©Àp˹¶ué)ÁÌ ¦ËÆTý€tkVÁtÊП¨`F½Yp oa4š$\©*E»ìÜÇM‚ùÂRãQ䨾»‡A²Œ+®ºŠ¶þÅ  t†N! œg<ùv¬Ï0¸±Ë59^eð59{o‡àï€(ÞjéÊst‡Z:ÒNid²÷[ê¬ JwËf1² 9Øp1^î¼((è™B†i T®¤ÓθÕgÐ_—”N6 Aða M ¢ ºôQB”´àAyކ€`¶V‰ˆ£ç^iœÐév¤c8dBÃüëAòŽ$´0(âÉ ¦£n Xýtj…Žg(M¥Î|ëTsšYH¿,CÀëR’iHÿÅÁ÷¯CŸàkôRÐÄRP¾È½jZóô{%‹ '²ÅÇ%QÁ½›ó[kâ9ïB:ÞéBÃ-ª˜Od8ýŠ. RÚ ©Íñ«šê2…—ÐÃ:ÉN‹5¿š=QEœªò¡Òüœ|xqÝQs›vú'Q­¹P)Ö:¦ÅtÇoÉð³4y“”µïQû;{ƒ|4¹j³ét¹˜ÏåºÉq«÷J‡RÆlK|¤àš¦Q·‰àÑUù# ³uk„×jÑÛéÒµÞ™þ‹ ÿÔ£ é[ã±7©èò$²Ú´tCÍY•R—3d…&!k+­É¼j%TS­OüAÕ!ÛâÙp4àùèÉxq>_^œ_½yóî›wïå¹á·ýê›_ÿJnÜ»oÞóòÈÛ·ËË«Ùùùt>O&|ð}8:áúñM*û ~ÒŸìYÛ}£¸­¡0GIhÈ`8àó}e(iÆÚÀ¨‹›ìg%WíV¶RNÛNaø5 çzæj€<^ ›sÃXŒ.’DY,h)!h*¨À,üº«å©"} ¬9GL®åŽŒ‚òDü)œ·šzÄZ¾_(¥ •²­ÑÌŽ"xåïL’G6A¡ É¢ƒª®_Su-?R‡Ü`BÓŠƒ £´*ªRŒ<¾?M”P8ŽÏxÿY®¼‡S›à^‚$ nÖWìÜžJxPÍŸÁÙ3²(píËoùfïó“|39pbòKºùÚˆN<ÚäFszÀ‚Y—R9ôQ²e*ßÀ˜’ ÚuÎÈ@w›7uH•Ž ‡ªÞ1M)¤9 Ú²˜åPt°a?XZ÷T«\,°¯CO‘rŒŽ—ÍW(‚&„=Ž51Ð'€b ¶n5ôUÔ1OÜ‚È_`Òº Fr‡7‡°>´nð‘*u ”ëv:&ÔI‚N™uf+ÌA¶ZÜt-˜=Ìþ ¾š{ (-ÄnóVPy@b7ó¶ÉVÊP³ætÎV ݲî”TïBøtuá‰Î‚¬øÐØ'+zT ŸÆö`»„€•WA¯‰C€y3CeöC+¬ìq¥øyµ2—$(«ÞJž©íÖ(=@ÙxXs¶*XA˜ÉE¢´•"è{ÜŠ,ã4 0ŽÓŸŠ UWÁÓÛ2 µ'¡õMã3'ª :°ñ6뾜´©a6Ãg³×6’ÿà-¡AäiP¡5m¹bv qI.hR±[æNuÜÜM]ÐrïõÅYhC,›«îÃ/ÉLKªD]'ýÞø››E rHš™Óר:¥ Æ»®˜ ²sId>f&¸cØX!r§žÖ ®h¨ªçE”áõ u›/‹Ëó«wo䫽éÂûwo¾y÷öÝ»7ïÞË»|su~u¹¸¸˜-–Ó/`Ê™SwâƒOçÂÌa"ཇñDa¬ ìH!ìã½”å·É‹³Ðg¾Pø2~›ã86\kq!Ö¢·TÇ!{”ñH€LI›7† ØøŠrj" þ½!]_lªS”ÁpXÞæ#€vSG`ã—ui€™‡¹ÄTy¨¡UP±’”ÊQ°V·ÞA0‚ÊúÕ€€=°‹ÀÍ[{ Q—ùX8ƒÊ¡$t2žÁò¸.MÁ‚½¹äÔ!©ßBÑ€ÜÖÑ&ŸN4§þ” F?2Æèš/&³…ð£ÉTg ?“áp¬îò“‘‹ÃÉÙÐ÷XmÞ`žžr·ÙiãZ³B:²Ò¾W§|íP+[[ÊJhÑ› Ïú¿!b:¬DL¥ˆàBapã1ªÀŽ´ízè™p\Ý^,Ð4ëBÔíð/ºÒ¯„í,O|è‚£â^ü¯ÿÉ?ÔQ5 jÐ¥e”~V B%hÒ%¶)2-Pbj¥¾ƒS.¬ çNðV40§ÚÌè=ÀÔÕH¢Cà§Eó§k= \"h |̌І _˜Çc×..¹EFCαd#UÏh(‹/˜j÷K@Ê(àn€—¹)Þr@iWr2dnƒËÁ¤QeX¨r:°+rMƒ¦4nFnL,ÆÔiš£¢ÖÇ>Tƒ3D ¢KU-•9Qr*œ<#£q*·„É9Täúf@%‹QMÔBHÍ”¨3ƒKQšn[‚y¥02¤ÍBäv‹­Œ%¦Ê½Ï-dU1¦Z$³ˆ êÆß4RW­‚ÞQ„ý/õðû¤Ïû“íöñÓçÛÍÃöÃOŸnùpùêööÖ{Ñ~>¿{sùîýÕÕÕùûwÄ——ç³ùT7ÏNሶ5"z"3@¦¥ :*Ð:H|'ƒ!ĺj(X°¼°æ†šÊ=p-ä %ú« *õ“"S)SÑDɃU©\Ť“?†®AÎáOBŠ^ƒCXµÔzÉ`Ÿ.|`›ÅK ý«=´“gîPkЧ8(òä›RIâ™’ïû‹zã õ\°à×”ÖŸß#‘7¦WJõÙ„^K½<«ˆ‹ægÞ‰ä† äã-Œ¨ø¸ÆOÇÍ&|CN›ò|öö»oË¥j˜«\»°öcxúzÿ̇6ûÕÃju¿~¸_}þði}Ï@TlwÔŽv)î9Âubí´tŒm¢‚†«ö_¨d(ï´%sðÜ…ùr~~qîŸL˜ó™ŒêHºQ{¶g+ìmÈÔ£¥LIÖ=í¤ixÓi^§ÑBðj®å}ê¿s½{¼½¹Ù¬w7Ÿ®nî­Ï„ü¹t¸f0‰…0 ÔñÔïy(¸o §81RÓÏ’Ží Íü °h7_,äKËù‘#)ùªf›à@¢m¦­<%,M%ÌzµyÚïùJíýj¿Ý­ïäÖð±Œí©ëPÀ-°”˜‰¬°²ªT»On=îþŒÑ¥ñ%_'*Æ\{ãV:}ÁÅ\4ʨ¹Ð[ëg´¶¤î#÷’á\H (²ð"AMF‘hH@VòDlÇ>Í©•óäTCQ†›¯FUÓAåáÇš`ëÑ»÷¢QlÇH [HwŠ”å÷*æ3Ñ;s¹¤< ð ,®’3=HÓhTBçÍ!+ª(e(S@â+Mõw¡zPeèØ&ð(¯VRdW®ÈhTƒR‡ ¼è¢Ê}ÌÉÈ{ …{Òe¬¶Ó}Z€,—ame&å¡ûzñ(¤M°ü:xÞ†Àÿ!;ªÓ Ã‘R L'@cñ:|QØøI‹Á }š€ÐUã§ÐnP¥_—  ßAŸ4E± ŸþÖxúL Ó•î'㢚Ô «®êCJ4jd†BõÀõU!ž­¯ |¾!鯗VpÛý€  ´…tnVZ¡Þk…„y£éC*¼Z·¡ýØï$éÂhÇ\¯×~†иCjÁ4jìh}ÖÊL ã±\Ds4õî ™º^”„®´YS˜&Â𤨫RbT®• ©Žreˆ%Ô#(ªždU¡r°0‹-Ë3q)¦à“ßx ¯:vµ‘ŽÔnL"sWÞ³lÊ!9$}yÁ|µ¶iåWoŒÕOCíëynç³ÅåòüíÅÅÛ‹7ß¼yûÝ»÷ß}óþWïßýêý›_½¿úîÝ›oß^}suõÍåÕ»Ëåå²>á«p>Ÿòc sy ³óéô|:^N'ËéXÃr¢a!oi1žÏø]m~¥€K\Þl«!ÁfÍ5¨v-ŠâàÛªÛ‡NÉ%Ôå/‹½v|\¸nMcë_Ä_ƒ—¥½¼’»:tD p5GÙc@/_KäFéÏAqm¡PޝA¹4€Ì[[Aú±^(±TÍÔ_¡ -5Eêk¸%PL’Ã+ÐJA"ɳ÷ JöÛäÐ,q.Ï——çË+‡7 ËåÕRãp~¹˜^.&óñr¦Á3žO†³É@a:LƧr}ø¥]­¬yå™yæËdžn»…’Öë0FðÌ‚ÔH²M“Õ®]æ²ÝºRA÷‘GPÃØ`zàÕ_©÷—cî¿w[£* ¡x|…yÒƒÿÍÿù¿Àaˆûo‡RsË—}•äT8€L`™‡•KÊ=ÚHyÈÆP9ýÛ¸n˜ ¯1ܶ!²Jh§QQ1s¦1€|âçEÂU[AO Jèt֬ЛÎCTj¦2(…®…œiKY%Ô•Z ¢Ð+R2éE‹%± Z®ÿR%Š 6ç¥U(ûÝ ©ž¥p‡ ru(L jXæÊ \j2xͶ(Cˆ(kËÐlB‰[J²@*¡¿°}©H†r±¦;x0"L,ƒ¶)Å`´Bð€ó˜cuh[ƒ9bAê5¦µàꄟÆÌ?ED•(ÈÒãš®¬E† ¼cçÛòF 8ɞИŒ§%%#ǯk‘:åšñÉ~w²Yïüþ§Íjÿùãõý?h¸Y¯$ü‘ÅbúþÝåÛ÷——W‹7oøHíëã‘N¸3,ÅYÉv‚A:]•M“Þ[„bõ¥”5Áމ,<…IEKL¤Ëk; l_A­ë]QÆ78ñÄ»rÇ M¯ñGdYá`c9¥kzÀ”Å ‘8 ¤~÷1 v  t¶ýVQ-M(J‘´é'ª…÷Ú©§…¬:b@á r?gˆ†JŽÊ‡ómP®Íó™C¾ô6™¹Ç·ß&Z†í¾hng¦ãÑd0žŽ‡S¦C‘¦£)~Ûd$¿+[³‹7â0žñ 9:ÿ4wHùšÃãžËQüväv¿zجV|=õó‡O›ÕŽWJýš¬me—¤4g8b±sÌ•$¾”É¢‹V\œŒ†ƒ1¯ÉH*©3[Ì\áÊâpÂ]AUå‹t²13ªiæF;¥d<6a¸DZQáŒj²ðY“ýÓnû˜G ®?_oVüîêýíí~ë ¹ÃÌJ’V²šˆâô + Š?Œ§Toã…sAQÝÔ:Žëšê©£ãçŽPŠ ì|M—à—‡ù€ŒÐ«»IËgoï·ëíýͽNÒ05ÚÖµHü{™iRÁyÍ@\.q V2ËW›HÆåbq±ä;‚ËùÄ?Ý1žMå–Kî,ºLYéu6â# ×‘× V­mö³R)âñ*YÇ«–t” ¼RÙ¸ †¬t‡©0#úzÝÀ¢cZÁˆª¶¯š‘äðQuÚÈ* ÈÈK'˜‹?FR#Zqà7™ÉC¥G.ß\ÉqÏÔI"3?÷\cÄ$X’ú‡ƒºbF/Ò.²Q¼zÈ+~ô¨–°JLX \˜„6ZÇÂüGÌ"¿í¿ù/´¦heà"©ìF/É ¶JìJm#¨ [Krh•ÖRØÀt@ÀA,«€©› ò…ÔŰÂZRÑ£áj“´ºzìM˜Á'±Ê{R¤‚d³Ó¦j±@E€‡ò¬o¶uK̰µTû”TuS)¸b±B8Op%"º’]3JTJ¤BžN·U #Sœ"ÚJk"ƒ¹†Cjiô¸÷l:¬X€ªžPÚ?¢UÎ >fG)Å9˜Ð󵕖ýÜ6,$³‡lx«KªI@¼…¤C]Oôì'N››Òœ6ep¼B¸uWwˆ¦ž²dÉ8íGßB~ä92„‹IC˜;K˜^ŽR@ Y¡2ºðÛžN·ÛÇíúq½ÚýðýO»õãÇŸ>ßßòrÕÏÎϧoß¿}{qy¹|ûîŠ]dª-]ÛŒ+·CaOÅèÉ-ž E$”ÒI°þc´()Œ-Yø2fÃWh”„+ ]ß™ÓJ¨¹®bœÆŸDOH…pŽ@ɺ ÇR˜Rý›8¦t–róFZ5gÇôÐJcKÓøßb(˜eæËûtV\ÓdÄNΦÎ]H¦PUʘ¤L$⎀=ñý7Þ=Èhr¹ü…Þrt¦‹ñtÁ5’ÙrŠ+¦}vÉÏž*L—³ÉRÙÙlÁE»ÙÅ”p9]¾YÎ/犗s.æ]Ìù†Ü»«ù¹œ89}#d·ä|ÖÁ¯‘jéÒÚnw÷÷w÷«›ë~Ñh·Ú?îý‘ö2šÌî2bsŽ%ýÑ8žéa'™Èoȃ}’d~~~¾XÊ7å¹Ké›ùCÓž‚ÈG+‘”ƒŠQ†÷EŠ4”âi35ñÛØêpŸNø²¿ô[¯¯?Þ<¬ï>߬÷{Ü 1dYÄ`•x²#„H‚~¤ó•pGºûØ*y¤NÎów-×±øA³ù|8ióÌ\0«‘Ç Aï#`=ö¸'€¨þ”Æêný¸}ä§<ïVûõnuû }¬Uæ‘¥´Dá,%ðU‰)ÛÇgþ>ÿq¹]³œ~ɶ¼¼˜,¦ŠÇËéh6ÍÇÃÙh0pM¾þl|6©×BÎÆ¸qñäül$w¤Õ³ö¬²Ó1¦9Ö a³øýT¶£[Zh«@º˜ªÒB:º˜nö^£ (J! à9X1Ú$È‚´"ý½Ó5ƒ3¹Ñ:Ò|Ñ:(ÑÆ“±[ö mƒ»9Üáh{¢;®4òC8 “R) s0#@yVÔj ä©NŒ÷P RɄӖLi£`ð_ýùmCÙBÁ†³—ƒ}>U…JWÔ5›´hR Ò´ÂÑå­¢. v•©º9tÅ­ŒJÈš²8µC éÄâ)iÔÎÊ£ ¥v‰¼¤²¢¤£4'‹º´LĈ(;ÂþJòîž‚5’rär½Aöƒ@(h¾AÕa RßRCWCºqAj:v"4•¨j•€ê@¶ê¡)ƒ4ËPUúJM9BuZ^^øKû‘Aµœ oe¼à‘  M•¦¡ˆLÆìñF„4ÖH›Ò`¿+jÈJ[µ×M¡*¬7îD;‹f¢ÿ$\ÜÒJš®+CË/pÓèž,¥ï ¤E"méÜÐ.(׊'`‹\¢ò)O7›ýš_ÜÿøýûmŸnùéžÍn»Ñj9›å·½y»|óöâÍÕù»÷oä´åÍq«]JÀÇBYуœ¨Øem1wȱF#Ï©K¹ð¦IÜU´mmBšCßæ#º» [se€UZ±«°êtÓ{üÐb(-I˸¿ø‡2c%1¸^á­§byWЏ‡´äb~Y‡ ÅžŠêùÏlà¾ÒÆ–Õnñ¸V&P&*IŽr0HH=oAgÏ,N¼|j×m6ÆE›O'òÛpÔ¦òÀ|Ktº¸ä© 9gÎúVéå|!ÇìÍBîÚå»KÅçoÏ¡téRˆ÷oTKN›ä(Í$!Ÿã’ëÆÕ®õJƒh{ww§á$ïíþî!ßnxÚ=úËtt–ŠÒÃI–Ë(M}pK}9ŠQ#e‡g5Ȉª£øy»PNj02Äbx:”Óõ¸{|~[´:ÙN9í™M4ÆÎ/υќ¢RävÒ2GK": öK ]b×ñˆ3&Í5Y FúÐn\Web„>¤nd&nî+¶soÎ.q9ªóg*8ÈŽÿÛòXxèm5ˆà&'JRC y¨B…T„Â¥»†IÈ·¸K‹ 4) êp‘T™S¶…¡ÕvÊ©]#À+ÅöA²‚zôGÃáI2•é_½põ°Y•mhMd¸¨(ÌÀ½½Z80òø”øI»Ešmzu1Æ5O4°Lù* H‚±°Y?QÆhV jžáE¢‚^ª|Íœ´B(ž:¦™†ì¤-Î.9@CBlRf”Ri© å¸zä :'²`ž½^¼L¤ÈÜrþšlK@AÃÞ…Dl}@n%‘(M[8™sˆ–ƒ¹`h¿©ÕÊJ¦mŸÁÈF§ñè—™µÀyšð3^K8=Ûlw«~"æ‡?à·}øðñþö~ÏïúíFƒÓÅb|~>»z³|+¿íÍå»woÆcÞ+TºÓ0 ú¢EÖ¾„ȃœˆÀÊZ,'´#+d; CqTp:—!­2CÓmµ†h‹9säà&‘Ö•¢¢ ž1Õ„À\!¨Š]ºj‰¤õ`‚Òýlˆí‡ / é^<‹^(·X«VHdX€Ôš¡IÂu3³,§"UdúÄ. ÂzÅ`Ã5;aäJù’›¶ÕádT~ÛT®ÛÄWª|ámÎõ6ßjœû’›<9!ÇsíµË™âùålyµœ_,–oÏå«-.…œO—3íÐBž¿¹˜Ì¦ÒÙ»‡¥¶äƒr#ŸV+96ÛÛ;¹4òÚøUÉÇ=רò^‚@J_iŬ²Üøm¦*D1JØ¿ùµ.Œ1äRÇx6á‡;/Ë‹¥\·Å9w„åD5d±¯Íà”DŠÝø7BàËFô÷ƒ ¢¨fÍά>`Ä& å’iÇÜ?Éåç•ðÛn佭?·ÇÏ÷ÔhäH%×U Ë¢æ>sÓÑš ¥¡#S°kçËÅLš½9¿Äo;W?žÎh\®¡$÷¯”¢%Ýï{‰paäp'UÓSîñÚ•,¿}Z߯vëÝýõ=ZÕÅÎN•#†ˆN(4ç‚K*ÇÇRÂU¥Œ<h$\¾»Ï'ï®&óñ`:Ê-›ùeg ª‹¹¸ÓñÙÙx0ž«ãÆ*Õ€äþ©Vùm¼˜Î\4VýÂ)—â¸ÎϵÙõ ùˆÄ¶•ÅÆ=j è 2DÖBHg±ª1Ð×)AªT°Â€¨µ´Q z´?üŒƒømœà·ÉÕœJT !Ó´àæ+Œ²†®*IãVœCòCÜ+Äoû’@"·8Uî#‰hà@8áz›2’] :jkI¶… äßø³rsÔm4ÍhreCÉ©‘lÛ+E/äXj¤%7- x¡“]R\3!ë§br¦VLU`Akf!kõ ¯OÛDApS??sÈ£K=Å׋)¢ÚGœâ,'Õ¨ƒ|}°¬´¢qó8‹d ”.F0/-MF€¢ p%eª:VB}wè>&¿%ð„@œ?%´c10® ȯA(eZÀ%:ÆÊ“’¹¸òßãGJ•]éÅ«ªú³ §›õŽð°ûÃïØm?~ø¼¾x~Úëìl:^\Î//grÚÞ½½º¼’ëvÅ{†™¶éÁqIá°Ž›¡¥Jx}œÍ,p­Â8¸ºR s\ª áPúwNÍY Ü>„)»QF¶êºF84Û² „؇l¥’Z™Ý_áLºÑ‡ íBŠ 4T-‚&dåQ §aLè„K¥'¢¥þÀ/M{õñ--vD¾×ÁÝ7Í$mùr†xŽj4œGÜy´{7jë妪ßEàF*´)æíÍ~úm,b8«ivPeÂjuóâ‰Æ€ÛÝnÿøÈoË}ÛíŸÈŸÛòžlTf3´Nœ(ò335¨=ÏØ°í^ ´—òþmÀZ;â¾%Ì|9[ȧäb›R3¹¤ÒEõjzb`¶ æƒ{„BÇmF˜1Yuí#º[8Û1Í“o½É+•ß)t½ÝòzìææóÍvµy¸}÷¸ç2eîu~[Y(ÜGô™åqcƸ=è¦áÙd8?_,–óó«óÅù’Çù'Òœ›¤båìLx}à¶qW<ÐOv´œO»'MòõýZÜÃÝjuϯ­ß]ßÂO9‰ÊX9ó_KŒƒeÖŽÎom¹Iï{W—ãÉäâÍ…\7ycòòíŸ &É6Œä½-¦`rï8sà‘Jk†gà&êD0ʃ”'>ã2Yð^SÍHO5êxÓÎh*ð+mŒFÖóø Ycäœ i`\a˜ZTj#»ŒX,*¸»¹Ž(¶ž7Ð4ðJï¹†Ý e¹‹­iãsO¦¬-†•nÅ ÁKa]ó*EÚ8‘HãûàŽå£ZðÔ…Mø¤4²£ E¨Ð(ƒÐg2×Ûª5 öÑÒ'0A˜ VöÙªfbbµÊŠQãXt…@ÒU$è§;i$N:ÐJ€"íÁ×ð_ƒ>}ÆMó%¨È®[Ùº£üZ•ƒEþû´2Tþ¯Ô½²ElH[ý´ZNã•3¸ö_9ˆ-œõŸql!ÙåAù$.ŦPÅvõ¾Æï_R±Õí%_‡6¡˜hœô÷gØÂ+-Ìì Oþ`¥²¬3g<ä>ûc\fÓ<ÕlÅ“hÕ“(V£¥»¤«ÛJõcAK¤¼B£ÏrXÐ%~ªþQú¨õð*2Ð/zQ½K;ç:2E’¥ ø„WÁEŠbÕPý ùÔ6oãÅb_Ç3“ƒíŸ!õ·QýæÁx:&°‰*É?›-äŸñ¸Ûâ|ÊÒ‹Ùâ’KY¼ È{¦¼[:«+m\Ÿ›,µ­ŽÔ¢—õu,£% W‹Ú©k Úæ™ rõGø^' CIÌNÙز© ²J礉kÙœ¸pî¶jÏm1"ñüÄ_¾MÙ€îY˜®w¾„W èÌTVÜãrO±L´Jt uðE¥Ÿ³ðæ.½q˼|HEüÑǢɫô,54 üøy¡L:ºã ê…lb<…¡ ¾ÎÆ«-Z+äzq;ž¡2•?ͳ’óåÕùùÛ‹ó·Š—ç¼jz.ôüêââíåÅ»ËËwWŠ/Þò‰A^Jõó|ÓóÙ”œ“óÅx1/çãùl¨SÉÙd n2ÔX"pkÄÞõ€á¡î÷·Â=r2x"½¦1vÐ$ýÛYoPïçªÄ-ゎLì% žÔiæ( ÇPó*dÌÿÅA†÷Àè÷¨4 wÏ ~{_¶]˜ÁõOþa 'ªku=½[3ß#ËbD¢Éhô$£qÊ„¬xw.ŠN¸–F»)m´áN SêÆ Ô L)†¨+©Š0J&i·ä€vªK3L,cä2k²)˜—uU\\ª“`êÄΖÂF,MÏLWÒĶXäB5¨Õ£@Ã=”’ªiƒ!ˆÒÁÀ àê@•Â@fñªÌø/.ÁôBÉŽA’mÈHvàî¶:P–N6U/*¸bžÔõ1Iõz·J уP˜we9¦9 li›“ª[HÈrÍ…Xuè%™}FÄ<ÕuL‚Ð8PKÇ$ܨ+9`âÊzZä)gi•D˜ibå ˜9/2.mŠe‚£l''ÛÝöñéùáÏk­î׿ûó?l×ûO?oÖkQéäV§ÁïÞ_¾ysñÍû7ïÞk•]^\\h‘Ž$^Ò[Þš‚”MI!ÕŸÎ5|¬ŠÒ*º;É'£™cJh’§•$­@i2¥ÈT¡‡̦Ì$]6<» ŒUþJP™"…)ÃèE`eü²!‰£QÒtz³RÊjO–4ýÈ=ŠŽ—0žLR[“¿–v{Of·œ:­Fr­üɶ‘ïJød[}mwÂ_¸Â{¦Êòži¾¼Ë=ßfP֥ܜ#b‰¥ñÀg1žž¹è¶Dاg¹Žª6V#>à³pr(ýŽd>)Â:?ä>)f•ÔÿÏìÇg¼ž1( ᜇóço..´ÓŸ/ççóádÌ}+_c´cB:_Z*¶hY …Mt`…Fd®¥'o"f_¹Q2|öó§“ÇÝþi÷¸[­×÷«ÍÃúó§ÏkÍ »»õjõ¸ßáwYw—ƒ{ÍA ‚¦ûîÐ4’úþ£œZ.ŽŽG<ÿ®ùv¹X^]œ_ò¶¦¯·i¥áQ¢q%ÕÞ°jù&ïˆ=€Õx“ôI§`Ï'›ÕZ‰5Ò[m×Û»ë[H¨ -0â ‘¬ŽŽÃÏþÎ.®.4bÇsE­ýâ©=ÌkŒWšXO éùgÐ2ÐR±+¶ :’.ÃÑ¢õƒ îcZ×Â{ÎWZ%†ÜëTsŠ9Kßö¿d'4XѹÑÊ”˜­[ÇŒåN|Õ©Qš¸’uS¬öh¹áz"‘È&I* GªXm…Fõ%@Ì#V€ uÖ@XÀŠ=3Ì’ë·Ð˜ÄL*ê˜cð+î‚Ñà»tFYЂyI#ªm‹ëkÒ~hG&€tˆfÐµÕ ãôÙG²ÊA[ú^°ß梀Él0‘ó‘£ Zé¡Ì½,´V7Ôr¬PXªV Â1¢ê‹ëZ,¤Tjì r?0›{8ÞÄjÄD©ØĶQˆI#'z¦O³ÛoS¼ßÊo{ÚÉâŒgîîq÷h®®F\sßø©p1•4î)¯Â#’Ý áe¾Œ†ß¶¼à‹»ËËsùC¾ Œ¹žyŠûà~]CÅçŒ×@ü>©Zƒ­bÍsÞáãº[¾»û(§muÿ°Ûlnå·I4ÑÓM„°) Ϊ#Cùmª‡n’YN€Nã4ç y\ËË%å´a?›Ÿá’ÑÅ/ކïm‚û/ΉæË5|0r&gMNºL1‘[/J U˜ðµ[;j~0ÎÏÀ±X:ö`lA”T ,}JhPIÆl!*{ì)ç$V<Õ§óTžÆñÑ]nÇOÏ/ÏòÙt¾á²(¨‰‰NeÔ¨ P`]‚éBb Pj‹BÇ_„À³Å&PëEYµºAž‰åI]~·$#bæ)Ø%’`ðÿ›ÿœ*›Ÿ¹´ Ÿ ûZzÄJ“ò_ERÈ´•uÛŒ8f¢0`驉G14¥³·ýk@3†È,vùC*÷þ] s†DjwŒ×Hç™ÎR))º€Dž¼Èæc¹r4ªðÉ6ˆÀ­q } ¥‘áeY@u<×úŒ»V^4×ËòziW”Äpöq¤pÍŒt:$à(ˆ“Ô¡B.,69[ —wS'ã,C†lŠH†@€]ˆö85­ÿŠ ¡“¿VÇŸ‡´€¦ £ý¸´—6([³Ïç“€V)¯ ¹×¢ÀJ®Å‹Ù"Òç§õf­Íõánu÷ðp·þÝoÿ°ß>ÞÞÜîw[­¯Óéh¹˜|÷ÍÛ«7ømWo.uê+TÔ§E‚ÿ;r 4c0É€«PC±cÒçftE…– À¼}Ih•=øÓ i|?¤VKéFôÑñ@ô5pƒI¹Í,rà& ºñF¢Š©)õà<@«FŠ£Spëªó¦+ï"Å>áeZ'o&E×[ HkûÃ/+Pº¶?ÈŠ’ŠÕî5L|]ÖxFK1Àh4<Ÿ þËÿú¨ –Néäo×ÒÀ%(Bfê+ö ô0ç)U"£Ó§O*k8_бüG•¨Ô#óTE›Ñ³vVèœxò8‘tñR–Œ³IC`ëtCð]iÀ•AÇhiÈë€ßÖ¨=Öù ·â“tÇ”„uMîJÐÞ1ôk} ÆšI[!F¶?”Æ*Þw~¯¼á“WL`49n•0ôµD@ãS¡µ^5LÖU–Ø8Òµ&bš/n®åz–ÇüìØ% 2Pð"ûÌËœŠ"Aå‹yˆ½[Ñé‘F†Ð*Å¢¥• 19›ä,›à5ûîþv·ÛßÝÞëüá~ý‡ß/¿íþöþq¿Ó‚¹œÏ.–³_ýê›7oÎß¾»¼Ôɲ85cÐJg´@¤ñwêPXâ6¨{<¦27äO” f‘l‡«\¥B‘zèõM”4_À¡z FQ5‘ûšDJ€£Šb“D†;!T´`LÑ;xar¹A„óÐĤ©˜*Y`Ô_.cb K蘺¶bÕ )„R„Ãxª¡…8ºÍx™Cè!sì´+ÕBÎÃŽ& -@=£žG\ÁñM±éÅùR~ÿr¹;Â{ —Sܯsž‚šóšª¼;żHá7 O†'öÆN´Mú›|UŸ-sÆ ü&ÏH-å·iCå±¹ «­7',rø·9ÑÞ‘¥«È÷ûð\¼• ¤ y7ÖTñÞDøô¼ßì7{ylürÔÝêV~›|¸\"ûm.` ¶­†£×(âýÊqs)W}“t1/gçW—r–—rLå¨rWîLÎ’} ÅVÍìNOµG t&¼pµìF“úéñqý°^­Ör1ooîÐxdÍ©œû¬:_ yÄf4#$£Pà‚ÉMíÓ«7oÔS¾.x.WIʰàºíó‚3nMÌMŒaÌêî®òrAWN[¾ 뛡ünÞ/A˳ǿWÖï4pn¾X(-_ŠÁ3NýºÃŒ7¸$ÆÅ0¹qÓ±O KXÀÅ];díÙ¸YKšI\$+¸ˆëm„ïÎÅ_£Ž“ùmƒú )6BS÷®¥kùǶ¤l]`\j£ƒJ ÎV [ã·ÀƒIÆŒ9 êÁÄ®åCüzo–m0Žºê g Š ¥£T‡@#W‡zZ4JP¥aÒñɬølH nAq ¾‚f§„Þ3’”°* tƒü(âú½²Ô ±hûŸ‚ÁÅ Í.-ȾTù"T%0Á;“½¼áÙDİ €9Ô­vŸf›:é.ÛÇü|èè_ ì' ˜ºVŽeÓ^ÿæL) ¨Öû¯BÌÿÑ¡zƒ&‡—AÅ îMÛ„*!îƒpRGPÂ÷ ‘%t"5‚¿š¥Ïô¡²<ÄÁÚ CËå¹â[ñMŽoñð˜Ü‘Ö+?tÄK :ÕbÊ970ö×>äFißb8t•/I„Ì¥¿@V.V¹ƒd‘6™Dô`¤E©ÐÈú<â„úžÄ¶ïPÕ[ë™ߤ…/ ë¨Jò@§lEg°*¨-fƒD÷˜ £‰˜=ªõá1êö£8¼X´踪 ¸¾›ïCq4‰ûÀJÁ*⊛VÁšhÁdÄðšêx¶˜.Îg¸ r³Þ\œ¿½ðï |Ñw9»Ð)‚ܺéø|<^ŽG‹Ñp>Ìx§RÁï1hó<}*œ8qÂ…?Ïî+<äG—8Cñ Ö`,R:Ù)šÊñ{öX%Áâ›3d¾”ÅÕ œ_<@oQ>1´î‹fË×AEÙô¹”'aµ×ð»¿HûŠÜÄ‘M©’ýÈ7LmsóWH÷Þ—%ßZ ½¸sw•[{ÊAŸÊŽ+À`ŒÖ­±Œ÷g ’³@ÙÃDAQZ0îoÛç¡s<:T"ŠbëY'z_{Ó¸—{Çe0¼U®§Æ;çW:æƒÑ|8^ðÒ —¸ %&K~~·dÎgŠœžMÎùp´ßf Š¼7<¼Ÿ‘ÎF $ž<;Q˜ N&Œ¨“щÆA* Ož†Ï|n†Ð½=l?C£H–ýe^÷‡µ²–þ¶&óžD/\àÿ…êÅEªJÂ(F¡®Õ‡^µê¤Rè¹%3J“'ƒðÿ¿Ú¶×ß‹ï®ê_1ç%™ùì6Iœ í¹Ò`ø4 _’Fø(ÓQYVUÜ„¡ÌõR³@5©í¡XKcpeIOPJ9êw]êÿâF©QÉ1¯é>gakÉ­¦MÆœ·,Ð #Ѐ@MhZ!ÓŒ‘oq_€ i´r†²yvpÛ]oæ?²‰ ²¤Ô&êÆ†Mu•6 ¿æñˡϭj–±sRÆÿ_.Çþ +íÁ|vîœ¾Ä ¼õ]©38õ—C;¯†chU$Û«ÕÃT­2Б##0dÀu¹Äëå»FP+íêºl/øY‰h3T•~(ú ü$×i·N2¥*HäL«íIu‰m¿ßîw»üv¤BáäI'–œîçÎ…¯¶±Ï5ÇÓMŒÆÞAèýRêÐAazõp¿z–éªñ«¡¤êC¡çÎ/ë:*Ý«{)Õxoá%x!Ò‘ZMÆÅ¡Îº¬ãùJ[»J3 ƒTñ…zfíZȼ°~ÂÚ(Ahz6MEB8¥„´hi»ÕøámÔéhêïýjåÛ"W‹ÙÕbÎË’üú8¿Aþ–«qË+¾ñ»Pö Y‚våé¹<³QÞ'å"ÜxxªÍu4ðSþ˜ «U{C„µá ¬JºÁ:’4R›î÷˜‡Ric2Ee q=ñ¶æž„©½ içr˜9ÃÇ5 ¨ fó¿!$¦v#žËQ|n¶=BM“Q¢@ï,ÁEvc@Ò†]le)lU<i¾'oAÇ>¶¢Ù´ì,&³éò'ÿË_ ²t´DXÁ 7%Þjb®2²bjÝQeÿüÙÙ“+‹7ÊÏòÉ'g£É ÎF£ù¸}f,çLc#—Ù4®ø¥ÚóÅÌÞä¢ñiM: 9jãÙX^þh6Ma8˜œ9p©ÑåÛ©þB ר¸êFàçfzf´»V‹!;_o6ÿ`™uí*m% Ææîëcø²jÙVPÕÓ¹@0Ušd ©•Ï÷ySÃ3HéÁßû‡ÿÁ†_¨Î·åë뤄‚M‚ËpòuÔ]nH"ÀÚò¤9§*€` uM"þ¿€é™©í*>ˆò»œ*²>C‘Ac:1ÓИQÄ-x âj$›$.°€š œ= Ý t‹ àìw+xTpYÎHh sãêÐÃLƒÉç‘4_ ,q f0÷d”äyjõë"gZõ‚Ê"„ÂØâ@ÊÁ|À[Jý+-œzÁu¿€>ÊÂBÖ¿Z%aZ2˜Ž¾NeJ\f|ñëŒèRÜH85zV¥êÁÔ¡Œ PVI€–ª&”N%Ëð.pk]­®%Ę­w…Z=8óO‰H±¸*~zÞ=îüðq»Þ~þôùÓ§ë‡ûÕOßÿø´{Ô4ÕDÒ©éÛ·W‹ßüú»s¾j»ÏòHŠÛì,ž’´\¦E´ŸƒRÃdm8Z̯ zÙP Õ«²IàbzÑÁˆ™¬ƒ¢S"…¥(!¶¡Tp—SÚQZ¢C T'pÍ"Цr…éEÐV]PݱxtCÆb‘N"Pº˜ä<º@¥ ^;û_òe YC†R‘o£ú¤0 Hìg1ÑfQï ‰nš‡ôÑ»íêa¥9Îû¤wwÂ>úW+0WHOýE\ìbÿLðDG{n¹”÷I'³©èƾd%yæËÅãóã¯,Èuufÿô¨lÛ¢qBÂÐi5²4Ñ0Ä…Þ«‹EúéY§*ñB±Nüú§“c^öãôrÂë ¼ÏÁOŒùx ç Q3-é4?Ë;ÕŸÒ³ùl¤3й_cr_•ËmÓÉ@œ'c±õuµÑŒ÷B¦Ë .ïq½íò\Þ¤_}ðy+þ—­(³`7ábGV@’ÐÀsz¥Àÿ*ÕLßâH³³»HiÕ‰I+Îv³Ô” IR>¢ µ¨hѪW!ŠÖO÷öïðuú_ot:Ï÷¢yœFü™Oê0_QÒðÎ\£viBžÖ%\ëeKf#šve‚­d.Š»+W9J)C‹Ü®ÚاVpžäüC+0 ±ˆ&k3*t bGÅG ȃI©†ifs4‰:9„GÈ~)˜·*lážï%K¸“BzXÈ»Êh!¥š:UÐ zIH+ÕqN†êUš¸J«¸LꜦf¨2ð=8Ê›¬ ¡ï h …j¼ Y¤ 59¤0%˜Ž[—6P–„‹º‰ºJJóÔêØ~ bI>^7WeÕ>{-8§j%çŒËyì€å^ôu¦ô´Ýï4ø?üôA³óúÓ¿AµRö‰©¹Ó|\.æïÞ]É]ûõ¯¾]ê\v¡õO礜QØfŒÑømð®ÖÓÈW5¥4áCt´†©FÌÌP¾Æ&!”M˜× &(&(ÛUÏðàST¡UlºÌÊbÒ¢¯².õ¬S¡…À ø?ÙÊqHM·u\§[ÆT&sÈ‚ìxÅI:£ˆ¸ˆXÐP±i\u«²@[iÍ}rŽœeù7+®î€vÚµ‡§g\Câõ‚í¸¹–M—¯-hCõ‡»´¡ÎÏgì¯ÜêšÍ¹ÇÊÇÌ.®ÎÎ/–ó¿¶®]œ—¸‡(‰¶m¹tª‚jý!”Í,¿-óÌý¾’¤i£eþñéäñdý°Ù>¬ñÛ®oî”ßæÛŽþ…+ôÄüÍZ¼½¤Œì&”ª«ÕYðmî?ަc¹ªþ9ù ùmR_.‚LSX§_”ÆC”Ï‚ÉÃßì`í4üxÿ3ŸbÁo“ã¶ÚnvXñÿÒ ‰$xéL]ÿ»D\0#˜´‚…£Œ"o[EêAaäÖÈoS_pvçÊja/£¡+ÐmmJ©‰ÐØoó)¥/,1‹µSE”§ÇPYŽ’©L#‡7Ôã8pÜ7hŒ|­¼¸ $‹ñ¦*ß œâÒù«o2¬\·.àØÍ4ìøÎˆ?I¢˜Ÿ]–ûÇÝj?ÔËøå\Î\.æÉíS¢ü6»¡îìXR‚ÙV-—(Kòå»ß kZ]èð=ÑSQFÀ¶€10¡T”˜©¤GQÁË„Y ä·ýM9j¼¥ü¨ĉ¾ÅR€D±ºR±õgÚáj”§Ád?ÎhÖT)99 Á S$´TC™ÆÕ¹2r¨1— +~Qe † ­•Æ:6c ¨Þ,«:%f˜,Ô ¤¦lK•0*vm`ÓŸìôø¼€~A?‘ 0kGNø‚ïÁn!tì 0×úÕª Aqö²b>*K©ã&I+IF:4z „Dw¾!unwøm?ýôAëøõçk¹n:³úüñ³ÆŒ¦êpxv¾œ¿ûæ|9ûö»o´ir†:žäJ°–a17ëš´&ë` ¦pOøºÑØA)õõ¢èXéi°Å@ðî„~ÛÅù`7c e¦^¢Y²ˆt°ZA4-Qàê1ªa Ÿ˜sÅ]J£Èje Sßl Jq™ÁÏ·+–œ¸â‹œù™ãº&‡?Çš!ŸÑþÍ'B­œ9|;Þ"d÷Õf,zÖUïJH_ÿ[,ÄZÂrYÜ:dUÇ5@åDÁóY<9ÀŸì¶;Þ']­×ëÍn³»½½U Híµ8KøI½a±(ÿŽš%SFŒ™°’²êí^qƒ´»É«~âíË|Ø JÕÕ¬³=µ˜€„m£t·ª´Ë@§JêtqÀcSý爤˜Ú¦±\*‰UP |8¤£Ù“g†ØùšKÖå]Wyd¼žloO4vùxDÌ옫›y•÷$ÆýÀjEm«M ±XrJ*‘áàÅR4ÞúKy"—9A\˜Â÷ h±¤c[´µïŠX…)ãT£ —5P$ùó`§ÿ»ÿÛÿ<Ž˜Ì'V&˜ÍÔÉßhŽ–Ë…Ì¥I8Õx)Î<28#[¤ÛéûìòñÔ°Š2ÑDŸÆÜ0 CO$CêWeá¦~”VàYG¨™úŽÂăÃ`F2-H©C…W£827²8aa’˜!è*¬AÖW1xêè6Ò¡C#Ñ÷%©yh?åy$[b±JPÖÉV " ‰Uš<::ö|‘ÕÈ4KM Ë…®npFÆTоp)Å }½Bhœ…ªê]£¿Š–-Í ›Ûó‰¶ ã®9ÓzÊjéí4Ã Õ Á±h$Tn{ÆrbèWÁG Ò•e•n ïªXB•LÆm óòˆßKà}‚ ¯=¯·ÛÛû{mAÿíûOµ ýù¿úóßýöw›ÕæûßýAêéœ>›üê»oÿ½?ù[ïÞ\üí¿óï]ò«Ö‹ùb¦¥Omî58X嵊–7:¥ê`x©OÓ¨í¾R$ylçÌl ZK-•B`•=\•’à̧¼Ì'?„Þ1 ôŠ Ü©dA1ôŠÑ¯Ù±­† •î1R²/JŒ0ÁÖjÛ2*ÀÈ™{G§6˜ÊuO9]¶š ±ƒjyf‹ÆÏAëç\ÌŒ ܺ²1›ZÍY:YAE'äþiO»ðef(x.‹9Ù¦ý™÷5n'|Üܯ¥“jòÃn‡‹Ç5$´R•`lð®ÂÅ$™ÆWkd- I9ñÈ ¿òùþ»÷ïóÝ7¿þîÝ·ï'Ëé`Ê/¬? <±yó‘i!Kªñ„ï)ò\?˶´xÞÊ'Ü¡Ü=žJ‹ûí~½½þðéãOŸ®?~þÝŸývuw÷éÇOë‡õ“TÛ?>îö'ûGõ<Á](ú×Ic%õ<æ‹xÒJ¶[\,$ØÅ»««÷ofËùßøwÿæÙttõþ­<ÿ¾¾ïîYÜ-Ð;É]…ßEH›êUxF|ßd¯ 6ñ(` ¢Cee.qò:¼¼Rç`<’㦽ï‘Á€Úf&- YÍ‹'é­ŠÏ]"à꣯­êƒCQŸ+2VR³¤6®ÆíK­tˆ”ѧ4ïHq¿º0Y—îBÕm¥•µûÒAª¤ ¸‘jÐ×··¸öô«ýHUÚc©L¿5i8(ðÇÛh˜G`ŽÞþ!¥r\ã3Ì,Dð¯NùúxÉ<äÁ-WnÜãîu¿ˆ†o‚œŽo\ÊåÐ\]ãwgä­öšÈàþ·~©°ƒ¿ûŸý‰-¦¡2ðg üû)Ü7öªÂ²·Šo·»››Û‡‡UÞXVج7Ü’×Ùo5ìå oÖ;Cˆ’×¶»Îx`Nγ|Æ8“Hx‘9urR)yߢàñRy”?ò6GSF±ÒfìùŒÂQüU±âÔ*©ˆ{Í¿€®Å×H„só"â:ŠIÔ-$[¦AdP ™ËRS¬ÎèDò%©âŒFƒÌIkå*a~ÄÕÛ0tÆ'I ”æƒT ¾” `õ"Å 2ìH¢Ê[»J6‚Š5K4 ¶»&™fÐï~ûû‡û‡Ÿ~üIa³^o7kQOÇÃùlòæÍůõÍr9ÿöÛ·³ù”GG#7ËYýÐ&Y·Õ)r€.’ÈáÝÏBõÌd#ŽÝqRP ™|­ˆ—ÔÀºi…êk™ãp¦+@ŽŸ^¶Ò)èƒ*…_ P2+4Å ^Ö8ä‹ÎˆD¶¬ÏÍbÐ.ÿôh.…$í”Ó 0€G˜N ^ãÒ#õÑa KKâªt-1®ñ,I, Bƒ ¹—_UànbÖbˆ¼Ê8xE\¯½•Í%©"QBÇ̯Z t"¡ÝBÛ†÷ ïªÈW[Ø üÀô#ÝâE/ÅðVed1`®ÍX@iíáxå!cD„#Çꤔƽ/ðìŸîÖ÷7×7ן®ïîîïïî·Û­/&¢¯ŸoÃV¿lZâT`1‡¿•diÓê<ާÿ¾·áü%”«ËËËååÅd6É]c;[xq]Í–—$/O"<Ð&ùs *jû±æŒän½QjÅ À;ÂHrºÌ‰o‚LkQ I©’ìºX]‰ýV$’Aót:Ùíö£¡¼hÄE4«†µ”²T‡£.!CE8zEI%P­"¶?Æ£pt“Ot¸øÊÀCÈÂå{Áè+Qáŵ4Þ–h¬Ïj]Cˆûï¶qž~ÃØ¿ïÌK <è6Í‹…V½ùby~îÏÖð^BNsÞZð“”g# B.Vf¦w´Ì¦‹Éj<'dBж,—Ÿëñ HéÏ@hÂ9€4¶ l /2Óhàhرn3R‘_È®!g’)Rœ[¹ìZŸ.ñdÛ_l>}Ü«ƒŸ÷Û§Íj·vX­¶k~n+ÌV²Æc«°‘÷¨°Û>Éu£sù–ãDÃ'ÒgµA” …Ñ€À*˜2Bce‡0ó ‡Æ>{èA½Rý€(Ò4øÇ 2F”²Çö(ýs‘ò5 ?‘žä—@Á¡¥¢¬ÌQNÐX¦™Sp ùYHVéßÉ«¦h‹eèCëªÑ - ÇLRttì9 Mž,ð (3³†–yR*DÜé«~éa­"½¦ qÍpäñ™®“é¬h¿-7@ÎNòÂH')žñì„l^MÜØ£CÚë·ú¾ZðuhUÜP×V—>´nP–}¨AG¤-P¾Wô³"¿€fÒñý@ð0›&MC¹A(S}ߎ&èÒ¯"±kz:î ]F`7ï—)y<–”<ªšºeßj©d ¨)–,žX‚2×BÊá‹;Õ|W§fΩ-VÁiŒÇ’Êcñ#Jœn6ÏGuY$µ£gõg›¦­0`J&QY¬€*49€¼1I€ý®“6²™quöíƒõ\Ûaé9"Z{÷‰³¦.È•’×uö$|ÑÀé`À‡h†Ä‡,O ù2‘D  à摾ZD“d±‘Ýbí·b#—w<Nùu;‚Mµ¼)ûr¤›¡[©ŽËöÈCr;¶cmÐ|Án»ÞìÖìÐÛ–§/®?ïÛq)‰ªæ"Ls›{òbU3æÖ­<3^ÑP!S¼‡!wOD°Û>rE‡U¬…çûá|]Dž«·lŒe;Úïå­~%k<âÝÓqƒÉ˜/ѵ(å@×½Q¿£ŠÑè –Ldñ b†I¿lÒ#(v†Bõ ªõ*öÉ\é0ªí‘Ån‡º¡=@¡að?úû›ñ¨ñ"§v<•O;ñKº2™^y¿”8pž«ÕæúúÚOÊÞl5&Ôw\Z{Úò‘‚€A³—»g'H¢Ö.ºå$ùi³ÙÞß?hrýùŸÿvu¿úøñçOŸø>Ïv;<=Y.gç‹««Ë÷ïßh½º¼ºd²Žyt·µñYûJ¼T(”Q¶%Iáw.8”ªŠ+£¬ ¢³q$I; ¸šÓÕŠAédí·9%À0²,’ÄÓÇ´Ø'nî Q4UhÁ"xâÊŠèK@†.®È+õ£5]»Ös¯ò4 \ŠØ)Ñ6pÒ¨bi>`Â9ù:H5BûÞp¨CpB^ Œy–®è@¡ö8».Ew€Ô¹€)Ñ]uµ®j»ÕêŒP çµT¹iTàó H˜ƒ´Õ•aé¨%Çú현âàK] ðËö\ÈÁ×ãc‡¸ ÷w¼Žpw{ww{Ë»¥›­Ä½x›ª[ä°·Ç P€úg",×$y~4žNççs¾*|q1_.§óù`<:Óù“¯±1—uje!9ûbw³(C[ùÙªGÿýÙ>–üo©ò6W«µ·KE¾ˆ%væCÂVÚ ˜¡Tú ?:˜×)0òd:Õ£…‚ªÏüø½{‘€-Ýažú/þ‚ãˆX»df¯õ™ýt ÌãÎïêÊiÓ_Ç6y :áܬW~OV©Ínƒ’|el»ãЏ¡—Z—6·õPœn`AO?¼:îŠÚ¹«wP8|LX8y8 ¼#Ò1â?ÝD$¯Ðì©LyQôšN ¼ÿ`]iL«w Üà&Y³*ò€ò¡¡›MšØ8@XK[ þãðw¥kœ6yl:ðnw^Õå·ÇÆ¢– rÈÖëÍííÝßÿxwË•ç»û‡õJSb·zà-˜‡‡Õ=ð ŽK¨Û½ìD#’ãQ÷V}§þòõáøR§žÔˆ©A©FøíYçe8©X”ª,•$&+‚ß'æ*¨ºÄ»\)Å}dE¿ù„ET’S(=]½"¬‚˜*V0˜P iu4k–›bªQNr\Q q¬I ñªžVh=2Hä©€m "&Ž^žŠT7˜Si<Ê;7­ˆˆô|•*výZ=äPü\\ ¬ùñºRe£D³fZQ‘u½<`û^à §"ÁbÅ ÛZ.(‘ÙÁY:“v Ò®i—8£ÏA(k›,84IR½ŽFvà=ƒ…E;…ÎUëÕµR‡t)eÆ­Œ“vb#`’a`"9m{?аÛ=®Ö:AºÛl÷ÿâ_üÙýí݇Ÿ>|üøq¿Û>=îFƒS¹koß½yûæâÝ»+ùmËåR3u4ækF Y7C¡W[ª,;°„^±+±Lg‰›53öƒË=|’¹åçŽåwJ5ŒÀ¶¼»Ž{C¤b€/°ª ûü¬_øÇÝî™g¢ä²qõáî~õðp{{s}£´ºãáþN˜ÍjµßlsÝ\K™ŒWÚãòãG¶l5õ ƒ„7L“O† ýq8Öät$Çï Ž5 ±ð£96Ô ¢+¬‚ŠPÍöWÒ [Óž"O^*K¤!]'ÉÂë5Hiøºlˆ’€4ÄIX^‹¦UÓY,4XG!Ò†‰`ðýgÿ¡zU ;Ì@ì¡€ ¸Ôýô¬õðð Aˆ¼Ì‹‰ù„ôíQ˽¶„uAW*%Üÿ•5HxõΗ²ÅG¡WìUƒªãÚ“Š²¾†ÊPìá‡[ÓÖ`ÖáäÀ?£±d0ˆF!bÀGªµæ¥9òP§j¢[“æî Ã`$–Wd8õ¸jd3¯Æð š ¬4(*"°4ÞÚiKª$µ)¡Lÿª‡›"ÐøVœZà°ˆ¶Yy X’u¶£s»°^Ý?ÈWØn×:Ê}@IPlØ}Ì6ÃX|ÄME6rÊ5rÖ³˜ËJ8|ãÑ€ßqâ'ÒçÜ¡“Ó6óCo#m˜xx6‡¼‘x“V” kH*†ÄZ@ä ›ŠÚ`¹ÒÆ¥©õúþöÏ‚pujÃõ6ûmô’9H<,«&"“·,JØCå¾®öj¹;Ó™6vi ó<-“ÉDlxÜMDó¤²å6SIïF=\•uH ª%ïMæÓ–zÖ‹‹&\x{Zß?ì|™Mê€1RãÏA–æ>ž8E)5aU£n—v¢#Ú¨Hù£–N–óc KÊØæ°z5šn‡D¥5)AÂÎ͹¼ Š¡Ê ýlJ]z/ÙÄÈá1ÄÔýàïü'ÿ¾¯LIfÄ–û+ÌΓ…9Í(7ºÝÏÒÕ‘g“Jq"™ÝmÒ©éZžÕ„o˜)$Iìõ+ڒ°"CêM œl×â/³jö ë%¤mq?!(µéE²‹ƒ 3Æö²PšH¯àõÏébþ5è¬dÖ¸jjõê‚ÄÀ¶±³)E$c“&ëÝB(þ\ û%ÑcX@«Ž,@W‘}…Ó+B‹Jõ-…œ;? ^m±¼‘*ëG6¼D‹•Š {0Ñ…,i½8›mŠJ°z€dñ£J( µ0œ~T-K«j%•þý„‘ä~Üð¸Á3¯ûlv·7>|Ö,øÓ?ý—š'ן?ÝÞÞꬖo‰ÏÆïÞ½¹¼Ò9ÿâÝÛËÉ„O€r“ÔOF£3‰“Nûi.ª¹y³IKfZvQ‹{`=© @¯@Å \B}"AjǼ(,älB?«„m{DÙM!dW‘1ï!@eûÈ÷@ü­òKPEnAyØÇ31—ID`²f–û_$îI„„}kÀm"ж%ì5oÎf '7gª°  =Eo­‹m4%/tw¿\×­À°&—HB`\XttÒí&¨sH0“Zírïàszg-³FŸ-)è!#BŸ2/QªÄè§¥hÁll#¶UaÍ…DK! xÂj§G!µäñ@¾\Ýk±‹l·[ù â$!†’ÆÖàGqNÏÎàMóZdª/-"E“LO&Ëà”‰GS¾<ÌcUós„—ßv:äJD¯­I“˜g…öZèõOÛ–±c¹Fö]ž¼K ׄnTŒ4¸ARPÖÑŽ)¢×¶«ûí¡„¸giûÅpöúoÖÓ,¡\h[;ÉÈÎþô´Y­ç‘ýZj#¡ƒMLf\DQÊ–×¾éçáÈj¡ÙîÖü¦*ohñ4üÓ©ô[ï>úüp{ÿ»?ÿíOßÿø£Â~øüñóͧë»ë›ûÛ»»›ÛÛÏ7·Ÿ¯o>¾ù|+@ÈûÛûÕV»Þw\©ëvtËBË7\Zï ÐÞgΨ¼¼[ J™;NEi° ÒñTBÔQt¡bÐ8-VÙ@‡<=qž)3«¨‚™Ò¯A'Wx…:"™‚-¯1lzçÿƒÿäoSƒî•!ØäåîØÉô¨ðüVçKGÕQ,kªTÝhz%!¨·4¹¶¨1î+v…¾t*Øë`{É|\Û¶/¨ )UW¾l¨–˜ºjY“EÄ LØk›“‡Î< X $/9„‘œO\–—¹ácŒ)ƒ°>!§r™/`"ÈÒ"ºô@c¬«&/ª(ïqL‹]œÚ¦ö±ð-ù²ÑM< âkåàêÐø1ì@ÄÊ?OfèZ¨Ù)›ÁðÕŠ3øé¿1ÃýJJØLhØ4èv“Ëi¯’TÒ±ow´Q GòÕ4ª¾|UY¯QE•.Ñ‘ƒàR\!ƒP’Ñc‘r„ÎÁeÈakQÅuºZà4(Õš_tn’2E^?xÖŽs}s§Eûw¿ûƒN‰îtV³ºÓùüœ¯(Þ\/ϧ‹åôêò|<’ß6çE>~Qžëm ð”,SÆmG@Ë‘¨õT²d4„0N3º4ßi)E¬=Fh$4tµ ë…^†f™cŽ€±d0êÇ´D ÈY *Fw Û‰›îH}' Ci2P% *«ƒì¦Ø„©Ô„qAÇÐÒÓ¬F€VdªÒdx%ªŽn%d_‡¹™ÌPÉ¢¢09K’JÌ7ämpšOX€õMÈhEQÕ€—ñPÚ Þ5z¢v'·'( Œ{•€rm£Ë0à%B•±O7NAæóöË56D6CïÌš>«-— ¸P é´ßïQ."r 9© 8süL.ªæ#¢eÉ9Å ©û»È«X›RIgNòÛf~«‘ëm³i´ÒÆé_ÑÂå:ØPuÓ’ØèmÐ ï¡· éOy¶BûLx³Ù®¸‚cÊW½KjXJ{š‘4±ØHóÖÚR ߆Cob¾H§Vy܈[j<ø/ökß<DB,/.èÀÞïSf m;cq÷\\̽ä~Òc¿÷áUºÛîîon÷ÛíõÇO뇇̓ü°v½Íåû öŸpòùæuÑÎ-ªuF !¾œŽZmÊ%œˆ|ÿ—¬Ý Eœc¤sm hŠ86é ØÃÐOl¥)†'"ÜBv4*hPXã+eC·y$Oê\„‘r!U¦›*üÿã?‰ªÈ#Ý9Ý8UœÄÈûÆc^&Ö!#Šg1ö) }óTçþ( ÒZCMãpµZÉ©–+}¿zàâÛš+j”òÿ}±Nm)¯®`ê©uùô(ª.é‚+þI_¬÷„âe‹’iÌr¨CVP­Œª*¥L¦'(¶¤^ N+FÙ<šËR0I¢@¨ƒ”1ˆ €Z—5‹”ÃK +ñ BÓ±R+b'h)e|`°"8MbÉ<•î#ñiœ*Ï“¢3w'HŒž$(Å%Ü”Ž@Ò¤Àû># ðZªØƒÛõlîši¦$—…Ÿ”"¤ŽÞ‘&HäæƒéX×"+PYÕmp™]ü‹Hå†VHS úÚÅ ®ˆ½C“†H»-ž9î\ïšQÜþ|>ÝÑöÙŠçwïîV>~Úlv¿ûÝï´äÝßßmÖ£ÑÙ…Nñ§ƒ÷ï./.—J¿ys¥%X§þ\mãÑ>Ù£˜º(”(ƒ”2@ÄK‚èb#» ÓÃgLA PÃÂèb”*­bz—’~ˆ­\ë€ü"dqqâ/ñ9(G© z(-!±zYÜ ‰É]¡2ë0·ÖL(£¥˜ÖV¿;QsÄÙÌ”FÓͲ*‡wWÅ2% ÈV¤2%L6G` ’¤Ýj¡¸,£¥ õ ,Qq6ÞÂ:€7Mì­£ÛÙL!|‘”NR7Z  Qè_Ë-å‘þJ…š_pkJ Þ¯j£`›0 M,7xºóo:=å]‚áh:ñƒ˜üOä±Èaáq^?ä*5¿SΓiNË!p¬çÿàìTdšac>2œ/æü8ér¢)ÿV¦?´›‹‘–Yp4E<äŽÍÙIE$ZãT Bë'Ⱥ »!Ïí±ïñª÷µl[Õð*ñÛâ’ùÚ Å>ÛN’㨱ÙÞj™VÙÍ•&©…çD;0òÈ‚„× Ü(—íŸ -±ûÚcDVÍ%uíõb vÿtf‡Rd»µüM~ö§~|¸½ÿñßß~º–w{»•í_ƒàÞdkûsü4º²¼æ¨sÖ¼8/O›×]÷\ô;{´ô·±Ÿ”R˜ÚŠÍÆ! (ý)C¹Ä£ÉcI¡K8 ÑièK™¹Éu·û+n™µ eΩ¸5‚×Ý€ àÔBø•$=|Q{uìJ…¯´›‹9ÂSЀbäwïXWýC¢¼„…1Nué½,„ÉÂÔ=ž‚T„Ö/%(ƒADàåÍÓÞSõP…ŒcƒW.ƒ¹'å¸ðA¶¢–í³pˉ =÷?„b°á‘ôTªtqK–D25Oé“ôÞ¬à¡A—p÷†IeÊĤÃ[IoIÄ.‰r^(ô@vEã lŠÛ.)q©IwD¼3í"‡éÙéH`¿?´*m0ägóý„»ý6¯³?iëPÑà÷ Ëuãát¼½áD~wHü¬þÅyî“ÊôMBMaÜŸ’86°?©ìÕóÍdŒ$4!ˆ o„ŸuàJ¡`·Ýú¹%»&oسÍ6¿•´ü m]¼/ 'i¼óS¾â·Z?Èk[ÉQûñ?®ï>üøÓÃíÝêžø)‹­²G9dòϸ¼Ú*–‹¦ìnëmÝŽîšœ6‹!zI+ݵÑ+Ú ew ¢j'½² —Æ΂m½‹<$¤x3ážj$N¿À·%ôßDH bX‰ ˜¥yöñAêÒMô#9: ¯æ §çÁô?ýyy¶€W‚tÐÀöESnwòêÁ ÂH­s_U`¯³@U”T=Ѱ0àlñàªI%‰Ê¡Œ"4âi ‰­ß3µû¥$›£‰ °—Ç“s qû„ò5_drV¥ÅšÉ &ëíÒÌ'ŠPÙ/¨$r:C¯s ×1vâ>¤rõYÇJ”é®/é(SÜqvGöøTqSô·ŽL‰CQˆ™ñK0Qꨳ\A¡À†¤÷‘j:b$Ni YˆZ©þÝ­›Ð i§ñoÁ…ïõ¦[LÒ8†£Wûb|W+ŒNYÎQ¨}ª˜AB(ûPr6úê;q…µ9Ñð4W`ØžœÝßo6›ýÝíÇŸ>iûÃ÷?è Uç§ûýz2>»Ô)þäìí› ir~yy>µ'i ÊëD°æûZÞ.‘Š…hÔÐY¥b ¨¸Dµ:¦gñ³ú$¾ìà„ÖpJK}–Ãf°¢–²Ó8] QÅitiê `ֱ޿`#Ø3 ­ErÚBº€Q[Iã-z•<ÄfAÂÈ€qŽá˜êÊŠÖÆ1t X‹#ÍUÞâ !¯ËJ8 M½„ +-Á‡¸OÕãˆÆÙv|z œ NrÝ¥…}™Ç#·gWv¶#æX²È6ŽaþI1Ò±?ÞAªD0ífC…õJvºZV{¼×HëÚT _®”ñ}œÉ˜Çð‡ã‘Ú&¾ëÊ ‰ü*Ôh<Öv5äµP¶>¾Í6ä¥Ruíev4½FÍ5ÿ þr1Ó <_ˆöûwKžNµÉ‹Q³jýq#°—µº(¡M¢ HyNªÙ¼¤ÒSœ4î>e§ÓüW~_—Ä Æ’Ò”]'Û.ÌdŒ8mŠ)`Gâ_-ˆšTÂ\Ú°…‰6kòÛM’ªE<;ö_{Ç~™EWë”c¿ÿô¼)ìq·»»¹“£v{÷ñ§»õöîš»¥Ü!åu„ÓÁ³/cJ`© žB–ßA2€wï²›#F>/b–gd*Ãwe±vt iiÐ*´^¨J§«iÔêò1q+jŒeã.<-t}D[5ünX²Fi{@Ú°p/ƒ—Ö§ÿ—ÿÇ?±ÍÜÕQõå~)¡Ñî4<<¬ðÜÐÙ ŒšÛ6Ô9=ãInÜh$Êø¾¤æ'IÕ´¦„œCˆ¹*âjTäï# †“Ñälpr~yÎEL§àn#<æ ø”v?Áoló*MÜÊ@†2qa¥³–HsõG4´…(kEk“¬ÆI æy°^¸OG)(âv­ ú4²x¯Ý )!¥n‡IÂ$Œëò¼ ]çvÄJÖ¨VBÓÅN0¸ÍÑêö8M ˜Ž¦#S‘dˆž²ÝF]4/(ÅÈÄÜ7éJMë:H’P­{tÍQ$:2fD nvuYÓÕ•4˜µê*醨#<Ç ÂäOgÜPX K²€©?)Cš3„(ÜH~X˜¨ _Ö½§ý‰º_ݦqxƽçÑ?ÜÜÞnøáÓ÷Ïþt¿{þ§ÿôÿ»]­6ë‡ýþn1?ûwþÆ·³ÙÉßúw~ýÍû7oÞ\üê×ßiðëô8˜(œXä´–J!>*Âé¡Ä*‰MéF¿Q(À”³,²@‰X€>¢GeŒs0¶Q¡U:ÓÖ%sö& ¤I‚{ ´nËt{ êŠFVX˜¬#г°Ñ×1*g•`ŸÖVF“¶˜:Ææ˜=¬ãЧ)VÁÙüY 4ü¤Öµ˜Ô8qËŠxý?¿-ôa-+êFJ@jïÁÙà†ÆR“¥e‰ÍÙüÔ¢ÑJÃÎ¥ëOß¹û\¬©Ä'¾X^”vÓˆkró,Åœ¤,@„ªku×Qã„ÕM'Öj©í&áY-¼Ôc¿å×+ÐWâÁ4EL¥ÐªgÇGŸª›ÍjÕðo­>žl×ÛGmP¶zy»Í^;>ä¶ÝîîïWâ­íH´+m71òwDéW|­KLå'Ð ? F£él¼X,Þ¼½zóþíÕû·o¿}·àG烱‰$ÿÄ^ÇZ¡UˆêO|ÐJ 8©Q'Ie©Í#àÒO A.IðíÕn»ÚÞÞÜÞ}¾»ùøùó‡wŸon>ßnV«Ýz÷¸fåîäéÉð„/¬²SpÁžý×®« oå¹ ;”8‚*£HäÏ=NgÓùr&½ø€íl*Õ¦ó9—µýNE0ä÷ üá­ƒþÐK´D¬¹¤åfÿtýé³ìöÓn¯¯Wßÿƒ²·772 @š­[wׇyBW mð”ñÇvu.:͸D:žŒÎNǃù›¥|ÀÅÕùpÌmn‘‰O˜Â‹w³ØBjðQÄæ“%‹‰'QJtÏáÓÂɬJµBϬVƒQ–2Wà !Š˜k¬²ªÒ]–R¹CãeAÐzì#ÐHPÿg¹•÷,„2‚ŠH=øOÿóÿI|ž„@—hÀ54å hp›SøÁ_ÿŒWF…fláÕ¤§.W3•Ì Ó0ǰ±LU­»jI _¡Æýc\ærª/a5¬ù> ã[Âý‰§#±LNYÔˆœÓ¦“ÐÇÒ¢6 IrY ™E–«¨+­¨ŒÙý›°â$^@šï d†V]GÔÄS’ôÉ´ºŠ(_ƒ"H•.ˆ«Bí ¯µH•W!|üJ§M*7Êá¯YEo1NGÓùtº”3Ÿú{ýª2s~÷,ñäqÇÓñ’XqZ³tN¥aå0$eEôhÓfÇU7O}.¹áMîýhöäbO©*§aÖÐ`­60Ku…¹’VÀ‘±c­]¦7%¨(ׯP"w0·ŸrãæOݱóòš§rÂ~³ß¯÷»íNž¥¼Þ›O7÷·÷|g÷v¥^ØnvHEo©›Õ=Ä­EÂ]£­L"€Á1”àîZ&RðøOLÑ>ÃèQÞÁöqŸs ©³Ulø6ˆMáÑ5cÀm€7¨(¥ÐSEb.DJ©*NtUZÍŽCØvÙ€s«…°p0=4©ž<Ül$k26ª°ã•¢ÿûÿëÿJ/E´[är®”I¹ª¨«„Ül6AÆðø¸UŽ<øs`Ô¢ü<µ‘S[¦ÂàL¥œå<ó¹?¹Š“I]oÓ(’³…“§ÉxÂumZFý9žNqóμ¡3&Ó3š$ÈÎFƒÅlΉO$*žú|¼\ð1RT·£ñmý6\bë(2N¸3l‡lLV4âÒt³j§M¸@±Fõ ®]¥ ‘A jX&ɪøåõ6×s 0¯e1 Q˜ÈÜfiºÁQÜ5§¸AJòÕ¥E¥ú«Ú>ÄtP(×4GÖ7AGÓ%ªØcMq­@–?ÚzJÛo…—ƒL2ÛGiS'¢º ¯Î`ͤ…$€ \É‹ý .7‰i´Ö€#Ó±d}I6*vY³'«˜¼Ç:š¹¤ù©V–¸§Ñï~ÿéúóæû?|úgÿìO÷ÏÿòŸÿén·y~Üžžl—‹Á¿ûïÿz>=ù“?ùÍ7ß\½}sñÝ·ßj"Í&ËÛÆrá|éNLµÚí}÷‰öa/”–t\ï+ɼ·B”1-ðQvБÉdž$ùAj‚H}ب ‹ÐQfÓLJJÿ¦îÚi%—w¨Féz Ll×À|h혌À`u䑱f%œL¡r"Y€!T„Q‡0D÷ ´#¶tY¢$l=—Ë@ ¶—DUDÔ ×"!ˆ!TJzº.™ŽF[!K˦ԌHtZÖh9= ½;Ð@œX±Õ‚&› Å™§@u•Êól»äñÒD{R›®&ülV#Õ-ž:ÝçR(—ß0âbÓ==úÎY@íS@‘ÚÇ`Z 'ýx¤KzASiÿäŸã¢§$†VÝÍj#÷BBj÷ýžëj¾Þæy÷w÷ê%3ù7 ö«õZ>Ãf³õ5æ¾´šÍfóùüâòüüêryuqyu!×m:›œŽÎ$4~›蓎£m[Ö–²È.COGƒ{eÑ ³Kΰß<ᬭ¶w÷wŸno?]ßÞÜÜ~¾{¸¹[ß­Öò‹îWÚ UMíÈŸÙ{šÀó"‘qÑF Wœ4«ñÀ•îØhÇÔÎŒ÷9K»Ét:r4ÏØ‡§S~9i ´ÏjÍðL²‰Ÿò!° Ü÷øƒÚøðÓ‡‡»;y›ëÕZåò5i›Æq‰Ø…í,¢:<˜F¬'FÓƒÒCi\ïî<}8ã hyœŒOO'g‹«åãàäí·oG³Éd6].—¢H©À->µÈTß© 8ráÓ»Ȓ«W4a¡§ŒŽ¡)_6ÃxÆŸÊÕ•5[± ƒ¤`"ª˜Ù0âi +"Kªz[$××°ôx“œ8¬2^WÚ¶ ƒÿôþÇØ†€ st,ÚÑ JÕ¢9Çê}:»GIZ"c†Q[͈‚\4^—P¬œËù"Ϋ‰…|^ó4ËÉÇO·wwëÏŸo¿ÿþÃv»ÿüùZƒöôäñììYKÓû÷WZÄÞ½¿<_j ™-Ïå±±Zi¼k}!xºr¾Ìù$X$°Ì[ž„Cg*kAø"5xx2ECƒY¼˜—ÈôïÉÓêržÞV«Öle;wª BmÙZ’²´æ“P`²:fj$ ±1©€5𲯇9¥ŠR‡"Çû  s 3óºXЕb¤d5ti‰å¤‹Le(š°*‰t¢7Â1X³h‚úuJ©[t¢€”É}Õsíè¥Ó°)÷¼çYi£Ã pic"^9iq¹0¦XlˬH­^K¸ÂÀî—±¢Ñ9}¥\ѸºÛ®2Zeî°V£)btJ%)Ã6®sqnâà"à´Žø ¼Néy˔ߒŸ"Ï`¤Mv<s®®ÃòÃPÄåÆÌ¦ÓÅÔŸÛMÓÉ\NÃD”§C®¡+OÉËuõÕ*ìjù­@âˆ/@ªÝëo”†BJ9bgÆpp=€¯Ûá ÚÊô†~º@/  0ezPØÆ¹C&!PJ¹È-i=sÉ1Oœˆa!ƒq*‚54jw‚0Ã.æH –ê#¢Y€u%¯zi ̦Áì Þ. cf&œ#)à¢Bxµ¸a¦ïFk#އ!Þ>­×ÖO?^ßÞ®>¾ûáGü¶Û»{Ñè h8<ÑÉð7ß¾Áo{wq~>ç‘”ó¹OQ†v×4€5¡rê¯i FIâž@0H) ™µ3]Ñ—صØz*ŠUêzK£}s­ Ä®¦ gT«K;IhVMP‹­:E@„TÖÚLe« Ukb* ËâEÂ|¢~#¶z¶›`RP@…mç–uEb‚xµŠ´¨=ÜÎ&J/–úÇoã›ü6.öȧÓ¨™@Ïã±qÏ¿M" R¸Y%‘Ò6ÙÕÑ6Êò6 R `¥qôR싲-YXÄ +ð¤©\nÉ;mÖÌg‹j1òNê'à|g6îÛ¤²òÖÖ›ÍJñzͯP¬V÷ë~rt}¿¹»¹»ý¬ÿûÏ?mVhwÖ¦Œ3‹7FËœ¢rá‘#cat|5dL_ÆŸ+i£/ErÙ¾SšÚ6ò™VËzFgƒÉD~WIµømªËšJ¬æ£*üm8›Á¶Ä6]¶â· \O…FPº*¥Ä0 ãv8‘ -1S‘y¶5 è/]lÒ$80—®é–ï˜òd³ d€s&mdåMçcÅ_‚éŠ ‰_ž!–‚Þ Ðc •ìV¢ìþA¤È¹€&œrê&ºíòõ °=‰’xµ4HW=”"‘ÁÃ9A–½€zI²¤’ƒºÛ$Œ†ÈJÄ/Ÿ¦R¹ƒ:Ý©C»€ÖÆ`ùmaRE†Ãl ˜|Mw(ru·GõR‡SY摦™&]Í·ýÓ÷ǟ~ú|sóp-¿í‡›o7<=k–Æg³ùà»_½™NÎÞ¾¿\žÏfì%3v¦ÓÁ3?à©ÍO¡]o³¦–‡¦³n!X_ìÈÓÄ‹¦‘9V¡¶¹H΄·pnÁ¥ÇxU'á*ˆ×Ï‚Öó©²øh/hº æêÒªR‚Y™ÞU¾èT‰ Äp‚!Þñ‰²²!%Ô¸/äLé0à´ÕQõ¬Q&‰0ð±š&p»‡PPdÐ9_CôÀÅPù‚ÊªÅæ·dr· ,£4 ©ŒÌªÀÓŠ­yŠ¡k¿Jà.5abÝ*0yq6öÛ$qÔ1{2ßÚh„çÜž“{®àºÕ¡¾À–‚ð4<¿2:s{p<›Ï&³é|>Ub¾œ-ä±ù筦܎g| ŽÍ ÿDʳ1éÒõ˜Cqþ:}ÂãÌ:CO)Û`1lK@4àN”½Aœ®·Uk*§×Ì„)_>rææõXk$YÙ¥’xò2óEbœ¥µLâ…ýj‚¢ *!³Ÿ$mT6 Vm­uÐèͱÀÕ0`:¼Lš@Í@d2Tî5x‡=¤$¡Ž„H•P?dæc¼ãÙpiKmG‘´é¦Kªq0'¥Ô@£ [B`ã Ü_ƒÞ×¾n‹UT¡' 2h(Õqr«´Þr%¹$÷` åðx!Ã!•ÏJ8.TˆÚì8FcQhA(å3 cͶŸ:q¦¦ïB)ݤð´ÞŒ ‘¼®c”©imHg,+i2/H0ÍEaË! ÷"”•,ƒÁ©v'í]ÚXäÀq“t2ËA˜ŒùðÇtÌUˆñ™ ª®¯·©=_i#VÖmÂ]”Ší 2ÄnÄé2SûˆðVƒzU4{m|^ 5·ùŽ"Hûa¸§âƒFÒ¯¨ìáìqø:PäŽÃMôîÙ}g ‹K$\çк‘Çòóù\>º¶ãRÈŠïåŠù%‚›ˆ ¾û‰ð%—¶~â­[ d´”–)—Í´›óEÕÀÚ\åÒæÙèl<Å]¾¸ºPG(Ìf3±•‹-ŸaÏ ¶a-Ì)ÇžÖ1Ç>|S% cºVèbg†Y’`’€½‹:âŸ(2.•b€Èo+áC@ïWJÜaM§çÁÛ¿±Éãi'öGñäá(äGméºÏȬãÀ©÷„WUö{™W̤(îÚp8j˜g¸æ¦?ÑÊt®QÏ·r|=ŽËrЏ‰Ž5^N}KTmçnúz<ÒäÐ|¥û䉯~†RWÈK£w¹ Þ˜‘¯.óµR®¶éTÁWÚP çY’Ó—v,¸ÓëÏ3ºwmŒeó 1wi £BW5ƒ"pÊØãl¡ Rºï·u"!<è[ŸÑÅEA¡0ÄjB„ T•—}\ZL¨Í¬SӮǓ) º´ðÄoCjñëÅãÖz&瀦¨É*q\´’J#N)@EZÐ8˜" ±e§ª²³Ì!Œ ÃHí—YXm9‡•°Ð´uÌ5ù‡þµ,qŠïŠÊ°v*$ALuÕ†[8DV ¨}-üv¹5üÑ“½L;5 ƒ@íûŸƒ× ü<ËEíïg{G×=öM½¡úæL~Ût1=\¼¹TïàNÏfr³ÕÑNmiR"<“KâôI™-ÂÆ&X@U;TÄ`ó#:˜IÀ1å!TÝ@{wn¥[`Ì™‰cêzáôèô€Ð¹vHc4x4žôU8ø“ÿá_Ó( üpŸ­¡Vößì¦q|pàòËïr„T²Ý2 ˆ!ÅV˜Bc”©¨ÉÏ~•ÙcªU•s¹š ¦€åÔ†ÏV@úÒ™D™¤½;ƒeÒÛƒ¨x £þ106v'[Af2Í  äJØ®@øÃ™ãb–ª1UR:²Q¡—èÒ„Ü‹?(ä  û¸J&áJT©!k°qYÙE †Lq¨U”.|Ź©áF ; ôB©8EIü ¸!U°`^‡ƒèÀøt˜” $¤âΆI„¦)R dîÁt£¡Udp¥£8eeIÖÒ6ˆQ}§ªy•h´`>Nª²¶˜‰I4b¼3FC’Õ™‰çœËB6`P­é‚V$j^óøe¬²ùï÷Ï7·÷»ü¶Ï·7«»»õõç[­Î*éx<˜N³é@~Ûx|öæê|á_*Õ²%¾úÌÂÈ^„bÙTÛWÍýk6ÒÕ͹IËÂO(KºžÈ–W Ž$W‚Niª¥(P¶6ŠEþïqÛcÒ‰+«a¯´rŽI›ÅA¬ 51»@<ÌÇê$_Íg¥90 €¢ÁÑý~˜¦APDnž¬"µêØ8‰“^‰”&ïRC§Ñaääx b•‘aØ ¥)01&ãète¿¯–Œ——l‘çX¤€/VÈllýw[jQƒ庖ì€*Ò®›†R<Ù¼hL*¶9EèÁ[ò+Õé‹y‰›$æT†],žNtf¢j®ÁÀca4SÅÈNËĸ×qŸT/%âøFgS‰™dù\ê‹ì,g<ä=Ê_ý0YœØ.„ƒ™¨®Å‘â~¬8)—r^ŽPÒ˜Уå@«˜ j^{c“ö;N¤–?âÒwj‡E-Aâ4£>$8>¢´¸Z\—`hšSŸ±„ØðÚÿµ (Ö)& ÛæH®sDû4®ëöÄÝêI@øÄ€/¡É€ž…Éæ\LgÀp¢?D1Ô’GU?Î6..r©Ï¯.p¨åUËoÃ_`TÇŒY- J ÷¼«[U•Óþìº/È›½£( 7ðEþ;ÊŠ_ÉÔ-e«RI„XŠhª þößû[¹¡i¿ ÛÚÇBIqšô?;A¿år©\´û‡;nÜ”»-29qt1RÈìCúò”ëºøî²¡¥àª‚ý8™ÑóÁ/4¨3|ßt48róAèRo¬ž³M”LÔØ0™†óÕ[ÒGeª9Íä1W`ÅÞ7Fý@žð¢P,æ&LSÐN‡ÄIû¬"RAW>iÇ’–†DÉtÑ""Ýø4WhàÐ8ËQÿÐéèr‘©\: µÒ©—¢>x°â91l±6íF“Ã2ÍZºƒu¸ÁßUe·å " –Çd®-”¿(FWK݈­à.#k†uM†Îe¸Á|€ÔŠZ¬À1‰Œ¬®†1¨%˜w‰DΡ”¸$TçW£ùR˯Ù~J&rT)&Pдq­uúAe½É¯ºþöRž_Ï»Ýãõµü¶gùmw·+…›Ï·øXöôy‚ß6œÍ†öÛWWóÙ”GGDZÄ5C;¸e˜[Z/_ÌÈÇŒzA-%û¡Áé«ô†J ­þaÉ3AÞ¶µ~´¤H‡ÆŠùˆaͪqu¹­á`Ú2 Ó]”t£…; $x‹¦€š.Gó-:åq¢ø°,UJÂuºLhh-H7Md…Õ¿T+^ÔnîZÁ98Lg&Á™Z×`DX-½é Ä—ÁE¡t­'2ôºm˜\€9„LÿYµ õÃÓ]ïÇ왉ÂÙ²Q×ÃÔ5l²dðDËcQ`,F&4‚Æ‘‚+Åfƒi£å0pˆuæf6Ì©½—PaXPXæ|G X)þ«œLh„²Äpª¸cÏ5 ŸŽžø1ª}›M×¥* ÐJg±ÿ{Ö$K³¥ça5fÍ{Ùz @AA4%)"Èn6I“d2‚IÓÌÄ ;Ðt%3 ü2éBãÏ"‰–ØîsÎ7ì³2«ŠÏó¾‘Qµëûútƒ xÁ·¢<Ü—¯µ|ùr™‘¾§ƒsNVµÃ­1a’¡ŒQ”fòÞm¶á¿ôéy^…¹ÓdŸpN¦„9 ê´žž© Ð ÏŽ*¤#Ò7N¥{äÓV–Æodý×±é¼ åV ç³Ù7Ç ñ:‹%éȳºç,OºìYnb8Ïñ 4噃mž™ˆÛ ööŽ^ˆáN?~ýÅÑÉñ‡¯>žžŸžœžžœFm9öº¼QÄ>[ô¯0†‘îœa.²üëd¶xÍ!k¥ÌkèÔ)ø¯0íLÅ $Ù¥o4¿*Vp$C ÕðþÞßú‰Û|†ï›Zpï‘7d½Qé±s/2f^o²5hÛäGÆ Ð7ã6üåÀ"çËßi‹3J¾Á;õÝ8X.Lp˜<;8: Ý|Àšo úuT€S$™óŽ#ã-1{ëôO¿±’±e`pã¶hv*d9¥h¨<öÍïG¾ûFõœûˆeðDe4©€Jb_Kš¼xl­•º§H;VˆXf‡öÝæaGFíu‰S,óÇ-Ñ!°Y7¹! =ýÔŒ…`6%w.€æ]€’·ÅL ™2¡¶îh¥õ°íñ¡¶Ãfþ» ‘)ïÓÀ8´_£µN6O-t«âYaöØ ó4 _þËi½eø”³)Þ’û, 1ÏIN«â”¡«ªHKTÒ³1Cl££9¶k¸rÀiWî Ê˜Š²˜WŠÉl°ÅÁô¸Þ~÷ýÍfýüë_~{{swwsýé­‡{ç竫˓ˋ“ßùÝŸŸœ}øxyšÙônt"°Ü1à?SÅ%S²³‹ºÐóÒ˜4öǤárDÉY9|åÀÕdèV¥8ìÄ© “:L`¡µ.þí|‘UrìÁ>G%"dE—˜1Ù”ŒŠhNÃbšÞ—æˆN=‚“ †ž$PŸµƒ2êß`ªW[¶9I±®Ñ¿ønc  ªvkEáÑHÑL82܆FšØ£ìl „YÎW+¹[Ø&ér63˜&~ˆÓ.Eïtô)U.lt‰—ÔIâzaEhÝUM0g ùÚÆ„)×á hŽ´+czD2Nþ…çZÊcÎÚCwk”ÙvšÇÛem‹S“Ê{ž÷È÷$=i–Ç–Ãas¢QRSÜPwÀÊNÐZ¹p̺ùmV·Á<X£Ë,­Øч2qƨc¾¸õؘI±EnÙÑÅ¿} o 9NÖ6•ZN®ÊņXã©ký9›©%ÿ²Úý §¦ÑYäq0¥ï*lîe³›ifl’j¯­Mtý7¦Vµ‘@9ð‹ðƒe¨ñ !M ÜŽŽNV~Ûñdutz´º8ýêg_Ÿ­.?^œžø‘«•¿— †a`ÜÙãΖsgèà0« ƒ5¦…Ëla²#ö(½Ž$VÃÙØPG U¡èžÓe¦è$nJQù µÅ M™‹ƒE-ι(ŠÃí÷ï$àÚ=7Ýüù6ŸZ6˜:8`ùç Ãô!/+àLCç7|Q óå陎Z2V?ï¯ ×ž|‹¿¬¦-4gØfÜæ#šFƒÊBB;G‡Diœ‡Œ­2¦~JÎôä0w¨5†Þè-ýÒS”Fpž#™L(>u¼2_üÔ§~º”ýÌÜsî#v[ѬLYZrAàìJ0rg%^3±Q)i™©5L O UÊÔ¼øq›(9uyÒ-*J7 ÙDˆ66Ðì4× iȯ¾ŽEh’MGÝ׆ 2ÚhìÏÜð,Ÿ¢µˆE4¿a–j3dIÍ(4¦LÆ6Ñ"¤“6ö:dÔ°¥g¶P÷Õ2%<†&=ƒgfÝ!ÆÍûÈ¢¶œ&¥‡hkÑUÙšÁ´ðñŸ%¸îÍ}¸á˰ÅûÜVÅÈ }òqYÒNh€‚½2‰(­û4Ns¦Æ3jÖBT+Ó˜`óHжyxØ~÷-qÛö›_}wwóðpûp{}ƒþ¼„zÿÇó/>^~¸:ûßù9‡éÅÅ©W!G,|Y9c†ëøðªË-°ù½=Ø8¤s Ãà×2¤äË¡Ã]ÂRyu¦gAz¢Ê‰4ꪙÇTæÀT„<^v69à Ò@šS&–—s̸F*ŸPmlQéö¤Ð—&uíÊt\é´]§¹Œ*JÐ6ÇÖÖ©}Q’jgF–‹\ûÉ2 ÷¤ÅI§£ºÂØŠD“äh–1A;R©ðkX^:%ƒȉ¾”4 ÔuÌÇdh¥v¨WÖ ÕÖÈ2 U>öÈØÕÿ ÒP•S3£8ws´ö™"AÁ´çÐUJû\„r1ï h¿¨ í Ë+=±—–UÆ$T%²é^ ¬0®„é8Ré«}w²ÅŽ©wð«ÙªmÆè¨)’3aáJCnž^œd±ƒø…Ñ;¦Lz¢6=ÎæëàÈþù†·hqêÊ’¶2‹jKYÓ¨¶—š,c†;–è=9¦£G«#³ÒÐ×ÍÓÖã?âH"òÚ5. ïäîÞ¹ÐÙqÙ®*©Êøw/4êЖC[‡P¬KbZy¥U§¹ÉD£®¸‡Ðá½üB¿q¾ó[ô‡ûLJ'çgœ¥O/ÏO.ÎÎ>œÿô?#sz~ʲFÜÀñ4:c+qe:…òüÆ…ðh+ÎÎ%fâƒa½ßu,[|¨¼Ä~¾mBtGò3@\Övޱ–lDçü”r`È×®©²à;ªÃö^ÿö¿ó¯Ïøœ4¿9@܆Ãè0½¦'Þ>#n˨3É}ƒ±©Ïw¼ƒ:Â5Úz~9`èé¸?"OŠõTÇ[LÑ,éKÀÕ>ýT›SšgKP.?g’¾#™Í–*ÓlÓ±ÉfëîØª-6üˆql…å‘“US?4;³¤µBÏÌÄZCP“;P«Ã$šÂé†6i-FS8­iÊûÙ±»¼,¶è={RÇWЧåaÎ4Áìõϲá ÇkPö"B¤t€Ý°5]Ä3Ìé=g¸C"6Ôr2LÄöòø´QØþÛ¸VCUÜlõ 5øFeô!„©Íéÿ04–Ï3Ù“I á”QƒN)VØB%=XTgÂå–DžÖeSÏ1bä=m±%zóÁè?HzDÄvtº:»<#svuñõϺ:=9ZÃÌÀÒj;¶¢ô)ãà Ž¬ØdŽàáxÕZÐf˜5Õкác6N§sºMøE!Ž‘ÚtÎFëH ¡Îóöl;%¤å™0>ø ÝÉ“ú° Ë£#žTôð÷ÿ×Ûo9½ÁEƸHñä”Pw•7’œ‘@<¬ïîÆ—Tîïný¦Šßvð#s¾³cÓž'°dQV,eàhYPhlˆòˆÃŒÄüs"Ò]—ó 8¥wãÙ3é,MôÞ 4ïÓ`?0!Q ïç˜ÖÙ™ëìÇXBe•CE. m‘ÎÊà„dVÀ.0Þ“ Jªp: µgÞ˜±Gض<g.’g z 6¸ŸP™ªšP¢­¦,Ó¬+ªÒ¤ä ´‹iϣѻ¾õᮓ?Ž2 ¯­i(颸˧×xZÿOÆf7ç~:úG®™ùàlAEŠvw É(ª¤G„‘o±6E…½Ð‘¹æ¥1›ŸÉa¶·qšêÈU°EfÚÖSˆƒ©¯{Ýr ’ÎÕx®ÄSœw{fÅt×½Ùž¯°¶hlv?ÅÜ“ªZÞ4lœB†‰ŸžIm ¥ìÖ‘9F\¦j‹uán­*çØ:^•mZ(V6FÉrÐLÚ~e Ä[m^ÎÃLš®zšaÞpRä(Èg²’YWh3mtÞd³Æ"zTf‹ÎÕOY=*‡i;Noô´Ôø!>“*£Ç– pçÈY4› 4u[ø¨.ø†¶|âÀHÎWµ%9¼øxy|zzñáêüêâälµ:?nWz `mZ‹æX5ŠcËð×ižñÓkR›*ý º! ZQó˜ɾŽuñCùÁL¾w×Z8ËL ÍIÀÒ ò;»b#ì‡ÿîßý} „B~h߈Ȁ —IL—Ûp„g~2ì4wÚ8s,o³ùnê‚ä~¢h;ÄëœgüTæþS?Õ–‡ªœŸˆÞ·¾`Ù›oÞ~KñKæéå¸{›íëí[I{ÿ€øÐïøxwÏN›2Óg;h?=ºÓ2ã€o4¡~µ‚Ë5GwÛMØã»|­ç¶m§ßâôä œ¦…ÏsqPæø;I@n.D»ÂvOæ‰,‚™èJ"iÆyTÁLi)3.|B6ôn;ì}@¤µA­i¥&5›4üi¢9Rv¤ÍÍ)1 øš¤ÒZò¤Í7]f н¿PæPL£IU¡ ,L–S‰lY†wvÝifäèõô´;Mµ5÷v0ÿ”ÂëæH§4”c;Ü69ˆ1¦å lÎ,xÍøPçåúáñáþq}·þö›ïÖ÷›o¿ýöîŽ23ˆ|üâjurôÕ—_~ýõ—§?ùéW¹åÌáÅl÷ret0‹'­Ð´dµdL¤lV…î³áXÌÓæPìËÔ!u4¥È!3»tJÎr¶’¡^+ÿçPvdK#ZE…É‘ÄB” J©ø-ú­è碓-‡¡µ•jºcŸ0r8S´¤j¨¥ØÌU7Ž`ÏMæhÕSó„d£.PR«òh5UfÉÔˆè£3Æ”‹ 2 yd& uUÑ}r&®`̆ryfG„„ÖÖ—cÈÜÛžç êíPƒ*¥©Ú6t2eýl¡¿Ýè¹`G'›Ã‹¼šmp¢Ð¥Ž…¥Zf¸÷dwôð‹æR»Ëö0%3é6aÙ ksUÈ‹¶åa.&^«´“cŠúúV§ŽéÚQÍä¨ 5& 9óÚÇ$Eá#­ :lV“0ÆSžQ‡:áŽY?½Í÷ìôœ(yï`¯8&úˆyc"ûb€èÈÅ~}íú&yÏ\ O½=sž”s9aÿZ•!lšœ}S6 ÌðÞŠ5óÍ6Ò|FÍ'ž˜ú¿{äç™ÎÏWç§_|õÕÙÅŇ/>^^]¬¸Œ]Á“°&h^Ùâ˜%Ð{IáH'(µJaš«wB£*µæ_:7¥ l;8¢I òe›ùß  ³ùJ5¥XA²Œ‚f[×F!ïþ{ï÷x¼qeÐÃ%ü€DvLénáZã4ŸT¥¢»Ôùh51ÛøzÃøH CD+LÁ¼„áçdWKm_ֹ߶fë¯OmŸ1À΋O[,á0Àäv•ô…­N?GÙ¦õhEÜ& ’“Íå ‹Í„h¶æ?²bmã~¹U¸¥~Dݳ§œRô%›·L¼·žxIÖø=,Â}ÖNóv RnÉw<Âý6§p›qK=l)qÅNé/êÕQ}X€Õc]²ƒÊ“æIEêfÂ)jKC(S HxÁ5äÔ“•îf¶9m¦–¢öqK$3úJ']`g% F³"$VQ?»f§s†0 ý‘¿éò¨U¡I¤›e™yËÓ"P¦­çÜŽWˆ 3ž_¸b¹¿[?Ü­¿ùæb¸ï¾ûþþî>'Ø øå—9°¾þš¸í«³ó“¯ò%—¦b¤Yg“˜!€–]›wmu²¤;éK8G¦] m(4ß¾p°´ ´v‡ÐR3”u%nS‹`'4ÑKùT¡gÎ7-ñMPKÿ÷ׂ©ZAu˜zH 8m¶Z;y§‚nÉô(J±R¯jq÷ zžY“r¢q4¶¤3r‚™ê“OOC¢È  ÆÔèjŸ"·I¦¡;Ý4B„̇¦ìàÓÂ%B!‘Ÿ ~šÆá•j[ayxŒÝ´ ë’ÊüC°2T„•Ø+wF6«]-*TC4>‹ŒÉ¥ƒ!± RÎ ‡ *2ݬªe®r›$Ðá}·UY!¯!™mjÚ§öuÜ6š™"aƒÑv„ŠÔ5 …e#öQƈÌ>k€‘¯Ðòñçg.‰j8õ×pÎæÄÖë«È+¢Ù4ƒô ŠÜ·TÅÿXž÷¸±÷ƒEW•nhÒ,Œ‰—b—·&ó™3kíZ¹t3=Mcø26¬‚ æ~¦ ‘Æm„"y¸çŒ]\œ·}yvqvõáêâêüxÅE©*n—ÆOMŽ5ß´=“,DŠ!U®dÒ…ÃEèô:Ó|p¤.bò©0c› ã«=iï3Díï+6”X7mQ¶äI“%qøïþÿ¦^» ÈÒ ÞðxнÙSô©©÷Ô¤¯ŽN,ûbÜoÄçt2v# ôÙ™ó¨v>uà]f=¼­›¹ìç˜R5ï€ø EáÆG8£aœîñ°°BQüpðâí7­õ&Dt¨eÌEL8õK‚7Íxøñˆ§GràѸ ¯÷6Ã3žé›sˇž‹"'²N”Xz[J´ÑƒûÃcó¤vN“Ê*€bmtŒ‘ÑB„¨¶‘²¦”bi"·;¨å¨«q[<38²~FÁp…Í#Ó¢u¦µÖbƒd&:h)R/5S„ëhŠC3xšY¢l`Î7£þ4Qb0ìRìµ6˜)6ú>dS¿Sþƒ˜݉2JS«‹Tª\nmÈÚ©Ýæç4¼¥0/˜€FlNhNSûÞ&nËÏÿÝß=|ûí·\¾·QÜz•ã£.Â5㶯¾üú'_ùòë/Y½Ù6§è×õ§uÓ9nÓŒTJˆ-3†?' …&û”eÜ6£U`îçNI2‘þ…Ï0³HŠvÔŸÍ/yÈ, ­r!HE›oÊJ2Rdfy2z) òLµe˜9=x2æ)U*"ÂÏÍTˆQ­Ä°VžÈuåX¢U ‘(_0ç °3Ãmº@”V ²FCƒ=”qü/5 LU`ªýnº"ØéYp›±QùLÒºLÚ,ˆÂ¹4賆VÑ1‰S ƒÝ£ñÕ CD«#˜‹ÃθCEÚð@€}PìàPºúSì|óVpºòl5Jªl°r[´±É3Ò®XNÛæØ·Ñ¥’ÝábˆµÈQŒ´Hå`Ë®”Ç@…âzÿðäø„S›§Á¼b#qÛÖ+¼<1爨‚œ/Ý´'W5ÔÚu@3™óÉg„ÌP3Ù\/i™ –ÄOÓã–|¬gƒ‘¼;×Cq¶Üf{AÖ À<§ûb6V:ÝŸ_]æ»§„n'g«ýü.&-ÄLôÒo-»i³N¤Œ‚ ¿Ÿý€hî5tÅäðyà”lGrò³ÐŒÕ£ààš'dõë±JY~8¼*Q¢â!y &­%êŠZÿÿ/ÿiö„h€ºXs½ÍއdŽRm±^Úú™€'M5xÊ›MžgxØs~Ú>ç²×~—4·µýáÓíöáÁŸ²òG4¶ÏÛ¶½gbÁÞL=9>Æ?ŒïMed Ѭµ Ýè VyÍq”'¤ üÉщoý `ŽÂ}ðf›¿ÛEfó¼!N´›öT'ÓõË‹ æ:¡æÉ銊ó‹3CV´ªÚPFïGæÀ[H*®Ž8:+B%îÍôïJÌç¸Ôå“|ùq–ùÂôâÌPÄüð¾ ]UYÚ“t´DQ:AG7ƒÎ¶ë’Q9Í6Æ5)6´Ò#´6¹Õ´å fZP3a´§2†vr)3Þ”¢ùA”4Ù0ÍÔêsUõh„ŒAT¥ÒþÒMíÔ‘‚‹Ö„ä!)<*ŠfY^7T´HÊü!E?@ÉLÑiÀÏÔZ(¤ìóùN?Žã—¶{k.ž¾ûîÓwß~ºþîú¿ü/ÿÄ?þ“?½þt‹~ø˜ÿ¿ðÏŸŸüÕöwÿÊ_ùí““£ßúÝŸïïmW,ÅN/ª593Çvé¶—F”i9ßÉÉÁ˜á6ퟱ´ØÉ é×\õ0´Š¨Â‰‡­Õ‡ÆŽ×!M­ æiS”¸tŦsCËü¬*éÇ0 :³hæ™››uãüH1€HÕœ_[»²$^Ý•-: Ï@—”%fµsf†Srj³£”ζ9}h0E•ÇfùØSd‘W,­Ó>ãàÚ™%h‚ÂÙ4~ŒB‰´çún:äfW¶¬-dë[0”ÆûÐÌLÏì¬xRf­'Èü¼å ³ó“PßÔk›båÅHT°QµÉËBUã,Ó>ôÌ*Æ<±Õ06¢èdí‹]–­²–}µ•!SµUö¦píEx4­yáå<‘á“QžÌ5d–vñ´7q@O ´¨ôÔf„wÛGºÂá Ýß÷æ4.îU¼ÕtíΤ¢·#ºžÃ„„.nyûDTw|zvvpr|ùáêäüììò‚Ìñééå‡ ?Nº:Xq&óG˜Õ2½âSOL Öµõa~Fsô…À> ë§C¡.,q8=j5õZßOB;¨'Äf–@g»ÜÚ°ÌEƹ)(‘Dó0›u}6|9>9:>ñÑäêôØ žºÏ›¿ÂkudJ ¡ôñÉé1é¼»eÚätSú±1Ÿ™nžž·nëÍS·G"¯ á nœF3|¨à¼…‰'>17ÆÝOÀÙ:“qxÙ2„/4÷q»~ܲ?ŠßˆéŸ"^wd‰Å©~ÿÿüýã y¢àDó ;†[ tp,Óƒ)yëBBÝÎÔžRÑ8—“‘댧¥—íæyûȵ{.Mh½ûå¯Í– ‚£µ× 뇞#‚δÝ?;;ñxòp@³ýpw¯K´Ïä­|'ç6ßIÊ>!вC^†Éâ§å8/ÚÚÍ­·¾1x“›sN×Xîkè˜LÞöÛÛ??÷·ÏP{râF.¼ýÆ@¿¦ágûh€ƒEGÕ^7šÓ~œD?ô1ršhÔ¡^ÚXjdªÙ^Â’©ŒUÖ¦(,‡yo'è¥øÇÛÙP˜QЕeµûI±— ~²Š×A>u³â¨ÎxF¥%»Ê"c2© r4Å{Ëâœ!¥–šÁ9à œ(šߨªÇÌxÑbz«¢‡â«æ@k§é\Áé0y¢&zøŸ ÆðÓ#Ò¯×pä=ˆâCŒ·jwç šò³oÞocêû…¿ÛÛ;® ~õ«o~ýËo>}wý_üÿ× ß|óÍÝí=]÷qÿÞÞßø½åâüì¯þÕßý+åwW'‡?ùÉGÖI—Y¿e˜/tv,m4ÿ‡½ ›/ çH¤_š$ÒÙæbù›̵3ÏaÌ3CSvLffl«µxc8dÂ\Uo7mbH‘Ï-æK$c¹+½ÈÅ¡­á³hÈn¦§^‘Bšzmm A ‚©’”Zö£–’ØÉø´@æ6.„'¬“ÁÓh—{’({¤”u¬CXã;·8EP˜»Y[ÒìÞkÙ¦|Z–’?NØûmêÉ™ ª@¹å6Ú ÈϘˆ´¢ÑʨÌFs±Î†ìœ4Þâä›ÖjÛ”ègqýìÚD¿¢; ¨«Ót†OÍ©ËÛ->bóµ0“-vÕ²2©PŠU…øè9÷6ëÇ›Ow„T¿þÕ¯¶›Íƒ¡]?mŸïïïñÌúþ!·=ž`£ (´\›§v ƒR.Fžc‹\<©Éì fsmIªÙeL œô4'pq?œG¤Éõ(ÜÏHAçÚôdåËuOO/?~8»¼8ãt{q~ȉwuŒ§0îyK§ÇaF2Pž˜Äh»‰eӸ݂·™ÓX¢¤°@¾,_øBéŒÑnHØF.yE¢§°Ì/™Á\¤ª¬˜ÓŠÉû¡\Û»€”Wô"ˆàðÿÞ¿¡#D™Á†k6áô0o¤*Pùƒ¢o2‡G•Œ‡÷›R<´h‘“GD?Ø—$|>^ù‚ò~-Î{aTûÓS~&.A¤»ŒFïçÇö9VŸŸÖD~›òys. 8ƒ-.§á~9ŬZ; —èÖ9u¥Ç`†|oßïñ¡7ߌØl\=*åxÎÓ¡_VàP³ÇÞ$TgÞY¯žŒ·¶ª°çsüÛ%Èe±ã0äÍÏÇÊÒÆPç²+%·êw?!µ2Hµ©z¦ò7¢blÝdaOíI¼cf—wiPƒæ‹¹¶ªf… L<Õmn`VÔú%ByVÇ¡EMj7[¿TÊgH€<3d’ï.Œ9“qÕ“an:w¶™Yj‚_@ÖҘ̺\><ÝÜÜÝ\ß«ýú׿æŠâîîž „3ó÷ë·~qzºúê«/¾øòãñêðââÅYº™4ÚmÑV!=lwAÅÒ𸸚Ι¹XÈ—Íü#õbÊ·ádƒúavË8Á7³f23fJ3ŸƒtŒB°l·JŠAšf¢cCJé2íóØ"è‰$¢b°UÛy2cð3eN‹ä•]Œ©Þ`íq~O­…>ZÑ”]7[?ü9UÙÊÞT'5)!•´8ZJíȽJÝF&öÔ!æHeF‡b!ÓÑB™2eHz*½ZC‡°‚žZ.ý©dîTB%QcµÂr0ó‡öªjÒšAª¦¤°Ñ®Ü¶A%ÿÝuõ}nl7[Õ3”V•U:\.ŽOº 5ã.ˆ‚YOwí¼"P`*öÜëAhdž^ž} rÖ::òU½œvUÕûœ-=›y^ÐW2‡¾n—LÎ:žßl=;˜gI‹ý•Já¾vÈùŠIDAT„ ¬M ¡UVù]‰|/Á8Á íÔâìÕñééùåùêüìòêòô‚ÂéÉ™ï×õw‚|Œðüä»k0mög–Qö±g‰©h ¡û9šÂ3@±nŸ´wÊY”¹ùÖ‚e~fh±-d”y”M[ùÔõËS—H)²%ŒZε'+b5ß{r|ÌvvìïN^œž_]\|¸ºüpuõŇ³ËËó«sŒ\úØ77_\Ž2œé¬K“yO†qÅäÛážì#B€c§¨MùY¤¶wîËñœüvÅ)ýËڦΡiC쌵ÍpeÒ¢nœ!u6DìÿÃÿûÊU@¯ã ÒŒP)]{»:XD^‘évÚpÄU˜ã)Í |ï(vj†âÝHÏa#`A†Šw¹¼%ÈᨡÆ[Ï{EÔr|ÞÜ­‘»¿½'"[¯ïnï9Þß=¤]-¢£Ã½Ó³ÕùÅêìÌxìôôøüÜ_zèóMæ#½aÈmÔ£”Sh{“û»;B1"¥ ÄЩqªö”í/q1åœoh<\xM`ø—ûˆ~§gÿôø4õà ^E®I/ Éžœï:ǔ͉„%3=+sÈpb­?Ñá!¡ˆèêæøÑ‡#ÓÞVË‘êtÍ« ¥D5Œ‘OìR·s`b`ñ8J:ƺw©"J¨.a˜S€N¦ÍdØ¥R¾¨q9Ó³µ—6’kMj·†à|ˆZôŽTEG7K–é—ݘ¥ª§»¥èC?ì:wúСêy%­T 0úPâ+ŸÑ0-©uêNDç`Zgn«cY&ÚÓÖþð°Ù®Ÿ¿ûöúáþñÿÉŸýéŸüãï¿ýþý£äO†·mONN>|¼BÙïýÞ߸¸<ûgþ™ßùÝßù-®v>|8Ϭa‘Æ… N{û‘¸FéºÕN,™<Œi>ñ'cÄœ‘i†‹Õ X]ÿæ`a¡Nþ1=qÚ²¶¨[ÈÖÕ¨ªæ{55s‚´9xJyÕpÐ*RˆR(À‚6²e§¶L©6Tí¨  Îy‘š2WSjÇÜ®èNÉkåô¡E§`_W•¡–™W»P²¥ªJ‹.’9 õzýxÊê…¯@®cOƈª´<¥ü,IÍ©â?AwîTœ`ªe<–^(5ú ÆÔ¨‡¶©TuzÁ¥ÐXyEÙÔâÙ³zÐ;ý^Âà <’üô{ŒKÈ÷qðŒ×Òó÷ÔSè…œ>"æ#'*á)¢s44öËÖí]ž»¡M_ +¹ Va‡•»t5»þ™„ÿYU¶ãù/ÜÊ´=5j0ÿŠcû€³" š/ÆçoÐà²ØØz’ì¸y&Ùß±ÓÝUž=^ädÈaCèÈÐ)rìç‹òw™é„ô¹¿É´:;9ð% ÆŽ~ˆþðàÙUÏ¥a4cDÖU¶4a>®˜‹©ˆÿ,ê£,;þHfò@ƒòé±Ý64įecÌLSŒASý”랃ç‘w:Ö²Lᙺt@›T¿2ÂÁ‹öù¸öpAß3 ÿÎ5øý#ƒÜoˤÐ<ý—k[šµ*s79(WsÔäÛp-`[‹êáÈ¡ dÉSõì‡ CGMøÐZ˜ Ì^Hòç#^Ú5µ ?£Æ8æÐy$ê­´—ƒí#ò‡ô—~Ù&½öP­m ¸œ.\xQ0NovÚnÓ€Dûw„íQÖ5yÀŒA1 Ÿs©£i«™B(Úõ”ÌËW+qdúL…~Ž;°}WTó=И-üу I4óCÂK 6}žA«©Q©öh‹fÏšºr}GáË6#Ì£$ñä8 –Ï uÉt×RÌšiúK8_&꼇bm´ýQhj¹¤•øž &¤Ö\Ü ZSíDä3ÊfÛk(ß·CHT tV‡ßc,G ©–ùžºŠ«@–·¶!B"p÷Sn/Ïï·±È^º¹þtÍzúí·ßn³RÂÇåñùù9mùœtµúâ‹?^2.§§¹lЦB“ô®þŠÏÛ.óù/µ2ìÙeЉ:‹ ÍxØ\;4—z枊Eñ˜~‚¹ˆÚNÕº òØI“8¼M6 ED@‹RùÂ?ˆ¶ÝúV‡%›4Ó pµ‰"zàH7w4àâ·§Ôhçh³^’škl;sÀÉP”†ÝÈŽ%Œ-áÑXNâ[;H9exöÚ1«ÐL:þ¤j–¦ïR…˜[ TÀ-Ìe¬B™&³ãŠN§¹6ˆÅ$!·(³×¶þž¸ëEUx›*#˜ëqü@8ǹΨ6%îå,«9ËßËNØôج<5GUl™],…™PÒD6N˜é\7®rú`”?¿è›>ˆÛrËmu|z’W~œ®ØÎ¼)è ¹c¿é§ÍÕÙžÖßs»­!­ˆKÜI,­š‘S°KM‹J-J0Ô…7l±‡lÌjQ_S«Ï'M´’I©n“$g&Iè ÿ(Ú£ª‚9†£f!€9’ :?T eÿþ?þ5fÎÝb™ºḣӬ¥Åœ·Pj, ž6¹hêuzrÒæœø!ÚPÔÃNñ¡‹¬h‰}b2;4ºõ²ÿDLæý6J´=Ü=<®·÷×7÷\%Ü|ºyzÜ>æ'rôo÷÷·hZúfyN{—Wg'g'çç¾Æoê £1{B»1ÿã\ñÓÒfóHÑwÖÞû$tÜ„#¥dˆ`4ýZŸ]œžŸûú™ƒó“sšð›Ç+ï:&yÝ€]÷ á¶×tã롽ްyîÏ÷ãé“SÍóaÿŠùí‡ÿê ¥”Ã\NÞø!Ó¡©Óó ú.[Ÿ‘umy¿MwÐSødõv©lú´Ùy‡a!E|LÖIœDìM,"û1§ü˜‘¨IÍËC,$/ʉÎäqæÌÞ#ÃÝ¢ ÏL†‚Qö»LK#^Ep¨ó¹¡÷ÛHé‘m;Ùs«Ø.w%c§%^ºF¤€ð´Ý_¯··7ëÇûí¯~ùíÝÍÃÿñŸüÉÿñ÷ß~÷'ò'L0Uø>šŸÿügþÞïýËçç§¿ý[?ÿù/~ÆL;=ó­~v6y;W)–ÖIVe2^výÏ"“ÜMÓ‰gŽ5g¤¸8ʆ‚YO¡‡#lpºlEý@¦ô®PsÚ*…”Ùßâ’Aýcþ°Õ¥!–“KÕ§\.ç6è*¦Õfš–œÏÐùäeìðèJ¦’›”Ï)å^SJ) Lž'ƒ8P¶å¹Ak ™ó¤>„VùèisK1Q,‡´NÅÚöÕ½„tÄ&ð*gÍHŸ ® £ŸûFÎ{ 1Ñv<ö`dŽ”ÄŠ`L˜íEØT s£Å_” r×¹ã8ŽÄ"¥p;ˆÚ›·M,¡Ÿs9,¬­å!­ÜeïüÛµäaædÆJ?fî]Ìê©©¤(A DDc;D]1 * Ëñ—öh ³®­ §çhXÖÚ/j”JH~ìÂí.kÞw ·hOP¯R1YãÕX4’hÙ„¢«“ Œn£…q¢”«šX^s™„pÉì7Õ¨­¯¸bôwÀó[“÷ ¤ôy|’²Þô«„°ù³F9ñù _t*ðµú! ‚‹²-yX2·(80|áÂ<&õ‰''_ß±z|¸â¼ìÏ-CóÝý'ggm¹kâ§Á½‘Š~uÕã(7£mÞ´fãІ€† ˆÏek•7h3½Ñc혤J×ÿVY[bŽèÝå)J;BC{†OÉ iç E—ó°K­cîÙ©^Aí©½ßF1ý’”cÓŽM÷ÛzôuÌ4Ž÷N¦qèðÙ ›{<ØAÒvïœÑxo¡)¥òl¡Èéý)ІaÉ”ŽB܆¡SG>½dóg¬ö_Ž÷Ž}¹‡O8{ËÌŒ±&«¼ ‡Ì¯ˆp+}Æ GWk)§2ã 3‹4¸Cˆª|Ë¥ÛÏüÛ$× l0°é4Æäiéú”¯DËz 5Im\Ç1PžxµÚ0&m}Î ¬~ۓΙâªÏ,ÿMÀ4£ôl/ª›yŽÓs‘̼XÞ ,óÁŽ­X 6¿+V`Ê|޲-ñ.±¨˜óoˆÂSâXî Ú…c*1]ð&Ç$¡®ÃšÇNf‡ÛÜ_T¨blc&ù)3ýbÑ.ª Öç;ǘÔcd‰¬JJŒ‘eŽ„i¶sñiOÅ»Š@5 ;–˜µý¥€‚É;@w6¶êQÅ›NÌÝ·ÇÑΆ.‡liÿNA`í‚”â¢-۰̱uE@Þ%Uz–6§¯Yv€þî œðVÎqGÕ«ckÒäö™›K/Û@æm‡Î™æÞTŽrˆFK³ÚLc²p„Sæ²±• L³662Ì5¥ÊmÆÄ“QŒÚ(Ù¯QŠžÅâÓþÓ3§Úƒ—'"X.â8ÿrÖò|š³'ç±ã½ýÕþþê Ÿ6ëvÈvpâíàx·í/¶WN»qŽˆ¥]Ò4‘0¯í¿°ùþ‘¶œWý‘ï«å]»Òcésesüvuœ{˜¶Zú|ˆ×']s¦t¦8DSñÏÁÌÇæÀ¿™…S{-’º¥ À@ÁA‹D3_Ä,øy‘|º4©ùÏÿ_ÿÀÈÇgɸÍ)8¤àÈ‘Ÿg‰^¤µ–‚ÃF¹E]©²iŒfg£¹A»c-kE²‘rÃ’¢–!j Æi0qÝüÛ¦kB½ýÍúi»y^¯7÷wþBÕÝõÍf»õrÁ /‚5_-øü¼98x9ÊËxOO}?Hï´[mv aÐ m8;=í Št,6&B]_ ²Ùr’ï;ÃÐD¨„¤û/}ÇÖééY~:Âo0ã[ŽTЋtÛ©­º$FÜzá…kŸÞDaLW‡ç~rnÿêÃÅÉéÑÉ)–s¨i ^-xÊc‚ÇÎ~ônôCU] pi‰ÖM02µqý„1²î†yˆçj@‰\*,?l¤Ž]øç éPf‘¦ÍPE¦ •š3­˜kC˜ªÞôò “H«?Ŭ•“03L6Pï…… LfÈ7)iÑkJçâÁêhE‘”뫜í/ÏÞ­æ¢A|ú^  ü´Ý¿¿ß\º_ßnùgßÜ^ß{¿íOþøúûoÿôOÿñfóxrêÝà.û·qx´ÿ7þÆ¿r~~ú‹Ÿÿôg?ûÿs%rïpÍ“±8µ“‹œ‡‘­“ RæÃ|%䘅/b¯Ì΄Üy ˜."ÞŠ4-3©·w”ÄÈ1ô¥â¢2wZV†Þo«ÿ‚¹jm•) ¸:q¹æ‰àèõ,—í¶PÙ¦;F©xSœ±l4†îP¬H›˜¶8ó }iÆ5ôrá;œÀ¾šuj«™´:‹H òlžr’–f†šºõ)¾ÃQNÇ+tõ³0“ópðV‚)ÍŠØDÛ2“|øêœô` ( •#–ÜÝý¶W#ÂIúŠXÃ0ëPå:l»s31¿ÏÖ&üÎ:(P©ÚYgº•äµl²­üÊs^É´¢d”—^Dt–5£Û\†ÆùiùÑ×s Úš¢•ª¹×¦ƒ±Ž‰kµEæ–÷=‘x¿_^J´OËyšYä×6ývo@e™çˆñåDÞw3—æo¹ß›¯Xð¶U¶‡öô¬ÏŸ¼Ïýâ{^}°9\ÃPÀpœ[+ÎyÄÅ™ñÔË\¿qD¸qäO+2úÞ'!Œ;8 .aóç0Óa£7­&¯rkÜŽõ~Û8)¡3dÎÈ’úB[ºCÎ<0Tƒ q¸½ËL&‘r51ÿf€^!úDó%‚(ßk­B?#ÛL„vüto–²”‚ßC»µûÿùÿ{<'õsôyHa©¡UÅ$úÄZ'è€82¹tÃs@{24rÙ~(IS7z£Xù ­Ö#ÆL¶V~;lÜæ&?0äf0ý`ÞztaaF­ ¶w77Û-Asì‘YùìDc¶m˜¥F¤y™3^cîØ‘ôö43üK v~æ#N{ʼÛÛó¾.ËJ&¡ J ïÖ|1ðÓÆ¯±nî¨÷‹9ÌNB--._Uð>1 =i½y䛣ü4ý¸Y{¬·=ï]œŸ|üxurvL$yzFä§OF܆_krvjOýgèv¤ŸÉÅ™þ139þ¨‰’jJƒ‘Î`9;Çâ6X˜;6€ Å4—±O~5sU¥–) ªiD§)ÿñTQâÔ¯~Ûr5}]¶KBÎt] Ž.ïÌ ·d(1üFÉqâ67˸؀aó’Ï›/€t`d'«ˆ+žžŒÛ>}www³ý³?ûõÝõÝÿñÿã?þãëOßýò—Æ>¿8=YññÃïüîo1wþÆßøëç'?ÿÙO~úÓ¯3*×X–[§[ì´›dÙÕf›u³ÿ,Kæ[›ó'~Å Ögm†9¼Z [ գǖ§fàsÊŒ¹ÝdzÐ(ˆ´‰ú\œÚâÀ¶ÌÌÅÏà1ŽÂÉI£/UÏ$A®‡9: Â4+F¤b­‚§ƒÀÿÔøÛôÙúᩜsŠ$s¨LÄm¤Õ\ ûaér2ɇi8Ǧá6nó+>%G¥ÈéÊót‰É$gî·µk£_áWUBì²Æ*Ž6é0k^üQ6 m¨-Bi´¶)¨…ùGñâ+ ŸÏ÷Ër½Ä^b2h'ߢ©<³Ÿw³C•¡Ê„&bì12ħF,L78[QËh:(&õ€¶:t’U>Bo=·öÃH ÏFý\gUHÆm>÷Œ@ã{´+Ѹ ÙÓ°c¶¬²NrŽ[xf<;;£îÐ÷’å1U82þžn3DZÂ1Ë9›`¼/¡‰Œ…ÓÕ,CƒZTÑPV yS“á›Æ=cÿMmÄÇ˜Ú 4Y8CC…˜¸7ÈE/}¥i´˜3Å’¸œ$I˃Ø —’–¿). Í#^:ˆˆ&7ýðßþÿ z_o–p¸ûabäÓ0ÿœâÆ,5Ï&Œ”°ÊX9ç˜)q¬ÚeÕšŒ­S(>ïÛ–l1<%yäHN=¶h&__8rˆIÒúËáÖ>­Þ÷W'Îß*rÌvrâ·>ýÁÝcζ¾#wt0 ÿ8ÃuLÎõãÃq&àS¯1|´¿Å F9vú12lµÛ ²`ŸkžùÍå>nõ©×3„•ªFy~>MÎÀÃÃûvij‰ªíøC~?ÕÏ·Ÿc¹¹óSðtVעÛÓ4ÝaK<¦eîºTºŒz q¢•ˆ3•u}7ò¡›N ™Âª¯ç‰v­Vfç@´S´‘`PC¹ gð†§ERZ¥ƒ24MÌ™wQƤ¯`6Á³;žI 1ký˺?x’.”—>9¿D) :èÓ­¬°ªx2fÇÉltôññéá~óð°ýþÓÍÝíý§OŸnn®×÷÷÷wÌÈüf¼oxþÉO¾bòþöoÿììluyI$†âžkÔNÃi"É#ΦùL(O·òïݧÀ:{’>tM5³²ÿi!œ¦c›˜Ãд™ö4ЬÃø CÛ´Íé›b™›)±”%ª¤<€}§«9|.mX]6”Ty¡]M‹Ôˆæ?§€v¤¨Ú¥òƒã5?Õ ”8WÅØìHÌ©©á%ÔV5Ï|³’rÂ[Z'u7Žƒ¨F1Úrbƒ^šˆCsf)L“â¢yU´×|ËéÂ8³†K¤F@# m7 ™ÒŽ/ytì–w:‘½µÉ5”À™ÕV¤6È,šó³j~Å3›%Û–m(žV„Z€km¶”ç &›smN.œ´f³išŽ€ÔWù—™}¯Ì@xS%zÈÊ–£Þ'`'M[§»­H>¡£ÒœC¦6‘ÊãT*oÔÈï¿Hà¬=‹žøãF9±žœø“HGþ<¡ÙÉjåä§þŸœú2/¯¼Ò‹TÎü†äÁ1'¹]|HÂÁ§GØ8\ ‡s0’l|¨¥tBÏë´˜nßÃ׌t;UT8Y'ŽÅà†™Z²xϦùwü¥ ž¢ë} ŽFφN vVÞ",sžÔ2Rod÷ÿ³ÿç?ð#ƒy…K¦¾ª2n3wžÂzO{µâRl{¡;ÿœ  ŸÝS*¶„GÒb'[32œõtf_©€ŽhE‡U´‘Ø·ªÈ¨Ëò”oè{Ã^AÄXþ½¢’H„äGܶ¹ëërD OXŸ_ˆÒ¸ˆ¸ótyGýíÍ-9A2'±Í»n{û_|ñ™+pyÅ\£ 3qÞ}¼»¿7ànnî>Ý?Ü&zË¥‰÷tñ‰]9<ð9©Ìtž¢ù„GÒ 'cT“ùøå—‘#zý‚óò­†ƒ/¾øàsÝÕ±Á¡~ðWÐãß{ÿÇW¦02ºÍÄxq½4lÏík¿~  PLu†*¾h—Œû <óàª&›)mÚï2?E˜NjEFSÁ¦­"ïtðPaîj¬aNm7Qz¥’†;üK†esG@k›îr¿ä¡ICÉÄЦ¥Ä¤fJ™8q.Ó{Ämº:õö\½eÂs™«*oÌ®Ÿ®¯¾ùõõõ§õýÑÿÍ÷¿úÕ¯¾ûö×÷·×ßÿ-ÓéêÃùÙéêç?ÿé¿ô/ÿ ÇLJÿÒ¿ôϱ^]]°ÙÞh¿Vf~uÙÊšC¦—Šñ7%h1,>l³×¬öKÉ w7{fÆÜñi`’š2•ãÀ,©-Z”A tžÀ¦Ë¦Óy‹³TZ,êEª'Î;J´Û«|X¾<€LUU3ÒˆkðÌPžR™r‚Ö’±U åi µÍGnt U4WYÒÖ‚2—>3”Îqˆ"€è…]@_"*ÚèÌC ¥M•R‘åòMÍ•"•9†qÞvŽ[VT³¢¢Q¥¸=l 5£¿f&‡øß£0C2Zi žva“%hÙGP“j[µµì7ëŒ.(6¯V˜«cÊ€æ9b½=ÛÎ…ß#gj}ç>²KE'RAÑæƒš­'ÓWüñP<' m¦xx%Auæ@­ÇÚ† §¥|ÌaT­7h®o‡qÎl…Å©‡Ï›|/Çs‚ ò„UÞPŠ' ]Á¢U3èN”mxæöuÉØÄHl€†8_søPSÁž.ƒÞè Ü÷é)m;\¬WTØW’ Y€×³¢­K÷üx<ãÍÀ¤Rõøú®í㦴šeR&W\ÅÛ‰–…`[eÉï%P丱"H…Ìx€ áƒEþsêlÃí$i3º"Å9Sú¬ ,ó†™ÒÙ[í ¢*¯¼IUçÒ6±ÍÍh‹=ÓÌ“w‹«ÙüÖbÜëX¢5»(ò¼ÄQÐûŒÙÔŒñ‰2¢k6óÊ)èh£¡ÃcóõÔlÞ`³Ú»k{‡Û½£ÍÞÑvÿh³ü¸o&ù#òOûÇ/ûÇÏûG/ûù±³|EG@q‚NŒkdç0ñ¿…ºyöE¾Þ(~zÜø« ~Õ†s.{â!_5ä!·#ˆÔŸùËn‡ùyB©|jЈ,.¤›OcÚa+ÂÃyç sY(ŽA©³M÷{Ìxøøëº±8&g&½ýJšîÑ¢Ž èàN" È2®½º©€½W_ïñ>èû ËÚæÁ(f+fâ?9æ&fñO·Ñè˜rÃ_hcªF‡š=‚²Uó†EÒ‘í6ÍjÌÿ¬ Ò!¿3ÐG¤ñ¾áÊ0¿[£=…Èóß­ˆ²šÔ¢[t+ñ‡ðª÷°¬-ëÔw03“ÉäËCæ5œü6¡’WíàŸ—}— ãûXÖFBŒòo€ß„¹:Á(ŸÑÿ¢øK(ر#9 ïæiË:m?oƒò‚#8ù½åzïš«ü{ô±è¹î±¦v[È”@vÞvJ^i£Ê 2ýÁ¬Ê{;…lGÑnî¶ePâiw®™‹µ$PË(f¥'cÑhOPáRœó€…`ÙÛ8å?yªñcücfÞ"îæ‡Òb²wê»Öûž×—üÜÀ ~3síËÑË^7ˆÃœd{’Xnõ›Êsž/¥ÅF‘îЋeG`”ÿì0çã“ø)yôïVM#¨Ü‰¡ötQûõU³kT“¦–߇læÃçls±UàM”RtmÜÿ‡ÿŸÿ#Qq‚ñB®á4À4cn(ÄzÛÜ«0º¹Ë^¡*1rò˜ÞïMÆ/ˆL:•yrJºµÎãô82±E.ìHc ½ä~ÛhÀÈ"Ð|¡¼q(¼F6O{~Á“¨ÍÛo€zþûÔ»b7Ÿ®¯¯¯?}ú´^o¾ûî;®Cì]?*‹öö?|øp|||¬Ž}¥Öè&sAæ à’çg®>·n>ƒWÿœ[‹û¹šÉ=/{¹ºúðÕW_¯ñ[¿ À»¸8?99¦‹„{Ôråå)UŠÛõ¸/÷GڄΈNï·8Á¶¦@^‘€~­V~<«hÕÄ£7K/ô8"Z'%§ò)]fÀ2?ãu¢fD÷àïÀµHÚLùç¢ÓêUq§™$›X2LÈ:5¡µËÔ YæmrŒ,ÎRf‘as~Ù9óŒÏ\dausñ„˜îFzïáÁûmŸ®~ýËëëïîÿèýÿ¾ùõw¿úå/¿ûö×ë‡Û»ûëç—ÍO¾þòòòì¿øÙ_ÿW¼ßö×þÚ?{zêá3ŽM,Ñnìq«Å®:¹¢ÈD«ñr˜ —.ø ì†`HOnœÑ“ǯEF¦ù¦T{`e&3ÃÝ&‘BîËYÏÏR ŸÑªf:ÏÍw-ò`è(x´Uwn'gŒ&ÍÕÆÇ=ž6áhMã^Í ÌsU¬T±:›' †ˆTŽzUÍ]««yfn(¥Ì€L)³):K/(O×/25 NûDî·AÛöª±0½›5Àޤi4ø¹QK‹ÚŠÅ«½ßV%@©G7º¦NøË9ALS3f%€¬›ÙŽ…ülåyÕY”‡w®-Â2új6™ÒåÈÌgœÒ9\TONòÉžˆÌJjùp˜¶©$,Tp2 oš[ cOÓe0 €³ÜÆóÇì“íL†‘‰=¯ŽL!e¢K’_ÐVH \|FƨC'÷àr8ANç,Ãïч6ŠãÁ,S˜1"îQ i} IS‘Êðåm§ó€@ÐÀ´“fRÑëý63?ÕÏûzu+CÓá(ãe';Æ®tÍͶ*9[« híÔ˜‰Ëôs@¯ÎQž8QE¦ù,QÒA›`´h|qøïüÇ¿ï:'³;N6¼îæíqÖÁ>ì†B˜”΂éšnó£›ÝO]\¦F ;üî J꜡WÍbƒ²¼L$¾ÛlˆWÏdh¤ šÁTÛØk¸ˆÚÈÇ@‚6¦œïOã\úôtÏLøø¸öãmyÜI3®Pq¥DŠ˜/Ï_åÈJŠtê5[ëí2?–æ[Ÿ]Õ·š›>.œcd¶:ñ±éååöŸžž®VœbýU{øÝä?_æ;îJGìŠ:I“Ó†°Å9î“wKžª}¢ácŠÎ§‘©™'[ÝélˆUæjå›DÂM¾×°‹­­ò ´(›; „‘ù¬R”aªz[»ÀWM¢ÌšÜszSäážõ¿ÊL"ɉùA@J©š8MKÉ ³m¶ÄúÏ}Ûú~ûí·ßÝÝÞßÞÜÜßÝn·þX)#sõáâüüä‹W¿øíŸ­VG_}ý“¡º2a6Än5 mh…³1î«$fV¤Ê ‚Å\˜Ø~fïASqu¹ü[¨*謘çFÑáXâëLø†Pº«Ò[e²k@‹c«°'±0^²YJ³³==$]8s3¼äá}Ýf›Û§1ó¤ó:Ý…œåaðô<œ‰ªE´ŽóR—ÃUk[¥0Œ×sH§"ÌIpúd dáF+áÖVcøeBÓ3è)´ªâˆ.½Ôöå µ±(©¢Ö€±¸÷BgBe’í–Ð"iœ˜®M°Ê®ÄlÌ8Oè|‘90žœÖvû8¯Î·ÜRñ—¦,omÈ7³ùmŽ•ø;Ç­4 eÉœ»®ÓŠ¡fAÕ¨˜ž Ð5+]²˜´=ˆ 3‡(ô©UÚ€olÁ†• ”I+ çÀºŠì#ßj1¤&ÌåÖ¦KJ&JR,眺•/™!¨_:5ÌÌé„IЍà÷ÿþ߉ O ŒHû"Xr0z[)ÿbŽ5M«ƒ·ˆßFFÅY{œ áőޓÅCÍ3[älŒo±³t˜’Û¢ÊEc»`db‹  yä© d›÷3HÊ$V“­œŸc{‚“3%ñØvC¶…ÎŽií7=ý¸%M©Ï{§ôÚŽ¦»ræeyÚú©ÿÝ]}šð×ÖNüb ¸0Z»————'§§çggDtùîLJ‹=Íï¬×k"HL[¯°SåÛ-Bà &ÉÑÊß]8>]’Ç1q=Áóhè¿ØRéB=«3ô|¸)S7l2òë\Ý§ÆøFmSñ!ºf̹)OÝÔÀÄ7êù[;³Œ å³z™ƒé‡ÆLŠ SE¶¡jgŽhvÈDÊ4ÕuƒèÜf¢íÎ~Öƒt‚4NÇÓÝÃÈ7×lŸîï¯?ÝÝݬõËo¯?]û#Ww7Ûí£wf÷_~òÓ¯>|¸üúë/÷wûìlõáãU¢¶ø€ gN­ÕŒÚü€…‰K¾Z!æÒ;ƒHI㧤ïÙø+uG &I“Z6,ž0yyGùå_JUù@î%›†t¹1¤Ú–“ÙYë~RŽTt ã«:¹@i·ó9>PMj^C† ­­T1Óg”2ª²m° g)0/%»¸™÷íc®õ~4 ö‘J; bìK5Z ­Ÿ&þ¹BÉLа5n;Ì'4²üqú7cêæ+,ið†]+¦t¥Ñî0¦{ÓЦÂf“ï–òt {Ÿ{Œáì’›ö6g&¾27Å7©5dɨÝ&Ð{õ0°Þæš©ü8¥8Ó€Ìë#š|гe³mm"M<†?íÌ¢Äi%obõ6…¢î”­T)òïÝš—“jje›·&Iª™‰3É%³€¢#˜CUTØp-Z†¯œœ$˜o‹Rºõ(–`QºFîhcæÇ­‹x¸Æ~**3ÒŒHN1¦ T º ûåö\i])¯0z5kØ1G¼ûMß*âÞ[æºÅä5²SrøwþîßJFU¯W½%•^«Í›! [M³ÎêÄsF/ÖÒV‹iy´å¢UR>†íCu‚6o-äƒãÀ¨â46?)Z5ùFžj9/F¹šúA®?R@Ŧ©~ÆL¶'_óá3O_Åák=rÞô]~¾ÍðÎÃP‚'Z¤GLJ䙅Þá86ëÛsONŒÈ¼ßurâåKHä½cIKÌ^h½ÎDF&QZ4ä¬K¢s3u0Üß_ÛßëÙ™ÎCŒ†ˆ…ÎÍf£Ïýz˜©ä`ôôo 2η1˜øt¼ŒG7S¶­½+áá­å+ZTDaÆB²œ©ŸvKÀgƦJ\ê%F»ëDátYpR 4t1×ßm¤jˆ”fUÉDù´ &œS¡©—ÃEÌ'Ù2•'„ON/(ÊæRӵǢ«’a—"Ãé8åÓuÞ=•ÂüãºàޏíúîþöñW¿úöææîööæa}ÿò´Ye}•Ï·}ñÅÕ/~ëg\z\\œgmtòhƒáŠÙ6m~4ÎF{d´ï£¾ŽJ?~SÈŸ¾ÜÕLöhÁ˜p šÙhO:!•Ö Nó7]Xƒ5`7W kÉØ÷±IŸ[ló±#Û ˜AUŠ­š‹RÔl†l}E"<ªƒ3ÅægJûRzQ:xSÕyÞªÙ†ä’QÊáH)ršZNj² š¦zÚ& Á0ÛœGW4̵T]NJ%ºœ€Òv¾d5¾]ƒ”öËÓü1}Ô¶ êRhÙZ»-e®ŠèȨên Jœe³³«mhBóo(c‹ÐÒu:Èbøã·ÝVËË,b“%g£ŒK˜ÂLÆ­4¹ÐîŠíœ–oÔà÷dÞX>cèÌ!Û:Uáw›8KõAËÊûCS]؆ÁüW2ÚÊâé·åVJdïæbèz˜¢§#ƒ.6Yu@5ÈCsb·vFõ GÑ œÌ@ UŒ RŒÊ‰+ª_EƒI,tµ6¼R›Á'E‰ŸcIŸ(¢¢Åb®-ZôdHJ°+R›sý„aéáÿìßýŸÀ©ÉÙ8TÄ'¢˜|šË(Q‚ U[ËæC@á®è¨Ü…Âà ²ÑÉÉKo½ù;¥÷œäL³ÈÙ 34¶(…•{Œžcµ|ó ¿+¿ÍoLäø[þJéÓfMh†MÛõz}ÜÝùºöl÷Ðäú³ {~þ€ëääôüüüôôôòòòêê’óeÓó‹‹3èg¾…Æ×Ï´ga•Ýœ§',ûêF\wêËkÎ.Î/?|øpyu‰TJ:?;=?#’;¿8' ;==!RÌtÚ¿¾þDywwKæöæöþþáúúÆWÊ=<d2¸œ†u»Þw õ-—Vþë6|Å 82F~~Sƒ t6zEl+šÝ ñz6 Äíz?ÅQ÷3½™eú¦èNt0W-‰5©hÕŒA;ž%ÊSÆ×ü32w&Dk,„H» ^µî·<vÄç}]ºä¨žJç.êsts{»þîÛÛëïïÿìOõéûO·”×1g§Ç‡Ç?ÿùO¿øxõÕ—ë·~r²bêùêÊí¦#|ô@iƒYlÒä„]&zöZ’ÒoŠYÏ®÷ïºb´1ïß´•¶w‚oœü?b§zfD!Šªë]»FP¥PÙ„e~FZË_Q\ÎÛ¢‚³ø\,Þ›ÎH¥H¡ -ëÃhˆtÙ¢l(~^;r¯½s)r¯x¬rž³bIˆ¹üEVíW_PÀtæ‰ËŠŠÒ¿ rçD\ûç^ŒÚì— !Æì㸣"œMÙ¿‘ííS£ê ÞˆÌ)hC©œAÑ·³¹™¢Å¼Õ¢Ñ“ ŸãZËfîR›Ÿš1WZ!á„àûÐY2hwð(Zf´,õ@ÌI¿#˜&¥¹'j†¦YÞ2&{œ ¨pDߨŠfL‡ Ê8Ký0¨ {×À÷Q†í8é Šƒgb,±˜Äõ^¦• ýPÜ6É,Û]ÒçüàÍãì>áuíNqÛÿÔ&ú ’ _S!òj4"7‚…QÌaIdf¸&ÉBO~àkpÒªaÛóô§?ºùü¼y1ÔÚì“ú³iODo>ðÝcâÐûB™äP¦GŸœµŠXÍÍÐ$?Ä’ÐæÐÚž!õÕiš0p¦ôµ·M7ÛÇ^ó±hìTÍì#œ@,Þ)ó~Ù*¯ì%íF¼5â6C7O¢1”q}ÎMC§=À|ŸfÒ£Ž<fs•ö vóUYÌé–3wz ‘Þ:x2j°OË¥£Lß ¡(‡”7êzè9LŠ‘Á]W8Fþ‡ËÔÍF=àPŒi‹Ö̆PÞÅÕ(’ª™¡™vª”7 ª%ƒøí órúîPþQX¨š3 .4•¥ eäp +¬bóý¶°½jbxÅmZÙ g⨵Ҋ ÒP‚6ÜÎÌôÅëíqÛÍ­oqûîöæný°ÞnÖHœ]œ0³~úÓ¯¯.Ï?~¼øÉO¿f|ÏÎVeÃ6Ò\×dl¦‚Øß}ÝMQS e)ìáÒÁEE eÌ1±Lœ?€ÊzˆÌ¶ Ug··8£EÓT‰Ýd´ˆ2¿ÁÜ\„v£ÅfŠ%ñ  Ï‚Óþ‹Ÿ¥ø²¡‚<óº”ÔŒªLv1SæÊVUÕ¬X7áóZ}ä^Ã#kj êk…ÑöJ!4¤2å+ÃÅ÷$ïŠÒ mèÈÙojÂÌÄI2¯ú c(½ß}.óŒ–Bw‘ ÍÓùÙØ)926:Y´3@Y£±¨‹nx‰ùO>‚Öy¢!CQ È.M¹©oŒy7……]Y~E(mçÕ=Rv fuŽÜ výS¦:Rð ÂÞöæBû“ö3v‘³:™~å θP’D@Ç¡<ÕÙÈO›œ¤>ÍO¾²>ŠbA›)È•wÊ8؃G=me[ˆNµÙ׺Ze¯*yR_) …“fZ†G¶ùè‘6øwâE‰€|œª‚93cI/¹‰³™I[÷ªÝÿOþ³ÿw›úP${lObÄ%ªèúhÈëu Ç™¨íÌ>Ø':Íßõ Àû¿y²rέ‘†ÕD‹´¡+ýÞòþS§FCº50ÊCCÑ¢7ߌ#w iûˆ½þas=Ví¦·ôdÕ”qׂRÔøxŸÏ篰“2'}Ý?Âvtpyyyvzzyu~yu™;ogGÇ~dÛ6O›ûû;”ܯгÝlÖëÍfóGôG4M–ôèèøää”î¯|IõêüüüòÃåùÙù×_~ås×Õ¡Ñãñ¾¿qêcX:°¤_ŒÅ.l'ÈÓ”|pÇÛ§ S1Ýp¶‘2 †xÈÄQ2ay3ï¢lð/‹CÖãZgNþT”2—§U%–NjÕÂ`¸Æ~Š·QÕ&ŠäóIÊ02ÅÈ“²ÏT†—)}Šß†Ô0&œãñ(5ù {sXÔ?~`7?”I‘”±€`èà[¿9úøë_ßþ×ô«oþìæþè¿þæ×ßÞÞÜn6w‡ÛŸüôÃÑÑÞ?ÿ/þ~úÓ/~ñ‹¯þ¹þ¯|øx‘¯$xY*Ž'¶|ÅÒÔù‹ÅÌÓ±¸5ˆÉÁ±ð[æqºR.KÉ|†(ƒiœÆ0à‘² ÔWi=2ï)­?Ge ݘ™:  ÏÑ?ZÚ½lèÅz;› ‹U2 ‹KÌ8ÊÜМ!eÉ@‘ßu@¸Vd¾IŸØÈ7ûBè,â` ûÀ’ ”Jµ bD‚Ò´€8OKe)f…3JGxÆW wvpôIUǪMFsIYù#S¨Ñ9».óï÷Â4…œÄç:NiÄó uXY ‘`³j +Ucõ¨ïÃS‹Õï. ÍzÞ£ÃÆÁ’~ÕÃþÄ>ùЪ±¤¶E¶¡*Uõpç­ÔÉ]žšä8ÌÉÎÅ”óN¤œºî;² –öÜpXZ#™úšHhj%6x3ãå9C$ÍõóN£mÙêJ@1‘`R9üO3¦v¶S"YÉdLC,ª·©Ê‡ i(%NiÅÜ“rèaœÅÌ¿|exÃö®Äƒ´Ã®éÃõþÕq‹kïZq~ñÓûžçA~V“àÉÏ„%Ÿ“ï‚#2 o0 ýY2QŒÞˆ» eÄÖPÊL¢ 4ì?'"ñ¬æÇÑ,¦Xz~«êîöžphý@ãÆŽþ<)æùàÓ´åXÆN‰žlIlÉGº|ëŒßzÉ7” Ž»¼«HzzêãOC͸­Êþºš¹îN ×8Êf´åÏå:ñ“b–?qúð°~ÈOjœîÂú‰Y„aäuM"¬bèó¸5çbïoÁM¹I†-gÞUó—ì}FŒ«Œu }yob,¿Ûj<êBi\Má#é4‹÷Øð­Ã÷¸¹¿¸¿»ÇB½‡qhbâŒ)¼› 2¡Ÿ{9G2ÏÙ1ÂïLY°œÊÎöç8[2û+Õª%èõˆ……þàMq‡ªäi¥ÄìÌû˜ë›A&V_)åi:ÝiS Hsñ»…ˆD)¾â* §ëãæáþñþþñÓ§»_ÿêûëïï¿ÿîšqa P}¼:øòË«“ãŸýìëË«óWç_|ñáðÈŸ•Ã^qä ÛHÙb‘­š¯ySë±EŽb,li`ðŒlfZ Ã:F”l¡¹—!ÕvgÙH¤~§í/ mZNƒ@'FçÈt7ƒ=ï´ñÍÅRx£v䂪ó\£î³—6ùZ|‰ˆŽZ˜gЯ¹”Œò£"xמ*…Ïf~«–üE¥ŠRª¶p Å»­²ÕpQöZ²"Õ<™ä.:¬ŠþZZ@–‰š|KÍD=ˆ² m.k?¯R "MÃðzPàš6­GJ¹ô ¥a™ŠÒšt^‰jnºCmPå¤<”‚3*] uvà¨[(ÃfRõg9o¿âàš2«Lá¶JÍ9 ùÒ8‰pêÓ OÙ,hñ«­ÉXk–eÄ¢–eëBã?×6Úª0¤hÜfÃiz˜j¿ÕÈi“—‰4M¯Åtuš•%’SZT×n&l/™™2Ø-…>c‡t e²µ ß?@ñæÌP[âûüä—EPN»³i±hñ 1£ßE3л/ìÿ'ÿ§ÿ}e 'B',pj+›y”¥¼ºpëÙÙ)â§g§ǫ㓳3j ‹¹½ÑCæ+j9!!Çåmžž­|b—W½ÿx»ËH“êf="ÿéÓ­Ag~¢Pÿd'˜y~¿VòÞ!¦Gž4_;>Þ?9E¿V¨[¥U[øíÎã£eâ¸Ã|Ù“€Éj Ä ÎlÕÆ ˆ#Æ6›»‡‡‡„A7×ׄ>÷7·7·wŸn¶÷™~QÔo^ú|ÓÿùOp×Õ‡‹³‹ÓãÂ?ï ø¸ƒ<ÊÝ5=ÿÙŸýéý=q•÷ÔrŸìùþúaóhÃôµòÞßÙéÉÅ%.?Z¬ÎöÏÏÉhú|ûàm´OH‹GÂAôõÂM‰kq£¦7„ÎÖ‡{˜Äˆ ‡Xuu²¢ØÐé à ‚XÙáG7ïÔ©_u¬¾³}¡¾*:+°i’©9˜ãSÝ<îÌyˆ|jí¢¸„ö´*¶‰I3­w‚R>WÒOëdÊwoQ”Ý¥$GGtî¬öCœ\54Õ'ÌyNêÖÛ±³Ç_³½{øôýíÍõú—öéþ«?ýÕŸ^ÿéŸüúæú†æ9zNÏÿê_ýÅñjÿ¯ý÷ëŸ|øú««ßýg~ëðhïü|uÇpÝá£ø}†;¸¦¡\UÛ²CS#Xö›[L½’êQ0˜gè˜ì57ð*S‡º?rJ Á¦“¬èNú3,š¨?ßŲJW.‘‰±4&Wh¸Ÿ8Ù`1 KóËL'¤–㫨š¡ò€kÑ!Ï´œkÉ@ÉAtUÉ­ôVUgé%‚*™ÇZJf™«`ž¥Jœ«Š24}Z;¡7u½@GgÕ–¾¬µb:=s0°Š´Ž”ëÕ±tDó<·±©÷] £z~q©ú›€m:wæô—ÊC -ÒRkjïjMÄÑ©7°*A Ñ—·%d20ZGÑ>¨y§í­æ2»ó^†™Åc ï=sJòkwz{(Œš0ªh$Ѫ秜@â‹Öf Æ4)•ÑLçgÌŽTZÛ;fòk"©ŸaëÞï'q!ú©srÑÊP“›”Jé-®8!ã“›e6QMJ¢ˆb z@$ÿ¦ô ZªÄ-ˆ61©E‰höÈ1 ;ÖœXu•âõsëcFÈ4štI©J­eʶ¢°ÅìÑSÍ•€Îé"'β—sâ -m{“òN`ÌžéE*w(e®Z¯Ìl;~ÚµérþÍÿÕß䔣Ò9æ¨Ð5Ä2Cø).ïƒ!prr‚´7„ˆyˆzŽ9»ûëI¤Â¨‡¡¡3ü˜OuèÙñù`ÿé`åày{ð¼ÙÛ>>¯ï·ëû ÑQÊšøÂ‡žÞ9zò=¥I[€ Y( g¿t5i ìvã¤ÏÙíøˆäøülujäí5¢‘ÞZ~Éà4Té0ø)±üºÁÊW¬ù©;Ÿ`’Ò‹9 ‡Ý4MÓf'Ξñ5Î6˜a€g"‚f[æŒ÷Î0ܯ²²ì䚪ñÑÑÑééÆ&v:õÎà1'lWKšѪ^žrn}½>¾ËCèø&¡¥÷)½åæ¡§Ì,DlT·ÄœDŸw÷Æžùjí;¶Þo žè/¦býœ 6V™ …c¾˜‘{Ÿ„“N‡Êà$mf¢$‰-x¯/DfZfèRšɌi$q¤JÌÌì³Uª”‘ó‡?L¯º]ÿÂí&Kƽ[âJŽÈpBÈg}äÎ5Zãh;dxwý€›×ww÷·w÷\Š|ûͧë›Ç»›ûǵ¯î#Ê?;9ùÉO¿däò³¯®.Ï/.Ï>~¼$nc2ª5`Ï4´d&-Ùr³Ý³-ú48´Vî¹›xë3”´sé$7yO…u™èYðŒýŸƒIÕ;˜«tcÀ¼l9ä rõ¬–ð|jy©Ù‘ ªY?i´(eÉ4Ú sÑbA‘ÙWsÓBΩø†>ƒâ²ª Eˆ3JÓn¦­…Emi˪%*È#2·;×zøfIg› 9ë‰6P)A~pìj!±cK½;Ówbì]ÈÄíó¡G‹a ÛÔÔ+,ˆ¤iÝ6ßÁTe-¬ž¹CæNÔĶж{‡ ¿T9QŽMh"‹u¾)V¸f¨$&W…³Z Tw‰úH†Úº‘q&ã”Ù)T8e™»µJ âvOZ’ÜbÅäÆ 5{iÑ5óD¶¹©!{Ka‚EÒHM˜ª—–[ªnê£@íJ…Ø?ôÓâu@Üu$º/PòV e·×fˆ©Qjvs¬Ôæø_T¥Bš?5“æô7A9?·äÇáÉ|’yÝ¥áðßü÷ÿŽáW~–X=˜§Ï>¶|â”óÀùžó;§~Ôû„<Ä7D=§GG‡~DìÈ~e uj²G §;0qöÞî¿p1±ÙÙî=m÷·‰ØÙÖ›û;ÎgëûÛõí­oê •>%!ÿp/…‚! $O˜L[¢Â¼O”>ô·ÜÏÏO..OÏû‘µÓ“s?¯vzvÞ­™Hí_¹cŸ”-õ[£}œJ·«¦ kó‰}.:»pçf-{Î`l7›ç-1)}wfý0d” ƒúœÔ½‘yy!ðÂ9ô=r|´º8¿`óU!¤gç¾Äwu6>ç.'jžïï}ÐyÿpG‚cò5ã®r¸Ì.ÀC$v Ô`áÚÃçï?áäÛÛÛ»[ߎÂ&ƒOñ¼³ËŸ;"¨¢‚sfGú]÷wZJ¡s´Eƒæ{%s×gE‰…ÄfCœmË=®9$šYæÉta•’5v¬³ lM5?S=ýI¥ê$k9”Òx2á†Î%ÊX—kÊÑ$ ŸjshpÿýýÃÍõÝíÍÃ÷ßÝ~óëëëO÷·ÆmkŸÓÓcþ³Ÿ}væsÒ../ϯ>\äI:Ñ{ã65G¿q´&i‘M‘ovÐkëdI,ÓœQ²frKŠC([}Ò¥áŠæ—9f¤4“Ôùº¾x+õfïiPÔ RH¥ ÙtGP¢"ýcìÀÿ‘€­©ÌÕ9Ûf½”g”¹‚€|Ãg(©O3µ¡­/8 (š[µÄLLËbˆM€2³ Ò¤³”Ô–èÖÚÒ I*ÒÔ+{¨y).k3®A4SEšŠždGÇI¥Ya:x& …ã*ÎrJì´$µ‹=ûR„qž‡CqÕN"–Û_ x GªÀÀ˜ˆŽ(•üèWu&XUaµZe™‡O8sc¢ªlÎbu“㤀¾41,E®WæK[¡åFƪ\ *6ú;ºV„gÒ1k5jéïZiR>8ŽnÖhkY’ŠÊ'-¥ ƒ³;ëá`tÑ”/­ûyš ̵†t0Mfu±vb¶¶<;¤è63…j2uUÊ`AXf”SLÅ„%¥y0õ“wêÎí¥ïÉ$;[ôç },é3Œê Å™èéÛi¶¤( æþÁßýƒc/bo:¥x®ð)ƒ)_Þ$u¿Ê\]]»œžžåͲ†;ÄdˆiNˆ¼a,ˆñ2}Ü08©³€yà®Js%Í!kfXo³…™Ï2—’k;¤Â/Ïs¼Wˆ¨ªZ⟫àA‰Ê%³¾BÏ@SÏ CrÙ•)²¢„ ×[¼Õœ"ÿ»eÎÕ>¢ql{Æ[U`9B%x¦‰Ëó¥˜Ç s›¨ûææþæ†ÐùžÐíîæááÎ/²p¥qæ¤]ýì§_Ÿžÿô'_\]Ãû}d&Kj§Ø•éHcšÄŸSstKã²ËÖ%ÃcÓ“B‰Í)î2…#ʆ7lszª>sècÉ8ç«¿­ƒ9Ó ¶Áé|Í쌦ŠLØs¾u̬TÒ“()r­¥ªRCD@ M¨-m‘Rµ ì‚0$Ã$?¦ã³øLËkxÜ8£à†W¤gäbÃÐFÊ?1˜¶vîU¥4-¥üíE)©dôYu *S3òzYEqvÊew/g PC0çÃÓ=ƒP Ÿ•'kZT£ëc2@Ûm¿ü`Ú¿4ô@@ÂÕ©ŠÇ>¢gé²ýêL«Ú3ÙlÑb”F.²*±.ësÿ„“ÜÄÈ…7b=tmÜÙ¨!¸VeaQ­\š7éaê¤D £j¬ ‚´Úæ0Á¹˜ö„k1i½6xJÁ%ªœXÓD3RÒ¦)MH|y$ÎÁBx³ËСH°2‰=¤)ÙØ;è12æÊ•#^T{[žÛÏJ¬–ê&£ßØô²Î™$¨LëÍAò¹–M{ j¤jÔ9uojä3ÄÓ%ÒþbqP43§ ]=Zvj©Àpøïü‡@¨aô³Zqª&Á-Dm† y-x´¾ÀsuõçôÌûm‰ÛNˆ<Žˆ1ÈBc œñ,qä^X‘\x˜z%àâ“cÎjÄýÚØæ§A;¯ð'}m@E“ÈËß’Š‘Æk㨟±#\[®ù~ܳR¿ª™»Uy~бf NC/$IÅA>¼4fd¨I̤ß=Úô.ñ_ øÔmó”—¢M¾ûm€°Kê‘/FWŸpö ¤4…;ž6O„šC(6â%n;:²sQGœÁY0Êåô‰ÍCßBâW#¼¹Å¡Š8–wc«Ç°;";Ïl0’øæ›ïHñôzóì#éÍÓ£á a4ÐMû´IsÆŸyÔ /9it³ÀypÌ|ldÌ(®9Qâ±Vðß ­G f9EåKm.¤‘ºŸb‰û‰K¡¦Êœ™˜«…R‹“ÿ&ÖgðÃÑ}¶ùò¢¬d°©ž·è\”ϸ_éæöÓˆÛ¶÷~#¸íöv}{}ÿé»Ûû.V˜ðqgÎÞÕÏþµÏIòÕ¥o}9ñ—üÎùXq†ac}Ö[2³C{CÞ¦-æDÕ”Ù·¨€£¶”üó0˜5v´ñCâ¥/ÍÏÌÍ‚Ìaÿl•ÎÙLNkî¹7‘4ñp¡6YàÁ‘K¬‰Ç!¬\ê¢c44šX ÅW7ÏFE•Lª)˜5´ªøœP 7tÚÕÚÅ(4­*ÒY'€‡Bé€bô‰°¼ÂL_Ö.¥P¸‹ÛÚ~¼X†W}OUÅO˜Ï¡7hC˜ ¡š;µ.wcF¢k}¤ÊYõ 1Á^¿ÆÐ›t¸®˜ò§ZZÀ“Äæ$ ÄÒ’{Qr$$7ovDÏaš@}Žâ© S/º§Å‘ÀÇ›©HZcàaA®¥IͶsSäSŸ’Ÿ$êµJü F´V[Û-k®P­¶JÆ%Æ­ôTz¬ !„SÆâ(ÝÙƒFmÙèIŠD+„Ð&¶5:'é9¹ªÔBäðüRq#ûlºF µËS Xžl•xúŠlŠ$Ýà¨áåzUØ ¨ÁKpÔÝuöNÒZdóæl[9ü÷þcã6oySêÀû;~¨‹xÇ Cæyï‰ ø!Þ]\ ||âÚ¼´òñ¨JV·µÏh1b98ôcc>ïÉãE?õïJÔxË{áôæ·W›n·>OÔîü ºÎÎÏ ÒNü¦'AÌÉé ñPmJ<õ#ùIÍ÷slÔzÌ€ÃÖE{h ‰û\Öqð3ap>f¤Ã€NC*o*|x¨‘‰(íìa^ÕKyŒ†“~ã¶aEz9‹˜úsë a—qÛÆ (g'gÏÛçƒ=B<§õèì­»Üôóè, x±q`oQoó–Ÿ‘nü€üóæ)“ã}㮬ўT°æ|ÿé†~l|1Ëþöio³E•=£Þx31"þ¤uBq¿6âÏÊery{8 Mp £7~².ôÉo¸0޳—–îdÄçî&8Üîh‚*Qz‹eœÈ£  :iÌñ`£‰]í„™ÒŒ¼C¢%2±r*ŠX ¿7_“wÆšq›à4éz˜âl]=#’j¯XÆ7ŒÎãÓÃýãí̓qÛÍÃõ÷wŸ¾»¹»¹{zôe1ý,æÅÅé/~ë'ÌᯉۮΠã¸a¶ÑT”«Ù6ò©Ÿ±5ö؉ä“.6þI‹æd7Q—Î=dÝ© 4Ôö¬9X­µ&´¶)eÁ Z´4›F§² Å™2锳ÌzälÑ*0”{ôzL“‘Ì<°»qȥġ2uŸ­ü´E‰Þ9ˆí[@r$«Nó¤ÕlŠy*x®Ó‹Jå&ìèÑ¡®jYB©cêiÉðE¤ÚÚI>³ŒÙ²ÔBÝñ€Ðå¨{ü9ø¡1Á;IR_Ρ¹˜ùSòæSN2ÒÀ¶Üíˆð¤ƒh/‹–AªÒܵ/ÙöHÁ‰gp.$l€ÿÑÜí-&qô8{lr‚’nÖ†‡]3;=œ>`˜NÑ•bMgý̲ÔÇHÁ‘.”èÄ2Qs~ „Œav#rJmøÂöiŽÅþx½YÑp7£ê–E &=“I%=Z”‰ÐÔ•\±'“D1‚¦6©4E° ke©ÚfìWQ¥–²¦*iP[v¨Š»N…D<°=5¾Ìh±Î‹œ„á·thÃ’‰,Ìgr¨S’}0ù=ÖŒ^¤K‚_ì™gBº=‡ÔNõDÇŠ k]&·Uû qÛï瞘 {wŠ9fL–ØçhuD Arp<¢4n :ðËžÞ±äÜŽ"â 5ÇxÀ$KÐæΈaòa8Ô…ÊÙŠçnáó?ÛCþ½ßö¼Q…‡‡g§§H|ñåWggççç——þNÔ™I#hëÝ6ŠÆ´×èɸÊiÞ«1Ù™ÉäKûežÍæÐKµyJnòsü°ùó\¤ù ~‚o¿%nc#H£Ÿ'ç~éáìä(ÏŽí­òq3‘™ŸxòMoÛõýãúîqû°Ý><­o×ǫLJ¡&!—h±ÁU÷øe<ìW.ˆJi…ï­ööWDzÏëß3¸{ t{¼_+èÙèÙ¯}ûa5¿­í3¡ð%ÛóóÑËË7ãöˆ1ýbÄ©OšÏOˆÛsb‡%=0Xítdþ`ášYšúŽÙq®ÓÞÙ:(cól«‹ùÏd"È®2g!Zm0ãá„ÌðàçÌ\ßLðݰSSÔ"­ò«Èixè+Î.Z©y2+rql+è`ÓU:æ4æªÄ–ò.y™ ¾£< õÕXžu2—¿û/w÷ןî³Ý}úþæûo¿¿»¾E n=??¹º<»¼:ûÅoýìüâ䫯¿¸¼¸èSþami…~âÃ0W/{@ílMÞY+›±ßédÁðXŽF¦"é¡÷R=Dô›¾ W6Š®æ/ÙÜ…?̶ ÿg[Dà ÜGsÞ–FçtÞàœU-7غ5OZÎL±i3iâo†-ƒK Q~vŠ2Ž˜ÑÉÀPÖµAü`†ÒDéæ è¡-ÞäÈu}Jmèœiƒº's¯&DóN° ô¤c’ê³a…›3ˆ>c¯b){€Ñ‘N±nTisÔð¯‹âÏ¥gÊSºeUc›Z»cˆ†™'¦E;iÌ$šéô/O ]´èÇš-öØ=’›3xV˜­Yš5 F¡\Õæô3mº° ®Ùýå$ ˆžf¦yÅîûâªêfLë=®“¿]K± 5 ú˜~ÙÂÙ i-’ca~Ór,kjˆ‹MY2iºC¦ó¸¡±rÁÖÓZZÔé‹V%Ñ*±{éQTÙ²Ë/„L8†%ówšRF‹+Ëкä)a¥) %“ü Ú(P÷è#¶‘Ùæî¬·b<&àÔXNgäú|rÎŽ‚†ª2^u‹$„#Cˆ…‘×òá™ÝA_Li™øïDd åx(¬5oVw…¿y´8ÑzW,!oî·zß`ÛXÑEçFßÁ¶ñeuÄj›gÂ,ºû´ñAçãz{~rJÕIîÑÑ cC¦áÁ·%ãœÉ±}"h{Z¯7÷÷ëûۻLJÎÝÛí#.»Ĕ¾ÛƒQÐ#:Œ¸mŸ¸íéàxuú°æxÝ{zÚ{ÜÚö¨-–ü…la"UxÁó#ÌàóÚ⯗K´;%)µØÊɿݔwðfè¾…©@ŠfØæ‰Ñ*@Þ³]èðQœMZ¢"sº„=A$ÉTñß|êdJÞ^¥µ@æ"Zœ uó#Nò•­š±ÓðOlÙ1€a ]Ø&îz/G2öÃÄCÊöZ߃U´T2xcÃ+X3D˜¨V$ ,Ä‹d£ÓL«fX¦*"m÷MëóôSÑ"“¬`¦ÎR®iÎÙ1|'jï© båIXA'Ô(DRÊ ¥½j"ô†‚‰až»JVÖºägŠ7Û¦NI8ô'U £ÄÔ–¨d˜rÄœÄÕZž.#a:lc!^ Ÿ³·?€šš¸mºIÔŠ%äI3s+s†Žh¡ÇJé¡®ý»#}’i¼RdŒÀ¨bdæbÚwUè4 È””Ùù áÙ¹aH“,üïãðÿÃÿ…µñXšè×âz–5ΧhTdHç%ç$t¼ò’\#|Â~èÝ_-ð…½~líÉ—ÀÙB”Û[ÏuÎKuçÆAZè7¼òõôû~™H9­àÅ«Ëp‘Ç4Ф–òcT•wĦ5‘œc0}>ã5¬EÄ“]ÆIq¬ðGB|!—?¥Úw}Hß{Ù¢Ò 7¯%{IäakÉÅD¸cÊú óôýþ¡Ÿ—#õ»§O·÷ÛÇ?ç7=Û68ƒØ‹ .{{ Ýõãƒ:ð÷áÞ‘‘ªMÒkÛ"Àñµ%§‡ù> 1Cîcb —;>4½G×_½þt‹£è£âå——CÂ]ì!0^ù;Y'gg—¹ÍvâOç£/cþä0ÞÝßÝ^º¾ùþúþnýpEëÍzóì/7è*Ý=ÝŒÈIl«»sx¸;…{ÒcpSÌ”à.2¢Õq *HÉùã`‰žAe˜ÐÚw$µæ½ÔƒR\æSU@™*!Ú»p2[}ù †h‹ ÞK :ÓØùæõ1©CýXé³Q/Gðü !òÝíã§O÷Ÿ>±1"øôŽÑÙ<®½P:Ø»8?½¸8%ýéO¿>99þðÑ›m _±Á­†Ñ >° ý±ù­”òMhV_ágö–5]~͘Šú­U ĽÍAï 1õöy,r&S Xø3ˆÂ)¦z1ªýVV•ÞLó¤ÕÜ4B"B­la*…ÂF§é¿NL11œñ-pZ(_ô®š—˜«¬­¶P›i‹s»šY$Ír™A¼ïÚaÛÌ)­é¬M“½s`N#ÑÖ“/¶é5µåN¿ÉÓ¸…Tù ZÕÏ„¹8SÞ1 %ÉPÚŠ3ÿή†°º7Ü9º#¡AЬtmѯê„ÏÔÌÄhÿv[D2sÉOÊ’™l9Ìcòûg®%3}™¢®Kþ]ìÔE¶‹•&ö<Ê`…“©Ï R ˜ºåêœã8­KHT‡nÒ6­ZŠÃ$]< ÒôtP£<³ ÿ”Ã4›µÙ2gÌ aê|˜RÛÙÉè” "™šSClÍÏD{àôíf¿ZÛ|o¬º(Ò®CŒ”ŒVe;Ã¥H¬‹eS‰ñ f¡,É0®†‰xH鯦pµœè([š`¡½Nÿ"3Ð^¦¾×jøO£ÍKñº{ÿcâcädÏØZÑ]óá³–b8‡ NëK˜$EÃÜäò“Kc%Œ7d“¼@ÿðïÿ-ŒàœoäÐ $>pùFžÓ –z–ñîŠaœ‘‚"p ^ƒ<xXú©H!Z áÓ ±FŸô°ÿ1<¦)È—bóÇiè(wÔ A"ëÔÜh×¢.–¨QYÓá–efN2»ªÉx~©DºÝSoÓv&YMM…nŠÅüchj ª`ÿek ³ïïS2&›§‡»5™ÛÛÛõzÍxá½ív‹gé¾ÞpŒ¶hb8ö×b½Ívt¬ŸÛ:6ÑœÏe½Çi[“ßð¶ÙlÖÄXÐOw÷Ç«ÓÜc;[œy{S£L Äšñý)~AZ.]BÑópëëBrÖC·Ž¢)'L´9þ²ÅƒµFO.`üÇÌ®xr8sºîD „(+‰Î ­FW­“TÇø¼þ— à‡ò²•Šf•·¹±²MãP§§NÙºr4ãóÔÉE=S9¿jáûn˜Ñë‡íýÃææz}óé.Ÿo#öÍ7ÌçôÑþùùéù…_©!n;>9ººº zëÁ•#^ÎÙJ³ÌÁÔhò±,|³åÃ!3Xäá´ui‘žº)Òþ©ÊYfi\’ÑžžèØe@ó¤ï‚vš K-ÌC³é°=†¿õÕ$HqÆL9üƒ¿÷7 9äŒï£:B {ª“S½; Ý88œÁÓa•PÙ(%Fùoó9„"¤G{çqŸRûáÃG‚¼|‚,q[R¬¤Þù,WÜÕÆ*q¶žMÈôYf΃¹ÃûIs‹É¸wtÅ`œR38axÍð GYÖ›dðbø+!š=<ÝÜ\ßÜÝÞ>>Ü?ûDûˆˆüòòìê*¿«ñ“¯W'«‹ËóŒs÷¨UÕñQÔk§[ î]c=ã@¬ë¶cubø ÃËù‰‘IZhŽÅˆÎJ{ˆÈDûWŠ'ЍÂæÈgôÁò Uö(l=‰S ÃÌMˆÈYæhTÜjgÚ¼…$èí“W>ptÓ½¢œ£Ú)—´5Sý(…¿œQ&:QißN„Ï~§ëæ%I-©îe´ÿRÙ«$úL¥&rTe,§½›‡YÕ$äRÀ†"’A…"Õ:¯Ö.„¥·Ö|jŤDɉ9>/aPÂTö¦~Š‘³W‡ ó‚a9É‚öoqÈÏéŒ7Åâç=UÙÏ\Ì4RVÈå*i¶Hg_Rèxzõ3Eá|0f‹šÌ„y·µÍ¢™‰'Üèp›Dl!̧ZEJÏf}8)ËV~w¤ÃénsÕ’J«,R0(­²XÙ#E[~²-íVdLÈ ô0G4ý(B„sVJ¥çÜ(wiRÚ.ÚÇìÕfÒ¢Z&ŒEìtŒ€;”×ܰ¦"90nNÅUæâ›ÌÚÑ¡˜™í©)FžÖÜ©¸’I¦!jÌþþð?÷DÄhyâWJÏ?Ñ{ã¶ããcœUÍшÞ¡iÜfèæRò@Ni®µcÑÕÞU†oãë@ü&)¥˜Ù a Ó‡/>Ð’Of‰Ø S·MÓ5]ò²Ëh8ËmTòõƒâA‰oÐ{fXfR¿‡0öS.šŽ#ï.Þ$¬¢š¨3޲Së‡5Ʊð:·÷÷tÌÓÓãÖ7ßúfˆíw=·yßKƒcÏ™œ¥ ƒaÈˉ½p n!´õT¼HжÙ´=lž‰ØˆÛ¸:@'º.¯.1 ©ÕŠqÜ?YíŸî¿lóå]Žaã]ÌÙúæÛÄÂÛEp·wwWœc²k¦Çi˜™1޳OœŸ½OdÐq ýÅ}cDžoÝ~ú”¸íÓõýÝíæñÙïw£W‡WWWù=´ŸþtÄmÇ+‚lü€æ6š©ãØ`"f6 h×mWÌé&B=1û~p˜#Óbêw¾Íç$œ«jEª/è`ƒ” &%)fJ mCa·Xª©l2¸$·ù|… [•TõR-„6Z¶n í9!é]²¡L€>SÆm!U¤5o`䤸M5å$Ým>ËÙ¸â6öÿéiÏ[nO›»ÛõÍõýõõíÍõÍíÍíúþþùéÖÓÓÕjutyyqyå÷n~ò“¯‰ØÎÏÎq[‘sÍkAiÓôÕ¼ÔåoøLV„=Ü::8÷Ûìå„:°€Ní¨ ’.ùg¼K,ÿNêk˪„tÎÎ sÚ̳hé¡1ÓÁÙe˜'Ï+ªÄÖFÇ[ ‹êû>CTí”T­C“ÿŽÑr » 3É•ž¥5Âc Rmg[,æ͘‹í;iA>;Ì”ÖÍæ2´zÂL7þæg,§(ÑbéEšÛñÔÂw1W)5¥K¼K™¥šYz äÔó&±´¾†6Š3B¬†+ÞÌ—òÌœ?„Ù“ÑúÊø7˜k?Çà˜ðfª”8ççÌ„”„2ì`¥!«KJoZyc[ª>›7¯Ú(sÐÌ(¢±ª–XÐæœîÞB›\×åé²5;¹‚]Cz«d°s±Ø)ùa´6ìËL›Á» 3j‹8ü·ÿþßâ”O,Æâ—°Í/³°5pƒC4H!tÛ7€ò'ØÔ¹^æ%½nòóŸs°-`9—Òyl·%X¦‰Í:¯.»¿¿¿¾¹¹¹õ'—îîîïýµ¥5ŽC¼÷”~ñÅG—|ô굇G†Œ¬ncítøh'a!K^Ç-O”8Ÿ¦ãXÒ ìá]9!{2s1^sC›[ rg\Ç#Úæ§H´ú.ßî Àõiä‘/œ;´ôc…¢‹‹³Ã#¡ß÷ª¥éQ7Š~’/?±€jœ·ö[ ÝÖ¹ ñ{ÓyK#ãsèͶƒ¾åxurzqyx|zrvu´:ß?<98:Ù>ù~ãÛ»ûïó’~­ëëoQü´]ï=oOŽÐ÷|l‹c4 ³2¿ÞÀ–×mžîïü [?ä† 4†—8Üô^O;é *ö‰*SÏù%[ãA­™ÉùzZJ,ˆ3dËÉkߦ…NÏplsïvP£öMæ=(Ú‰ÖÔ>KÎÞlc'=æc§1¥š¥¸MÌNJÏÀÄm›íÓš ín}}ã»?>}÷éÓ÷Ÿ˜òÌ~\E`uqî[ ¿øò#“üêêò«¯¾Zûò¼c]gü¬Ï0l÷½½¢ º%éØâ-)c²¾×í6e™N½Í¾èêÝÊ5ç ßy>ÊÅ7˜éÍM –yÐÚâsAT·Ð3>ùVMGx©&ú!l’_cI¬¸‘âŽ`GM>x9]ù5 ÃulË…¡"VÛn÷Ÿ^6ODÞ/ÛÍ3Önü~«ßºÀF ¢Ë£“Uì6`O÷3,í¸ÏsQ\ûÓ…œ«â$¨$3ð¬^v‹ž"2!MDTÍ(¥(%“mˆÌéoˆj˜ MÛÌ_º¢Wò¿@Y§É”c³‹.{þ65gv¢ÞÇõ³÷ÛîÖ·7wÞlË/ðnýå±§ƒ½çóóÓ“Óã««‹ŒÊùù—_}dÜ}µï{B *36§-u[›uꛆ+ d¯=Y.Ó)æ&Œð J¬Ì·fŠÒç´Ì»Ÿ‹7¯a`ÉS¼ÑÚÛÌ›AÜÕ6?J¶á´™8g¶biR§‡‘âŽà˜§þ•– h‰ˆ=HäUÏ.• ¦nÓ~·ílÂÇ¡ä¸#“e¬‡ ô"™t@›¨F½î,PÙòK¤ƒ; jÎ`E3!Äœð.ÞˆÏ(=êE‰?”§‹»Ö—™¹ø9fåð̘‰ošní(jßç\ⵈÅús”Ò*¨ŽE•ú[ãiᇛø£ yÅÁÌ „è­z·¹™s΀j›1´»Ê¹¼¼©2Í“f溅bZÌË l™×‘ ‡F׆&KkôϰÐþCW?-„dcÑ+ŒÊ´ÄRZ">IjÖÒÚAþDz¡s*6J d²5üî@¤ÿVXÞß'nû›°„Aof!r­H-ÌŽ ù®FN~!áqd 9 4ü|•7Éòqy.2(Æ€h–ÌV›'?²MÐÆùìÎ3™?—þ@NÚ=9Éo¾Ÿ]\^œžž^}¸âd¶Ê«vµOl—-Š”éXÛ®¥ùiÝÓKMC49uåGehù›ì–왼ƒ&m´kÄæ¦Û âì|>2ˆ©úFï휞׬ÎNa'r;ÎovùaßÇáOx¤¦{q{3‡Kƒ„FlynÜßlaÄ|=ÛáÑéËÁßÙÁM¯N±qM‡mÙַן¾}\ßÝß]?mî qŸ¶§4jÐhèzzÞß<í߯ŸÖ›û[3¿…ºÅ^œøÚïÀ2ò£÷ÆâOFß›G­ó±¬_SÅ0#øœêRú‚¦‚A«#11®õêNÔˆÌÀ²XœGF`€w`i ƒž­Õ‡ÍLÛ€)%”6%©’ðWÌBX3E:sÇH3DR÷Ÿüñž|XßÞ=\_ßúù¶ï½¹Ìœß¸ûÂÆ½+ÏjÅ•É_|¼¸<'ãTÏÍá’\ÿõÓ¼6ަc¼j!‡A|Lû¼PÌ$î^A¡ìÀk|NùqT4Çž]›¨šÑbé l6©mM——‹Whúï ÖO˜?Q’;LŒáˆOZÇ$Føà0/°¹©ÁïOn·Þÿ¹»»_¯×þ¶ùã#†¡¶³³³F0ççç„3ù•ƾ¼×PÆ£Ã1Îg×¼¯¥…i ÇéAçM;LkFíÑšS×N¦ãéWyÊ訆!û â-JW$Ïýµ¢*¢Ð(c¼7öUø„¶ˆtÞ˜×/^ô·ð{ÃðÎ(9n XVáÚD#G‡{LJûÞíJ„¨SüºèñÞþÑÞÁ1cºwHž Ê¢ágÄžýô·¯ý}¸»~¼¿ó÷°6D4H//.‰øhÿèpõìºçÇíž/^oò뱬 œûð–½õž«Ý9Y¤ÏX‘Èå{ľî/a+±7L~ÔÎQGtL-Óøo·…Ò‚¡èÁ¤–S— ÇBjƱhž´ú͵ ä«`“ÁÝ-g3z"–Œ|Úå¿•wøÓ‰gÊ,•WhfQ,‚¸…´äôü®U:iç¦nÉCÃà‚<Ž•öî]´ï ÅȾ…í.èežEÈt(a$gG¼[lÊörøï_‡ SîB3ŽïatXÕ’›FLSç••)¼ÍæhI§vwÁûoy|’ÄŸKªq„9Ù›G ±Õ„k§‰Ûüø×±¿=Š‚¾ZL“r€C0 ,gWú¢Ô$µº]S»“l–lÚž\J!»oal¦¦Íå2-u¹V®àÄ­1ɹxp4â68žžŸŽOŽsƒò%ºWNy®ùàsd¿l› )‡âù‰ eÇ{Ç«ÃtS§î¢aeÜvHÜFÔD§!4„6‚BŽ>Gû{›õä#|F“Ï›-ÎÆqÓ¡7Ûˆµ¶OûkǦ7*žò€ßv9ÛÌô"ÐÓ3Ì(ŸÃn‰ò׊„ˆL£Õñª7 ösZÂE5Vaöuu’ÉGÓ¾ô@Nдþs-yçáü’žîmÇ$™RÆN5ÍŬ2„;ˆ¥T =ÍzŸ/Ç”&dÃ9>$åzäþþñööáúÓÝ_J¸½¿X?Ü??oŽö÷¯>p‘ròñã‡/ÏÏN/®Î}žwõaÉ“q[©z+b IfZNl4®}¿XRÖ¦µ$#–.š›Ž¼Bé35˜)ÍÌà(žýªó]ÍËtÎ8„Î Ž*'’-íÚj-h~.s¼a*º+-¾A«„7$$Tª§|XzÝ\¢‰ÀÒôŒË%‹Ö&Ãh/û9å3æL´‡>÷¤Y]w €ü<¬o3vmÆ(é Æ¤ðßüÌ<3]`›¦XzQ*‹OXºýaè] ÄÖ)¾mè O±œ´³ª¢>Äí³çAÛëÙns— v¹EÄgó MÏ€ÒÚÝp‡8cw 6×ì'ŒÊ÷¦Ç”KòJ+OÆnÁ¬[êfZé•m¡rSʃ¹ë©ÓW ¼†îªwQÌ\ ÿ»®Møœ²D„µy¸zÅ¥£ ˆÅ<À’¸à¢Í3ü+ìf’»Dbïðßú»ÿZüˆˆ@÷\PSûYž¨‰”?Ê7:S0Zñ®‹ðãNds‰ÿùÙë“ã où?‚·½K*ü–é?cztuuÅÙììüìòâüäDaâ¶c9ê(')#³xD—ùÙª ºú<«ù$`3Y•ï0ÏQvd- *æ8Ÿ=ë…3 Ë–ž‚Z>§€îäÉqHðÙ’îÎ1»Ð¨ÂxlËÉãÕêðèøÄ7§Ãó‹sðÙÃãÃý_ѸþþÓÝÝíÍ?zpïMB¢õöqCʉë ›=tÐ$>ij«Ó£c>á`uâKöŽu>[½wN|r|vº:=>\ßßnÐó€6»¿½?:^øÙ¹SìneTu']ÚËmRŒð‹¿[ÔaoϸÓÖ÷þ6ÃÍÍõ5uù Åöøððñq“{Gö܉ÔKh$_‡é †+”=CÐ-9ÁléH©fr¾âô‘›ò3…Ìœ-•dŒuJh1\-⨲õH"T_˜â÷ĽÐ%Fõåmlý&)ãvsóðéûÛï¿ûäo[}úÄP>>ÞãÉ“ƒ/ü%Òó/¾úðñ‹Lxò Ú¾ï1\îsÒôxOÐms5/k¯ Î7òV9éLkbáÔWpƒÏÕM‹z8þŸóÌ™7˜Ù@Ç¥±7#샓̛Alñó‘Uf’0Èãêïq]”gl#7Ù0 ‹ÖßÈÌô9Z,œŽVñÿŠTUÓ©r®5¹„倸gׂìSÉ5ntlá¤UGw,LMpœ¶Jiföd=ZÔÖ'¦ü›2ñôcÍ™cÃZJµ´ì˾ÃÌYÌmPaݲ¡Ï![¦q á:rL &…aÙ—R–HÙå|d3“áj¡µþ»ÊOJÒ¦K#íÍbÊ Þ"2àê9cl9lÀózs³¿ä@èHí“f3†Ù¦ìGÞ"ò Cv(AKõdïŠQ~K©¨ÈÙ'Ù”ì¦|CÌvžãÝêF©.K&»hÛZawãÎÈ=A·øù ¥`p¼‡ÉYÑöÚ)£Áœ¦Zœðªh£3¨2nùQ/0 Z@+ã¹nNTMê6åYýüX“ÛÞáþžo];Ü?ö×±òó¯þ°ëÞžŸA{ö׋¶þt©oÜòg·ümS¿ð4R#^H,_k‹EÌÍçýCb/¹—3χÇ{GÇûÓv@,G<çóӽç—秃ív³ñÖÚ–Tmñœ3”Ø›˜Ã˜Í_GmQûG/½•FtâWLˆ/˜\ì|ò'Á6lÏfò-œƒçLyÖŠŒ9‡—hIäp®×ÈtYMÅ›xW'´PëÀG×¢Öý8œ2ÊU`JŸ&i—+×ÇÁ_ÐFßNs|Þg+qYµ¤ÌÄ??Ì>5ÚÏ3™ìkçå.öªf–ûDèQ­3õŸìÔ«Íæ~xcÄÿœŽý¥ðnãþ7»Mü(àwûs¡g¦ñ¶H&Ä%viæ ™¸ÇøÓ±öÝŸ;X­NVGggÇ'ÇG—ç§ç§Çg§gg'ÇÇ?|„íèà¿ÞÞÒæã§ÛõwßÝÝÞ¯ÝÖû‡>Àe8NÏNÎ/N/.Ïüþé‘w 9§ÓݧõúñîÎ;IŸ¾ûþ»o¿ûþûïîüqÔ‡ûbÏë›lÂÆÍ:_Zð«­:yZ@óU?:–îëÔÅØé9§ÍED z0Ó{ï¶Äf>/¾Aæ*3Šä†”lsƪ>U0¢CRó¼ÇéɇØF´tôá~s}sýýíwß~Â37× æ c÷ô´!b÷7ÎϾúê㇫‹/¿ü\\ø 7½¡Ú`gQ¿2¹%ê/½–㦭f‹e5)áZA%ÆÎÑ œÊ³y%‘ Žé“ttÄ(|‹•yn¢|¿;¯e åUêa£rÿë)æ¥ÚbA-I_Æ0kö³©l9’¤¶¹ÎÛI£Ó«*iª$÷ÊÈKpºi‰+GëXb†ëWÔýqŠd–Üd–Où1!&uŽq=E“T„e®±™"ƒ@emlEr½º|ü ¶wÙš6›3“û^Q«Ôá4PSuG-(C‹¤­m:×΀8ž²ø>6”e|¬”‡ÿÞ¹$ƒ’*2ÔÒ ë´ ¼nX«Ç>C¦fF§PßÈþ(¹ä—(«bÝèàÀ¢ÄôÖþàm&jÅdó® — { ZKQ£#«[¼ÖŽšŠ›x2­s£€L6í̲Ì5œgeØÚ¢ÍLˆååN"¦*§#Jœ?ѰÛjjÒ,Öäq²qµ*õì4šf@dpO`*ç yÄm RUgÚDÓh°fàIÕp·­ŽØžON^V«½“cø‘"±ØÙåÑÑùþáÙóþÉãöp½9¼»{¾½ÛÞÞmîî6ë_ø„ /ü5…ÓƒÓ“Ã>§n¸É0ù[÷þC^ηÞn}’ë¶y$È\Q>>><Wný:1\nÂe‘ØrõüéÊ1ü4ðÊ…Ÿav±#7¡”ß?,²«øqµÔíªƒ\m=Ž|¡žýbÈÀ‰ár®÷ ³j³1_ýé6ç»2 »#Ï<²j§r1u¢MÍÏ™÷ k‚QþÑÃ|©¦Z'Kñ]ŒÂD:¯Ÿ?bU:àB?i¶Ø\!] "¥±Õž#œ†ŠP'¼Cz…©ø1qjjɰL‹amx—éU—Ë$÷¤³™žw 9+Ñücˆ¶?‡§øÍ9—¨éç›`ø^Oâÿ¾agðtÿ‡èE«fž¦3ÞßG]Ô3Çgˆ÷tàkU)¿á ’oÅXAæª?öá³Vºý&ýÐ ›;î× o=mS•–Pþu¾D‡´‹óhà/†ÑÍ’mU=ö.ÏLœïmo± žtdç‡ü>ic«ÜªÑ›‰Lý'ŒˆØYJ\M"IÊñáüœuT-O.jd5Ìå2Lñ#EZôN6B6(.=äºåq³!P@ŸÕùBC?ýãµTÞK$ ꥫ=8¤{bûŸAžìC0ÊÁ\|CoL{33ñXÏ¿°f gvC±dðþ¸RGÐKûèâ¸'Þ[rk'Ç+Tå^¥?%Jàtt¸ÂO9É;>:rÿÀ€mПãJDI/Ï[œdpïžÏc1ÇÞ?ØnŸQHŒwpp„;7H­óHö…xÑ{-ð1çå}Ø—[ý9z¢l?¤xlÌêL¦'bK5ïzS Óê¢<Ê'¹Ó¶%³/sýŽè½(L ÇTgØÝdÿz-¦æJ‰Û˜N4@Zb1ó,3ïÀÁ zè98™i¬ei$ú•‰lËFlûýRBÞxçÏ[ÝÝÞßæg|×ÍVÒc†óêòìòòô‹/¯..O?|quõáòôÌ—À0CÚº­Ïæø±y|Ø\H™tŽP8¼U“³{:¡m1”ëÝ©0©‡NwŸ£Î,(:ßl·Âo¡ÞT‘ÎG»RH«¤tÏ”>ó@¡E2œÓeqFéýsW¦ @vÎr5“´µE-Îi3"mµ5ho\‚s÷f™ËœÓ®F¥eKgs;-*òXà0W™#5HIÝSOJJ*4^²*K8›¬#(«ê׆ÉôæÁ<.¿d²˜› PU~R”³£è˜¨Ù—9¥·˜ÍxƒIzgÌœ_—¨=…g­—Ģ⪞  ZÑcGâÄãÁKDÁ+}d—åJ53#žÞy¾ÄÁ“•R‹³à Å, ª­ùf–µoÀÉÏAiƒ¯ñÆEdÊ#k2¨%Å™Y^Z»¤±Üt†¿ ¦#ͪx¢OÍÍf×õ@Žqc¯„ẉò†¾#²ÈNM`#ÿoŠÁL)l3{šŒ6þ²½ž#35'‚“E£GÅÙcU=dç‰ô ê–L™¢Å4“Ï>áR3Ëc¹šIÁø½B'-°ƒS&¤Ä¦É$¯ÅVSàü*w’4Ôö´;l"d[_ÇúÉy›` *]–r«9Ö6 ¸ïÈ;‡À¡SÛU`CSOXÒÐ/¿0„ë-ZFy”ZÒÚb®j¾м)mêeáá gúŸˆ Nºß -Ç #O†NÓEBø Nð'ÇÇTøjå{B ˜Ð.ÿžŸÃ_¦:Ä%gáB¶ƒ*ÞÐͯ’ÔBÌ:$:;>>ñ±Žð÷ƒÛÁõ-{_ÑF|…÷q2ç…ÄÊH½xôè`uŒEÛŽ°Zïˆ2L~[៺Û·$rˆ>)Ž»†¾àÍ{Nžo6Ìî$y6Rét #ØÌ ÖcAÝ^Ìóµ¤;èšÎ%3 sº€ƒ3ɽóm2 2Kò*g°Èä»/^á€ÍsÒçÇõöîæÁ¸íƸmí·781ùduôáÃùåÕÉ_~8¿8ûðñêêêÒ7÷¬ŒÛ(§Å®‘mgäÒ¯’ÌÔ¼¤Ý& —$[úì¢7:[ æürøš Y”8ƒ²Óf:bïBþ…¶f cXk—(CaO ìØ21äI]¢ÒŠÓ ̳º Î2kG÷^ûí]„‹ÔÍSÌÀÐùbʯì Èx€¥ö-¬.gô÷9X‰¥7ìJFSæY*hmm¦ °£LV‰jÕ*”$5Ÿ{&|{‡øäýmú2ÿhÆ”ìmcŠ-ÒSÁ RL&…²Á>餞“›ÔNŒCpþCrëÇwØP²©³=`t¢·é°Ê•¡L"3/~t7¹S3|¢À¡K 9-ЉmJï&ÿ¨}¢°f§‡Ñ¯Ò"PrÕ3ˬašb¿ºíl½²‡›•ÓÛD6ì|QÍóËãÚf†ˆÁ ›ˆÞü.î)©ß=öÇä÷ ¦Ž}߇÷¾rײÝZy䘺DåëZcC/ëGß—ûHœ±wHSkrGÄ]ú4¦¢‹׎ŽaôÞŽ±âôU8ûÿè Åœ¸rK.Øü¾0šˆž9Á¯rT:ùH'ºŒÕТé¡_˨“R¥Õ×4Qô-Îó8k–?§A¨±dL%ûi2ìº+S%œ»™2¡6 ˆ6ºƒÊ¦ò³jÆmþ2©ßy||º¿óÒ7Äm7·ë‡5¡›Ë×ÞËé‰÷ÛÎ}ãîÕÅÅÙåÕÅÙÙYbÆ 5MÙYH™ÌjŠ%šHܹÊÉ7 ÊÚ;g€ƒÒþ£ÔŸ$JäËã ת]3o¡¦Y[ÙÒâ+hmˆËª¶››kgKñˆ*1å'vPºbRgë¤N@aéz!“·¨?­´ËàýóšEK&Ê;2þ1ˆcâYËšmy Â–E›˜!Mv~‡Â¿­9›°K NÿhWÞ?·(ÕÒ)£ðäŸ^x+Ú"ºtÒ2;e¥Ä„‚¢MëTLÈlÓ™ÃBõ^©Ú»ðKZ[DÄl)vlÃβIa è¶Ã²‰vmFõ•m:Ó3ú3¨CC:h£¹-N­•¾k òE¼lSC ;ý‰®L¹QÌŽJ«g¹2ÁpyIƒ:gç¶ǬžfQ´lw§Àä0šÛíÕšá[Ô (ÒzÝPU­j}e¥ç/™O:—ú ˜5Ch´~Î7š7ñC&*ÅÐ ul¥Œú¶:‘$Òæø 5­ fÐüdógV*vñS£½ ‚Œ-¥VN€R‚öÁVÈì8,5Ëß• ž×ò·Sìÿgÿ·ÿN÷Ì7Ý0EC©JœálÅö¼›åg›¢IZ”Ç —œ6b:(W%A刲½iㇸž8³‘}|x Ä¨åÌ÷ü¼ýøñ㇫«““ãŸüä+ZX­ˆ)hËÏu©ædÌû,ïxEW´½¨…¨y|ißß]%í¥* ØF ÒåœÀÚ÷ô«âblà´¯Û(ùB`, Dë9=ÑX‚û'·p':«íñÁ1&Þ|º!n}ð{ë»O·¿üǺ¹øÓ?þÓíú‘“9ñØéÉɇó+×™ƒ½§½'â»Ç—Ç=‚؃ç|uÀíg?ûúâüìÃÕ9þÁKOš‡ÀÑËÞÑêøüðèœ8ð›o®_^×OÛëëÛo¾ùf}ÿðÿý£?òu w×ÏÛ‡“ӣ˳ã_žýì§_}ñÅåÕÕåÕ‡gg—«³s¹ÍÏ•>®Ûï>­înnïon·w7w~˜K¿yCÂî`ï'_~E $ <ŽÎ.ÎöÎ/ÎNÎNNÎOÈH¦$}¥äŸ’gÊz,­ŠÚç18NŠ)"ÊH kÉg 2TTTC͕ԺܘþõÕP¾p/Àl4`9PU0[ÒâÊ:Õ8¸PÅQ9a›Ç²±H=UÒª™ÞUÛÚÏÓ‚¬óvaز 4J:NŠ;§‰zrG'ƒ¡z@‹­©üêdœË@ÑWÊkCé„m&Î)˜•´jЂ1÷ …?2É%…_í\!ä‘eZRU MÏ(¨lÛj(«º²Ez´²™òÏ€X60«*}ƨJIsÛX»'"ê'Ã(.3©Îì‘0‰•£œÖ“z”ò9†H´W4tÈcÁ¼ËÌE¦­ûó1šŽë0a!¾b}ž] !¦?ÅÙ3d–€R’8áçðkP¡^ö ™«ƒ0ÿî(ër?šúÿ+Fÿ„˶ÒVm\dŸvxÏÞÅøý…@{#÷O†šˆ ù6EbÄ#ãaž+ø¬Õ`TyVàÏÕSfôîÅW„ŠùRÜç½›ybAßàÑ… MÏ”ˆ·œòk` “u@FB>Ü›i/yÉÞÑ1 ‰÷èˆXP2ý΀Ÿó'!õs¾:ì—+fÛYõ2>Z©y“‘3àtÛg¦ÓgíÊX8p¨É¦Qo¶…þÿ®°4{οîË;H§áêNLöO³®S°ù…ŒËxÜúLì—ü·‰¥êÿqäòŒST>}àuÆnßÊ¿(ŸÝý˜ÆL¥ Ѐ¿ÄŠùßþiõúÀÿ€ÿ>àNïãðþý¿Ep0nú!I°#Ä< îÇ>9ãNF#¸$V0áˆOÿ`Ù¼šÝ嚆ŒÜCx_=¡·ŠPŠ-³xñ‹2®Ñè=9¿ZùôððÀu±Íqírx¬àüwÃ[%‰1ü„ÜÆ—¢¢ç¤.Ýl7”7Ð|¥ª­ÀfÍïF‰àÒ;%Þ,1 KWaƒâ›Î4Ò( º”ðÅ­Þ\|Ù&ºóÖnÜ>n÷6ëGƃ>ìï=ï?ɺݮ7›ûLJ‡Ço ›»«û{ϧDŽcÏùjnb¿¸ÂnúB„}®—‰óö½Á·òQåÁ!—„u‡~‚ðeµ"8Æ"ÌjûøàÇçžýQT,Ô05åÛ:Í[P‡È>©ÆËŠ ={ÁZLÍ7[UDž &`|>ÜFJ˜O¹Ñ˜•o™0E"w±";ƒºW GM—p2Lä©}­ATm1‰ÐGÞÍ¿Z{¿jÜš*_Újƒ牳¶ñ„§ÍóæÑüÝÝ=ÜÞÞ}úþÓõ'¶ë›O7 „OV‡ç§þéÕùW_û³¤§ç§'xŸÑbV†ãŽ´”i™Ÿ'Ô; t‡BmHç%ö&){@£6}B¹‡ªHã¹W˜‰‘z…ˆý*§†!°@9F!`,F.µóWN°ÌŠå,|(»1³Nòo2 ,ƒ‡ âÌ_fæ\ .•Pİ~?(wGó›tÇ> ¤Þ™àÔ‰ ía_6æ˜s€=9x„kB®EI'г©Â*Í U}­Hq$û6•r¥RõÏÃ̺8MìqR»bàpJVª,S–r}4vBá­·‡O@ù¢o@b-)›:Òí'•efæYò^\²7isiÿ]C ÃA&¦½ªšÂ¹jâJ,'}£a&Î ØæÞ`×Z¼PE²wÚLÇgúà°ó±µ¤T1de£Øn¦~ÇP¨aj® ±p×eÐüœ.3Å\»l¨™RfÀ±R#I¡-f"9åF¹ú©_ò¤:í”V³ù@«’¨pÚFnÒŸÆ^y`Â+åK†fߑ؞4Žý‹ñ£6=¥N¦hH?Dì0ËVþ"õ2p<ö@2­ZfŠÃûßÿÛpgŒFà²k5é0Õ"jòÊ .!;ïÏUjh2aΗ7§nÔ¹¯Va“{šóžýƓ⼃á,³ýE,ìcõTÌHÁ»¨óøðÃÝ>!MMÛn»PØV±ôeªÎ04 Ë…µBË»ÌEBÝËšÈaÇFÃ~ðI>ŠCftÞÅ8+¸‹««htèhÄcȬÖ.«¾EÂj}/!Àzó¸ö‹¾*…C)wÐöNW«ƒ½R-Á7´Žp7æû§øçøxïð@?"æ¯"ÐG¥ñ×Ó#¡Óæñ!_n >÷ú˜3¿K+â â6ÚFM¿v@/ÖyØD_ÒCåØúyDÇ”a`cpàÉó q¼ÂLþ>îýo*{÷%Ù–$?«.y«û>§{ºgša€1dH2ÙhÀ4 C†É0aððà ÂDŸ³÷®Ê{feñ}?X¹ªöîÓƒWT,›¯kZ.6Š©H“X_¥ ÀC`À+·º©(E)N¥)zÚ¡ž†ÞèÛeXy2ZðJ¡b¤”Çæ2Ïùõà—Ûûãfí—øðØVË•O·-WéåW?P8›ÜÞ.Ÿîïn~ð½„Û¹¿&âó› Ðhb7i.G·æQ¢tVŸhÝÕ«+vV¯áN©"R°NBÊh,“V~‰ (½×ûG ˜…Bù#TÎ8_ˆ«o!¿càƒKŽôdþ‚â8³VT@’Å3°uÅPÒg¼ÁNç@w•ÄR¨á|©R±tÐq׆îU`d“Å œQÆr…ùMÁ<£‚Ø0[[«ÀÀV,²Qʶü©¼DÁC“Ã%”09FÐKy0ÙBóï!„J*r`&UëÞûmjV©@c l,ïaÈ-¼xÂÕªZ…ò-´bŠ8@T9[]•…Ú©häWVÃù™f÷xa8OS1ûÒ-Dñ@*j Ù[<’VˆKUðÞ ‚zgÈi`vquùñ[ÒÀ&°44…´€éÄò—)diÒfYÕÓ¦‡¶’ìcñ†_á C#sB˜rký,Ó ªh’ ­«’mÅé-b&¯qæ¼%³p¹ŠI‹äsêöõ)¢›Â)¨ŠDzÎ32Zß§#þÏåŒ4€uV–VJ+[YZ0j˜hÊ!ކÉ´,FÔ(W eV4¤Cè0$ä8W Ø­@¤†9q[[[ïØ„ˆJn¥eIʨ©Á~AJ%«¬KLµJOAuVeYˆ8R&¥|Ò—F™¡Ñk&cËrèV^k0Fv¯B¨ø4†ð3l3p[º •À!.$PUÇ·ÌiH£JKé1¥¯~S„q[9Ô÷¡P/Ñão„~[X:ªgYÆÜâh¹’Ì«~ Òc¢¬! BÖƒY¦?É  XGà‘¤:ôeY¶Êùmôõ¥Æ*€Þ°@e5Æ;,g¡òB–£q]ÿíÿ¿M§-gtƒ5‹È‘6ÙM’« ‚“,‡ŒÙ9¶U¡dy·Îmƒ-)d§ªZºrô¹d?}‘ë;lí~$.Âþ°ßãôúãå~ê̆  ìo¯~Ý-•TÅBTª6ùïk kjÍ¢“æðß!ûiP2‹ v×°†49”t`ÖN[Ú?ÇUk~gŽŠyÅ›¤Ýºs{óúÒ§eq×È=l÷'ܵínµ\Ñüõr}8õ­^;|¹Ãöðº?w^ŽóA´‚É›Of”õU†Å-nÚµïLqn_© 鳄§¡¾“ëéìz¶ÈU̦~Ø}ÖÏ/§×7aï}RN5ì ¸\éT?ä†åsqøÒˆø³÷oôKæ<€Ýh¡ùœdLQdOëf³¹^Û|vssƒvÄ‘GçSĪ4 –iç÷Ž:-hh&ŒM>«¨ÞïP ¥;¥ÆZòÍ9ÌÔR·Uè5é|fÛÅ«¯œy½À\8¯[–t¹Z®¿|ùòòü¼|YnÖ›Ú[‹ÅÝÝâñÓí?>><Þ~úáéîîÆëm3›Ïd ¢0­Íhõ´†d YÎúDÝBª¥ -À«-õÛZ†qŠ´®±Q8ï÷ëQq üo[b9Ï!škÝ@;^YïÈ?q铤aX>Íu¢§ú "Œ¤¢¨UeI7­¤"Œš™ÌbRC¨­«-å:®9]ѽŠî2+âŽg'sá)1(šŠÐ[ Ï/O˜M.N~jǡήfJ©¢‰Z `@¦ª6ùÓÑâVÄÜ”/ˆM¬#ñÙ&@ªÈqˆ…’ †aФ„ÉìR!7 @=ÛSÙ R‰Å+iß4ÔÆ¦& ¬?[ëÈÉZmo¨Ý¹aÈâRªÓBW±‚a*ÑÄe6 :0&ôXôqukPÙXC—!Íf†¹S°B‘ ìs›ŸPb‰©^ãjïÉÎÅëÅéøvܽ¶GÂ~ûzÀË=úôŠ?ÎÅ¡FÚëÅãtq¸¸:\M^¯¦o×Ó·ÉüŠ0Oç7óÙb1]ÜL'³ËËéÛÛäp¼ÜíNÛía³ÙåcÝ—I@îýÍäsCÈÙ<¾]†Uߌȯ £#ù$û «s·±Fë~Zv‡o)cÀ¨ D€oƒ¶žñÍÐ vD FES;ÓÍ #`Î>³è#Sx·@iE'³†ë£ùÑvM4"»jÆ’•þ0ô$†Í0ìtz3,mÖ¥.‰ƒÙÔ~UÝ/@Ë)P·†~`nÕ"Or /d c†1($bŠ¡ ºaÍs©q\ȠȸE@úºuiW»sŽäW¦·ûãîðÚÃi|;亣ד¤,žLZ–M‘6Ös…–ñT]•R—1­0¤Ö@× RYÕ•ð¡ ­t“!g…–M£¨ƒ a’ H1‡§‹zÅ †*Šâ~Æ<‘Ñ¡ÕôNBËúÃÐøÞs~Kù{ÂûReñwíýe×[ø·PYx* ´úFqÌð÷‡qñ1Tî·0d[gœRY@å$Ý(,)…üQ¨óñg5>À/пÍ*…‰FŠ7(æ* Äÿ*³ðïBãøÃÐ$½È u­óô¿ÿˆm¯ÿûýÏÕãÔ·òá¢_`’¸¥ªóRIe˜H‰ìlÁ“+£Xå…m€ä¶ =hö÷6áx8@£pÑ^O¯ìtÇ£Ÿ ñÎiÒÙ'£¶Ãé[9¤ðëçI*PlÚÕªA+·€ä0p雂PZ†•ãW1nÌLD 5%š /ÛnIe5¿Ð5˵t¡r\h ôã«´Þlh¦9GÏONqŽ>ŸûT´×èÊÀºÝ~òmš L§ÓÛÛ{\¨©×´¼7ê^q}yôó ¹”îÆ_x¾}=‹@÷÷˜Kïx^\ûé 6#oƒî½¬ÿƒ‚èl3Þü‡ãëq‹7×ù°?¤t boùm9,7ç>ÓIÿc°«ËÙÜ»©t>Ÿa ŸVÔÁ(+<¾|Y^ÃbÍ¢2ödá@% ªkˆ ¾Åe²¬HôTLìfbÈõÓQ%ÚnÄjyz½d+OzŸ3춇O¶­ÖëÍó—çÕÒ;¦œaÄÈÓûûÛ§Çû§O?üø(þtïµÆ9®œjdv8ðÔ@O—s¸ ¯ZzÛÎ,xZÔ2”2Koº¹1e®4éáÛ1'?Ém "à<ο –ïùJr“?bþJ¦lß8Ϊø»0΢ÊjUKÛwpœy )Éš7:¤,ˆ6߉c‡‰ýŒÙÀÙ c~»ß®9ñ—ÜŽ›xo~±×Ü‹ýØÞjR@m™žR¬‚Ü k`?ƒŠQÿÁkL&Rb8+öø®†1@6<-™âõ%”œ 3Ĩ~–-½ŒÐÒÅÙ‘‚Áncb%ªÊó•¶Þ3­.܈B Šg€"Ž`ÌP›$›ž¨š;TEv’ O¡äW ˆE9 ìPxd%² ‘õ=Rð¡!c“~€^ˆq£øLÅ@ªÕÉúÏ:‚(Â_†ö@WÉ p°gQÎqì¡À»¬@ï…3|Ã3Œ“ïM½²Î¥ˆ ýc g×¹C‰j0Àr:b0.:xÅP•ä Tò“¹ê4ýµªeˆú@(=zý7ÿê¯$ËÁ?¬Užþ ^IAR%‹Rx$¥mð¢èJÙmé²Þ:‹L1 §@—t<˜Å±IŒÆ––jœëÈÁ“¡líMÐS.ÂÁ=þ Çà ¶ï½² A] Ëm“jaœTE Õ‚Ä"0«mF†­Ð ,÷^i9üèF.Ø‘•ËZ¯Ûí~³Ùb1©Ét2¦ ÞVÄÝói6ÚïÀnnïôŠ‹Ûû;¼×Ù|žòÒéÕÛë( œÐÚ§R®[ºe¾tê¯Å£Wü6o’Bǰ(¨yœ¤%¼·r‹Ãòê7lhá«“*}L—ÛÓõÎ5é<\^.¼3¨ã‚<ÑKºYÑFÃ4-=2 Ùã1ò÷Ф‡ígUktÚ%JD‘ £"䦔æ»ð™6ú›ü “:ó§Z·;ïæù6âý~ÇI'ø©w÷7„‡ÇۇǻÛÛÅÃãýüfîåV]ï¶O Þ½4#š›,VŠezr£[`@2Œ‰Ë?3ÃQ‰•V 10ŒðP¹ßõ¦À Háƒâ’PHÅ… 0bÅ… 80Æí¶åKD%Ê(ïJJ‡*ž Ï ñ;psí\sOb>mºÙá½|Søõ¸?^½ù”‚]å©—/y…Ù£aÑ)5žeeÉŒ]r6U+[(½6¼Š¤¨Ha²T\ˆ²ç€(»±Ÿ%ÐR³zî ÿÄÇWJ»}ªTÁ( bÈP=7#qôjõþ(é=´Œ÷Y•”jUïª+ ‡‰£—}ÆààèÄV8Pô–Дï÷Ô†øC²Z:@ò?BчÜ060ù e€FêP”!«‚!· ˆc(â[±0Ìš‡cQFœâH~ d 6΂Oö9w°\lñCø({Å ZÆhNo‘¹ß2ôxчQJ’,bâ@ÿäñw®8)^™âÒÛqɺ¸þoÿöŸÖç®5€É®Ó–É…2ñ¾lYäFýÎFY*u‰ß¢ë\ydXRHl}½åš,ý,£Ô‹§bX‰ À§™ø©LR„Ð œß±ø/ˆ¨IªMÈɱ™²ð’_b±uÝ·ª¬‚b(¨~*zI¨deq„¦Ëâ>n¾Í++ ¼R‹¬„2`<Wj”=ù‘ …ý-WÄ`$‰ß¶óY6_Õ¤Õ>æÌùÍÍüîf1›\ç™v=³×:>M`ºÁo»ºšÞâ·]ž²œüLË–Á™¶_z›¨Î*ãâ &´Ë;×=ûÔ~9A£8ÅÝäÀØÅôÛöG/·½ú½Yd€ùŒœ^ “«‡IÒ]ùÎ-@¼Ë;™ÎæSzm:ÁùlsÅÈe ™< BõÏ\€m ÅЃ«kæÜé… d€\Õmtfjݘ ’W>€Ð(û ˆòßín»Ù¾¼,×ëõòåe»Yã·aÇÙ|2ŸÍÊc{|¼|ºÇo»¼£+½Îjz©-ÆHEôÂù BÜ2­T¬’éùúy¡(¦b7Å„âm±? äM1¤T ¹ ƽ¦Æ6PÄCQœÃ<5ÚTl bScòIFã¢Unâ*ÒCÁ™X fe}©³ÃCL½çÆVÈâa”µÓLšàói…£–YÈÀe^sþrôó.ûíþ°ÝíVÛõóz·Zï×Ûíz‹·Ïµ··ãiÏ O¾íñº?:±ó*Œ*5ÊÛ›:m#‚CЩBMmÂä‡ÁTà s– „BJ@B3Oe·¤üC®£(M&n=FÓêl •W±ÒŒ •ìAÆÔ¨Ua—eÄn-9„Ω* ïö/ù·%D~œá±â–È7‚Ê3ŒñÞ1$¦lÁ‚TGÜ™•DJA%1 œ– >h.Xi¯¥8‰ B~ŒÐ É훉š¦ü]xÓ°‰¨ Û%æ'V(=³’NÓŒ¤Æt_­Ká =ݞ͢6ù‡ìÆ M²©s\Ô~ì`íUiSi\œdáÉŒ\ÉBlxA1ôRY£HUø> ¹ºÑ**¢GQYE¨J€êqjI¦ÕI @jER¶BÁywµ-èŠàLb’ƦÓöë¿ú›\¸##Á%#&.MÂϱ*LÚ.®Ê%ŠÕúBfÉŽâ© $PÝÁÈP—è00…ÝØÐ÷£}ÃkÃâq°®|ÿJ× '¦YòSÞ[™Ì6S][:õz-àjà§Ù ªà¨d‹]Al›kíÀÆ vçwáUÚØª%ÉdT PX]3gÓmÊ™ 5Õ Ä=IF‹ÞAMsÇbûžC%õÛ(W}¡œÐiâ ømÿä¯ÿ¡+SÎ÷/¡°Ì$®u+œUO«J$-©(ˆq‡FUÍ@†Q–Æ®qdUÜKz !a’!ÂB•éÅË·×WÖTjÝà\ÓûAÓRr×ÓiöVVâ‘#è:ÃþT¿à»¯WëÕjUüGÊnwqÝöœ1añç<%N·hº˜™äYÌà®Ùèñ3é³kÆA––¼ŒÌ3¨pC“hX𬏠Éô‚°7¿M¡äô¬JŒjH\½9PD`Œ ¤GZÕõ1§se™TGr`X80Æ¿…6‹Á"ªˆ´€)¤Éü Ä"ôUý½‡ˆiÄBj8ÑÀœ¸ uØ­ɱgnä¥ú˜¨²U-æá¯xàIܘ ¥BwÊ“«ÜÚz?$Ô4Q+˜Czð»Så}¨à]KZ¥AêB×PQáE$]ñ¢ÆàEá.ò[ Ã5»üÊ+ø¶ìÀ00W§h…q •EmÙ¡’•KÌÚÞ1Œü¶hDÂ$ÛN¿þÏÿË¿Ðgó>€AOuæÀ>­Gp8îqŒ¼—%Œ ćÂï³V“Ѝ%ª*7"‹ ®b亅’„bÈ¿íq* ®Ÿ9vV8¬"•¨±åΟ)º‘R²ˆÞ.üäX:qBéš–Mºô| T²bàcY…çÛ¶èäºÖVS(”e89­QH±Púc]­‚‚礮6“žó«E‡ÃëòÅ×—~såµ·.µ‹aúë×7<¶W?žF†§ó–ŸT˜.¦—³ë™×Ûn©àæáF7X·„ºK=ŒæŒª.«.ˆyÁF“«‹‰û„_e{Ýl‘ZCcwz;¾½ØZhö÷ Ðëëùâf:õíÖéÔ+|´)39Ò`›ÎfTGÒ2® ºÌqŠ;.´¥CËû¨Æéb¼(²(æ¥êÄ~€˜ðåø.g‰’KÔÂhÔƒ6G…2Š¢q~ñµ²½ävÓÆ<ÐHÇ×ü:›öúËçÏœ¸ÕŠ]ši‚.ww‹û»ÛOŸðÛ¼OêÏ[ÝÌoon}Âakg×™Õ J:G™¿¢áR¦æ„e‡5d9ú±0™‹ìP¶ªŠ È‚HÌŒo¤_„E\VtÀä÷!™¾*ûŸ³šÖ#r p`àÊÑVžÐ{<0‡qƒURŠ&Ju’b"Ž.uŒÎ¸nœÏnóœÍr½}Ùl_Öë/χÕv¿^ïñÉ|¾­<³#«§o}{¿|ë×rÍôÙ­·xlL^x´ÙÊ6òýeÖ«,§u¹e*¨ úŠ©²M97[ÝÿЧÕðj`i¦^q$sîPpà[8$áˆ/¨’Ŭ¢Ñ;|+-¬ë[æ1åÛÜÐÛ\®”PÕq,âÅIV3Ÿ¤w‹6ˆÅNGö-¸)<Ž ”<’ Œ{‡¬Â 6Kv¨âB®Òb.ž¡`+òšìvÈ1œgæTQKG%Sv„†G·!'9¥CÍE‰‰I5ºàa<ÊÆ8PÉÄ,ù²FðQ·Eƒá[" už:qe3ýÃ;o}u,x¬Êõ_üƒßéò0Ûµ‹ ËO¢L^Dˆ_Y Êc³ #k˜ÄÙÐü”š ÌͲ#|öWul ¢_Fv̶ÏBU¶Ðlñn âxSÜ„ žÃF¼m‚.µ:˜ þ†R9ÇU„EÇÖ‡Ùg¾,Þv©'Út(ª•´þPG³rÐr°4/?I$¥@Y@ÿ²±)×%F“ íý‚ëþðü̉üfµ\ë·y¿åàíl¯±Þpè'¶ìð±}ú4½]N¯æ¸øm“«Û‡<¶«ÉEžŒb)§º:u¤Vk¼~Ãù€Ø^NeH@;Ot}Ü6y<Ä×ãNŸ?çn:Åðw·w³él1¿YÜÜæíÖÉ|>§M“ ŽÙÔnšÏuÃb"D~›6³·ì(÷D¡.lToh8uÁÛÃÈÈñÜ5•´íF¯NQS7ªm”Îp%ÐøêS³~¢I0(­¬dY”tÝãEˆÛe„z§™âZ Š®ÛÉ”{ª³?.sée½\}þüÙÙ´YãV3vi4NÛÃãÝ?<>}òzÛíÝ­/—ä>©RmJ´R“’œ œ³,ȸäÂúè—™æT©i ÿÑ´ÀžuZ2SãÐÕÉOÈ>bX©ð–,DA`0z¸1ÄHÉ53Þ‘9;˜òMé {Jb¹ˆaZÀœ.H&yñ!Ø„oœ/ܺÃI1U‘XŒ¸æh@Ô4”Xy"%5X–†ÒsÕT²x©Ô¨™#ÔZ_­®îkY6·Ò¡¤XÓ$Ù!¦r\I©ŠZ¹˜ÊÕÄ…©¸Yûæ~Nùöe÷vd™Ü옶'Ÿ 8x6Åòâwsò¹º ¾õçéXV=åò¼<Æ…««^tóa¸dný^Œ?”æ¢uøGÁ슞Ô놶*lÈN{´Ý2zi*fy(¿í‡§§ðá°H~Bï–±eÍÈl‚«"ƒW‘dÐk“d¼¡ ã¸ëÚ …ø+ŠíղނF1Û ‚ñ‹à‰Šž.‰ØÞ/t QbF9:,Õ7õ…`¢’‰ƒ$Þ”On@"1˜k\TªÜN¯ª­ü Ñ%Ç´¾*EäQRý[¸Q+‰dH.“Ì òʾ©ÇAhécùQ¹ýq½Þî×»Õ˧m·Üì8Úù#Á^ùfd¹Ö±t¨ºæ¦¨Þ›²éü±–êýÎan¢:4âÀy×tãÈ$¼&—³e‡«¸g1^Ï“éÄÖ€MZ˜&ç¤ÇW¡Zöªmd%´d£¿1 qá* ïA’D»è ZR96^±åaù²ER×Á¿–ï_%ÈeRŠÅ-p†p–SA‚®(ÚXÊžaƒÊ;0+@.¥« ÉpÛâêJõ0kn^u®eü×Ü…Eymº£ÈÙèƒ)\S4ɆZ¬éÜFrÁªž¼Î&SrM…3B£'.6   Tå-'ø˜a€F²ZCR:]”šçȺªÅJ¸!]×’¥8scªÊKÃc†,mVÂ×, cƒê¸X[Aðëßüåoؤ=ËóÎ[-2â®E'¯±Ñ?¬_ÔN¥“ÉŒL·^˜.üXk܇|¢ôÒÉSwQÖ†ª¢ÃXœ8 !Å{H hj<ƒ©”ÊœqxÍͽÙâÙVCÉærÅÞv¢„Ív‡“·p‚³=US ´ò˺ÉH2sSîBˆÓ#eýX,=*êÄÓ¸¶;ë²"G nòi–Wf¼ýA=.ñò˜¿-ḅñt¼À¶¬Ýë«ùîçŸ?¯Wë<s€‰¶Úè4·Î¾Qèt•Ï|ú}~”vÍñÛð™nO÷“éõÃã}­üYú­×v´[€ DXÚ鋦¤PŠNc °ÅÔ¸`ãÚ®–»õÆ€ËN±xOxg·÷7÷wúmó…ÓPÎß<%L'øi ¬ýŽüÜt˼â¦þÚÙß«JPó1a;ˆÀÔ˜(ŒbÕh›£VÕŒ6¢4ß®‚…Á¿ÍJYN ‚-MAíAT"B"‡XsêUÌŒÕh:Çò½‘š¯|\¬×6㯷½ÄoûÙûËû=ýƒI‹Ùããý§§‡~x|üôx÷p3[è±a—«©O; ©¥j€‚,žê3djÌc4¸{Û¤l×0³Íae¦­£W¼œ ZR¤þ,hì Žé‚ØÑÚ*ù²äPz*<ˆº§x äIV(‰.5Gr"6=–"­}ÙH¢JŠGÃÁÛ|* r*]\s)žT!Ô!— íà|èRÛC·Û .?uO[ü<áa½ôå ÕW?ÿ±_mw«íiç9bœ6uŒ¨^~›ÃÎËãüéÖ{éÄ¥Ui>ÑPˆn\Þ=ŠÃæU;-”÷<ÍÊï43m}gÁ¡h%¶§þc:š[íÁ¢ 1»PÎàrK¦¬Åƒw(ûC÷àJm‡ÃÐËøÒl¡ öšƒ·CágHJQ¦Ý­~JƒŠƒ ˜dËè i8@tîX‹Qæj`ñ ó=YhZ®O(À€ & JKý•º…!¢ á•'‹qIBf ¤YòÎÍ0³Z­Ú’àÄÌ.æðibePf“ˆ:"5ž#š¿`~ª…žÇ—5]‰¶lè¦-au½ðhÓ- Š-¢,[ü=ŒÀRµY¨„ãÕ †¨cÚ_•—S[Ì©À^kGGT*ÝQE3¡1„Õ'AGImÞ›0£ò›ü¡šŽtÎQ:º DDthjZOBéi#CLÝ ÆY8€˜ÑŽK­uõï¦Æ²½ƒ·ëÿøý'í~ÍNRo <ˆÅ|‚¶îAž8¿:ú€ü…7îtÔòaý<ï:å%7ºÒëFthNX}Љ5b­Ñÿ !¨ ô~ön„^QÞêÝĨ‘¦zéÁqoI¯ÀyYÞN*w¦ÿ„|GVBäº:ç\mª²œ(ëÛз”È?1t1tu 1;Rº€zjEÅ »È¨WkålN›öõ² Ä\;‘˜¤Þü9u™À‚ÈÜïŽ[wÞ~ýü¼Zm>þ²Ù¬ý9ýi°æãm>Pvs{s{wËÞ?™O.&õˆÚåÛ5’Þp¤p îî~øñÓl>{zzÂCÐQ²mÉüPÄ ;£KœììFòžª7IsÁa»{õwýõè\tƪ³ùäîîöîn¯vwwãSmþ×góQ-R½Ô§á|™lŽ«wƒþ^…›Íf‹Åbî—„ohÔ<÷ ¯`ÃÌ£rƒšÚÌ1 ¦ùT¼žäp Å¡[‡¹Ê%ÔJçžìpÔØ¹ÎY’ìÍQâÐÊeŽì˜©»ëâ;9—œ¹Ž¯{ç~ön·þúüòüu½Z>??3úŽGÎ.iåýýí§õ«§OŸïï|¬ínNó/é8犡DÇzf^o‘õ§ÉJqÔEÒ5”i7‡Ÿ={öql1Z>]‚=R6"š4‹X/4YC§²€ FWæ° Çž PoæZçF«lõ N”ŠÓ[d¯™h\©–†3 ¦×"¹BþÑú"¤ ¥å)&[J‰)¡=°WGÍOHXcð ø^Ûl7zl«3òërç7Û¶›—õq›{£¹Œ›FÔiO 8‚L ¨nR‹7¦”‹…§µº°'!åZ|;D¡/ rŠÃºžø™CµÍtì%À"‰W/ÐÕÕ”Ö›N=KeD3.r s1TI EÁê¬@ÒX(&$ª"%ò@^ßéåëœ7YŒÉÉ0s{Ihoï(I°2¯Ü»öS Nä‡ü”@T毫 ™,E4–Ò.(ÈNâ²mÄÊVm‘¤ Rm‹WÁ¦Q2-Ý|¼˜ˆeÌ..¶”7Q½Æ*:;qÇtü‹=Óêê¥ Û$‚lÕëýî” H—[ž6Q:Vsw3K#"‘.h ËØãÝÎÔ@,Ã_}2k Há϶d_°_5¯Hu¥I-e"VɬYeJíA£ÒÇ"&+/}å¸In+?‚’'+O EsÌAPŠUD%+±Ê–ucoµª+«Àä@+1ˆµ ¶Š Šh±ó¨DAš2»­lnaîbªèNu³fAðÊ}eÀVj,ãë¿ø'‰‘Ðëtyõêñúý“."f“v(Hy¹OŠkå;ÐAìð¦ :Zèæ&½/Y¥‹’lG¥Òi±jftÖ¬,°qIÈ€#®'ãi¢×ÁŒb¸ª²)•v›ÝéˆöK ;t5m\É   뤩À+ºÂŠ­ŠˆÆÕ4·û=ªTlø‹'¦ûdSÍÃ(4üäóbÒÓ  ;Q\^µ»ôß*{»Úìõ î_¿~Ým÷ÏÏ/~¢}ïS6D?r<<³©ÿÕÅôêxùv`íbõóRÙÛÝÃÝt1»»¿ÿñ‡ð‰ã‚Æ„Tˆš4ÍX]îUZóÛÿ^Œô*’?×°÷Ã0[ÔÚبv>~ f¦?|ú„Ó…ƒxw3™]ßÞ.®óöC2íDÛY0•ŠÝ¼7ÞxÇÔ_WMŸÌ]ªç>ý†[ç®óHÜÜ¿RÑÖýg•AËö=ä)á¨J}â©Û²·£Ë–)„£«DÆM]Fƒ~•×/2Ï3—ú@‰8ûëðövÌîë—ÛÞVK6Ç_{yyÙn7ømN¹ãžAtsƒßvóôô€ëvÿx{s¿˜ßù.ÇdáÏÈ28\„J*‡¥×P’h8Ð>©"„®–e«ˆmm°÷küÉVü2Žd3Á™}¨U\5*PJØ’?µbÉ qx"Å\œî;²gY4üŠEÓ’0†J†œihO™(«„EHFÊÊJv“[ŠZh0ã€X<í•/Å’dy~’;¤Û½¿…°Ú®¾.·ËÝæe³ßìò3 ›ÓþÐ|'k(§Ó ðôŸšFãdøsømšå1ƒ’àÒ¡ßáb¨¸k>êÕi¯:ãÁøóÅ(+c‚¦#¨wkM«š›Ÿ‡ÄªÓJ!l+±-(ãöÿH/,x«Ô„P±PUdÑ‹¯Îʵ o+H ÿ‰‚{‘L-À?œqRY8G%õ¹ö™ ׎œÓ§åZ÷¬OЧ Å«Ô¢£ B—ðªìwÂÙ'C‚{‚Éf+‡Bƒ2^ JõâBò*i!Ã"IC ǧpâªF’•eßæèà€#ˆ­l#ætÉÍn}†Ò“Ðå–mín³!06 ¯d&=“TGÙLõjBr#ÜD%-—Ï@$Ž*7Éã¯Â©Ý]Rª•›*Ô @G—,ghrÑÞ|%|ÈÀDmWJ¯`Þ7Èba÷JƤFn“±r#02‰ÏEììBBiF4Y­išªŒxQ­0Ì|6K‡:eFü¶ô/ÿë\ìð$vK–ŒYžGbo!1cÿœÍ={vï×åd¯=ÕAG°-p^›©g8ˆ}HžSÕ<ɱc¡Ë—H}€ÃG:Œ}÷Ѫ,à‰f~Sý™ÎÖŽÄŽ7Ç€#µµˆ`ë°$‘í E™LTû’}œ¥À¤§¶~Í?KF\Y9EÄ—3¿I¦ ±6]“ÍN`‰õ*ûsUÜ6è£’Ë ‡bvÈWwí[eÊ¥*d}ÍÇÆh8í.[½¬Ö›8j/ÏË—åòóÏŸ7ëÝòy‰ÙÊPÔ–­‹Np¹DN'xÌ!*`j±Øù+ ‹Yž|¿úôøÃŸðð«rµÍ £E5Vÿ4>†ÈèAN–?Ü—Ç«>ù¸ÙmW»Ýj—+^/p?¸|{zzœL¯nï7·8aW7‹Îí×2øAÝ‹Õjy8뵟2Ù12ïçiJo±ã´¦'¬¼¬š‹ ǘ+‘ ¡=ˆúm]ýÓ{Ö®h#$q=ZÐMÊHpÓ% ßMÂû8¦òÒ£9¥Al•N¤W1Åáp:ìOôÚvíçvñØÖë5±Ö½9?Ç,w÷·O÷Ÿ>ùd8s‹-ùrr‰˜Qâ!mkâÕÜæ:æÑv¦È; ¡4(Féß~ Ï2TáaUn¢i­™2ÆKR#ÉP+Šœ€¹Al•}–‰Q \™zQR=µ½ÝQ¡˜hÚ*É< „IgÎ^°41 …v…’6„µòˆÐTøšH–î:â›>Ž|Çèz»^®^¾>¯_ÖÛ—ÕníŠvØî8ïÒl‘¦@ŹN×9Áq¨„jQEÓÆfÓ)0s°V`<¸ôÞÜ8>I¾É<™ê,à •-mWê¤$fUl‘•™•`ÚÿTœtÅBʦ ÿA,ãÜÎs.˜8/Bï"áN?fÊg6¹XL#]ZYœD .ˆGÇØKáäòOE5Rð aÖÝXyå“Sf‹Õ±bÒ–Xt93‘Í*ÎÌô´ËNNŽIUñh J×u<œ¶:TŠU2B¬ I©¤ÕNì5ùÔ®TÂt?JïTQïÂ$a¦$S$š ¥3†Šz¹ÐÛ<†‰ˆ0”¦XŽ¡¸ý”’)*¥3yüyÂï°‰þ²Íd‰ôG & _.ÉÒé†ÒHûŸ J½VèÒ¡"Ù·<ˆµ¥±œAJÛÇWXÞC± QIŠœŠ#¤ií£ŽQBfr±Ùä Àˆ ׫E4‹î— Š*8ä*"‘„”ª ¢IGJŸ’=â)°¨5³ºÇÆ Yb€Š¯ÿéÿðÏüÍK‚—B€<^äSæó6¥îfPÃéäÈ$jmÔ`ø" usù¨¡|¬pµ\ãÐÖÛˆëÕÆ+m»ýr¹ÒÇÍ[mTàý]Ï«\†êKz¤ÙqØ&ðÛf {ïñéáîîæáñ¿j>›‚‡ši«HôµN¯„n{ÿs›´ü¶=~ÛúÅÛC»µï*` ‡õå¾Ètæo¥ßÞRñÕííœE'¾Pë*}y~¦Ó7õ“û£_™É÷EâÖûP­ÓP^årÅN)_WiÅ‘R]»6ÊVC´ri®ÊÔG\mJkrp X`J±Eò2…6m½lU“¯ Nϕߖqe +]ù|CÃû¤§ýNÿûåÙŸFxö½“t¹|QÔ~Ûµ¿‹ðpóøx÷ôtw—-yëkä¢Eûæç¶ p¦´¥á=´¼@O¤¯9iCïÚ‰,×3’NRÄd¨)Kœ) 39IÒN›ôÜRÌÊ“¥d±G–£-å뎰GÀËo«Òrt°Š¨Q$qCXšà¸Ø.C¥zFlЦ-œ¤JpkEœ^9Sb¨ÇoÛlV›åˈ3«ü@‚מw^ànëAÉÑÔ±vÖˆLkˆæ5Õ@«ýšË¸hxó‹<üpËŒe.ùÌ@»Ø†•‹iBÄŠØôv,ƒt“1£ÆÉ EIfc3‘Rnl5%ù«z¥©_¬œIeƒlRi§1Žlö]eY ‹BVA³ÌD:´­LÆŒmã¯jiËkØ’lšc–Š2mÚ¦L+Ûõ@"¦K†3J/sŠÁ¸HšžQ-Hªl… T™ Zg)UÒcËâl”T‚2i‰e#«åÈ€›`:Pv-0·ƒËXº¡©Þe”JÑ/0V2QUîÑÚ¸©fP5˜êªªß­¸©&5:¹TA ƒ•ÂÔTR«´ôSHE1ÿ‡ÂÔ¶1 Ÿ“aLêœk¢iÂ-bMrXt(k‚Øë-°¤Á¤ËTnè‘Ô kPJ”¢Ð’g^#oD“æ$)B$T{;…kûkÌ(pý×ÿú¯»Û¦¯¶˜»ùK˜{G®eé¼éØÄ[pv¥tvgNP½&Âî• þìrå´|T‹P×Û|‡ÊWÞõâtßÜ»¯¾­˜KnÏ`sÈeV*©Xª¡ ´'S£2båå`Ë®N—ùúÿ„$F×§ôû#æˆ9É›Ä:,±>‹ä3ÎíŒdÆC“ÖE/½R@UÍøjÄ|„䮪fjvŠk‹y•Ά˜­¨x«8®4Ëè»`Ÿõn³Ù?û½õ-Û?~ÈjµÆ`+B5‘¯þØå¥Î•ÃÊÛ×S¯}¶˜}zz¸Åo»¿x¸Ãí¾¹]”«¢Úi0-(;(Fœædhd¨B½ôû»Ôv½Ý¼l6KÜ74ÞÛÓ¶øxÿx?^×õ¶Éôa.ä×M>õÑZ½Ë¯.Ð 4Í¿ùByó˜Æ6jzÍtòaަsÛºú«upR9ló­1EF@#¾7ª¦‚ËÄX" Ž‹K2Iù *ª«²Ju¯”¥^JÍè*nÌñÛ.Ñ}O³§ç/Ï4ðë—güT†ûj¹Ä„èÅÌÁ>÷wø¸Ou½íî–u=ÍE”@”4RUÚ’z+kÌ |`ˆÎ 50,™ B5–Îÿ-ÕL#^È0JRÛ{褒 â€ì UI4ranXëˆ ËB » ¨~ «BdV¢JmzV¼U)œùÁ,Q¸ä’ÆsÌ`Çg†ÒÕŒ?–0¿ý±wn⃯VLÊçgb\7<9NF_^é®Õ™FÝx,©©°,uÊr­9U4ÚA$î ¿˜3÷‰Õû[<{À' ~ §®e9gKéè]MI5n1¤f§S·I¥k/Í &Ð>Ö¨ì=—ŒÔÍ‘,ˆ%´šBéêÇp ˆÌOV ÊšfD"^9¦2Tbï*Ài©^6“)sÖ&æâߪ²h(äI”J™Ìw³Zí)'žƒá;³<°ªwÙˆþPŠ_ ņœÙKŽÌ°t0£É嘦‹‰†R€ ãJ˜-´DUWq€­ÊC#÷C z¨ÄŠä_š3Ÿ1*˜­œy±üážs-Ö\N•ÃOHBRZ¼jæ5J¡ñ9¶ƒ†€Àc6æ†Ef–À¬’ŽªHVã†!}ÇÁæÙëÉ¡ÿ@]a³]$YcP)‰\(ÈÉ…à°¤9‚,ü×@"ʱ'DM­ŽŽ®6Íeh½£ÐR J!ÇŒ’ÖAz‡V¼ª¬æREú‘Dšš¡Ì“ ²4ŽåÜ—°ØMh˜rnqk}b2 Z™–êÙE/ƒéTZ³½ç¼çi0ðµZ†ÂùO»ZÙ*Øð0¤~ Í€‡Ü8tAÉŠ®^HI¦„€éP[nÄ*n…ÖÚª%¤sÓ:w• ¢’V4üI³\Êöâ•]l,PM¹0ŠS¨ÒüŸÛeqÇ—é@ÌoÆh503êVÌ‚fJa)ŽKI:ÐZâõßüÏÿ|š«i^P»òZl¼¾\9¼GzÑiÁâm¯tD±bTµ/eÇÓ›_8œ¼¶æG¬8x‘¦žƒÃ!À§U¯'3¼4á»!Î'Úfi…ÃKåΠƹ•ùì½-$ÎD ¾:]Õpªƒ8QA ¾¾õ vå"4{]úð/™Mg4ËÖºÝÙ´(M¬ªñ¾ì<J¶Bh,\ZcPa- cŸ·¸ê^óåC¶l€ŠO†ðM¼$¹Ùã§a¥Õrޏt;ö6ƒWþñŽzW¥ó¢[äžètÈ}EZA÷Ýxoåúá÷mN¸õ~ÜõlîJÕ’†Œ çÖ¦·É%ßÚÐð°Ëîía»Ú­žWë—5~·~›?”nÃîïïf³kï“æMR6*™Ì¼Ã¬¾J»X¯w´žÆæJÛëz³ÓVô:T#G‚õY7½7Fˆo)k>=ÅæÎZ–í©Ë o5ææå1÷¿-ö±VmC£ZkBÅ}:"‚È@š3R,žõW[¥¨ƒ€!ëm%HI –ký¼öÃkž8ávç>©'zx»õzr¹˜O±Ïãýýãý·¯½v3±G2—b$+²#¡Õ -N(b­ ªž&´‰¬Ä½\²óï€,ºÐ¥},ŸŠd饚Ѐ㾲Îrú¿à %Ó"Y¹¢ZtkF?ƒd8kÞ$‘,GÉQ –°UE «†ÖiÀ _€šŒ2`lå9HV.ϸ<[ã|âàõ¶õšS ¾ §Í‡Î¯ßü¶HTÙ43뢡Y¼8ìLAŸO&Y6R7ã7Ïlà·-n7÷7^l»¿e„äƒÌS˜$™é%ªoÁ#&-KÍíhn*€ËƒK…Ûjs쇢Dî@±T³O&'B‹b\À”p­:[ó‡Üj€i"YžäFó0uyõ_ÉÈp…%Á–tÁMÒZ¨µcjx0U.N:}åðšŸ*U„¸jˆ…7P<ãÌ:+‰êÄ”B-ˆa˜mG5Òä A†"÷¨¸„žÒÓ"ÉŒxr›ˆ¹«›J`8?9t_l\LQÆC&AJc‚b·’ªê»ìÊUV“˜v 5çr#6zˆ®ÎèìïáéŸÚJ™Ù¡Ÿ!U†p¦†¤ý;q@ J“.Y}r÷ÌA}ŠY±…× P2$„¨—ÐpeV2S¶ƒVÅ "¶ÙŠdŠ„ZÉàDgH2ù$ <bIf›Õe$õvùüŸÿ›?å‹|3Üòrå"[Z¾¸NdèuQò€_æ‡Û¼Xvñz±Ï·"1Pý™mõKGÛÃnsyMõ¯—ׯŒofÑ,ox.|b¶`™º½™y‘ï⌼i–´‹ë¼äè¼£”›-ä¤->ƒýXeãdŠ~V§mç×P·+6ØãÛ‘…Ò|óÙoÿô··· //R㥋5âT ýÊ'î' èFÐ0ô’.’÷/¼ÇrqÅö£ÁBšgx‹ÞüòÁ¥rå¼O‡îõ„ózôËê¸h+8¿,—ûãiµÜ=¿¼Úym©ž™¹œ\áQÎèôÙdJ^ºË©ýfƒqØs²2^¸Ð›¹¾ÌÅRróé‡ÎÔøÕSžYx=lzÅàÇì|?ßyÁx@Ã6wþ@#A™ž_èP.×/_^ž^~ùŸú¿?ÿü~þòû/Ï_¾ì¶ëÓÅát¹ÿÝï~óøtó»?ÿÍŸþÙŸ<<ÞþîÏÿÌÇÝîèS¤øhöÛåËË–áôóO_úé3.éOŸŸÛg•3´P$ƒÛ/§û“Qzrt(§ ww·ŸðyîüñGZ1ÏÍèU´,^úÄz³˜ÁÃ.Þöû­ær<Øã~·eçíÑ·õr÷õËr·}ý·ÿößÑ­ÿÏßýûŸ~ÿ~ùzùÕ;È7³ÇÇ»_ýúÓŸþöÇ?ùÍöÛ_?ýðx÷ô0¿õzÛ[¾Ng³íc§¥ªS=ûÅ™ ŒGâ4V`Ø`ã¶.ÁMf+С±•,5jšµ*jÁÙràx.:.°éÝð9´œž ÎKª&¨ S€àçÕ*+˜”—2å`¯êºàÊ «´Z1(U U på÷j‰}‹þíš“ÎFXpÈN{]·ãŽs•õúëòËÏŸþ‰ÿ/_~úyý¼Þ®·¯û\lㄊQÊ PËãÛvëöJ|úÈÚ ùíßë‹él–iqò9 Ö¹›ç<÷O÷O¿úôÉðÃ'GÜb2ŸY„‚>¾¡½Ñ9s¦„Pùca ØÌ4,C[¨qR Õ:–¨%Ïô”¢,ôN¤‹< ÄÐÄÅY ,úU’9÷z³ÒwªM§¯ìðç«ä@“]F)vT·6xìzyØ–´‹†§v­–Ú B¬‚àD¤‘¶çIŠ?ùí1£J6,`}ÕEch£Å£BBv“çþ⟭„Ì”ø¸BÖä¼oñ’W@ÙÆû`iµ“H~ &ÕÕkH3l€ÑE©*±öÔD€ç3¦ŠVj‹Úü&¨µn•OíЪ¨²LyĬÔWæEH¬ìDÎÔiPe; • ÈFèPl¥‰ÿT_|QÅb œnLÈ0>‰Ó¡ˆÅÕò¾D‚?ép8ô^IÙĬ¾Ç7ßML eè„7:\ûW¼:ìœÒSïMoȹ74â/Âõ_ÿÿU–†tmÆ7H\°v‡TÇ'߸Ÿy/Wb‚áU§i¾µÅv4õ×*]nÜŸ¼°“J¯Ü\t‡ë.Œw ½U p’ÜòÜær3yJ„Ýì>g¢?€àö×ÜÄÝ×}ök›í4ZÖÁw0ñÿv›ývcÃÜKSl÷'ëD\VãTåˆÎ¾=t< xrÛÍ–Š]¬wnkÌÓñ¹ÙJIZã]`'¡ï^øpÚù3Tk_/ÐMØ Ž®Ørõ’›,Ä$Œ½í‚Óø’žŸ_>~^£;ÿ>:¦Bñ-êá'Ç[«›×žÅÞ®õ,ôœ­úyÚÅÌ—ïïîüBØýÝããýí­ßuÁÕ¦pÜ$Ï*|êÌÙ®)0mÆ7•ôæí’]´¼åºßî0éz¹Y>¯^¾®–_iÈz³òýüSºˆÕ­ýñîþþv>Ÿ<>=¢c•­É±wI‹èJ µÝSÅaÊ}iÁ1Æ(ÑãG‡cV?(‹ìåº×À[,n<•ÎÙeëŒÐ+¯–°P.dýÒ ¶ÆÿjӨųAëûÑ\†JÖ%t8F¤Þ\†®þx[¹²òÚý´È;fëÕöåyÅHûýO?­éÍ/_ŠZðtâ‡~ñ·­ž>}âhµû_^NnW Tºþ3+|š @Чå‚dš•v4/ƒÄæÆ 7—ö%Nj®ìœR…Eƒä})Ъïýˆ‘-Õ)à$ü(¡šáд,PâùhH%õæ,G¡Êv:¾9bK°d£JÝýô$èßwóäÊ·Góƒ³/œYÑ­ô2kãù.î6,K¼:ÛðÅOeV¥nÖMýF§{E% «¾#!/ÞÜù‘q!.ú^J\±îo*F[þð‡vûN{ÿËËêË×g÷s­ƒ@÷ÌfÞ'½Y,05vÅCÎØi~(vÆ9Ãsº»Ço»õ›m>Br›·Iür'lÞ÷Õo#ÆEsïtäÛùt{d9:óL’CÆë´d·_/·«ü¶u>¿Ù.׸¤‡í78Ͼá±Íoæwwþàæôñqì·¡¬áŸg·ÕÇ¥ ܸ4  0Z¡NŽÆ>¹(ˆ úMúÛÅ™å¼Úk³‰áÉuТ{Ö¾Œ%c®TƒÒ*d`9$k~•Ÿ¦A—dÎã!DWz‡ Xx,+jyøg]¿m{øýO?3 ÙàÙïa¢n§GðÕ|“ôÉ-ùþžÞ⤇‰drŽ#•\gJ«ÃCQLŸ!í²@gIs:}È5«f^Èfkfòˆ‡5H)ã@± ¨/¨æW\eS¡¨U·I‚že±‘'`µnöàEê@ >‡BFµ”€P‘¢ÔxNƒéƒ5bCINƒ•U­žLèƒ+†Žë@ùmíº¾/ÇäZøËòåÅ©ºbzïY`¶l,Y’©$-WyÑ"•TýÉ×S£*G»aùmÝöX[ùmwþêÈídö‡kYv½u¨q"RÂ:”e¦jCšˆ¡C1@Jâø()´tg¦4e×Uù/©hn¸ø—'ª…³u¨J¤vA¼b¡/È‘8œÓàöLaN1TEQ¨j,.$+ã9ÖÛf/XšC³R*R*i ‹V$gäšSÇsJ!E•}ÄÈ_™-q²B¥Ù±˜§xµËbü¡oÕ&Ežà9V‰­P@¾’&_˜ÆÙbx¡ |$"¦¯ (³1÷ø\ S€‘ªüª\³×ß;i 3Ã&ËgcN¤ˆÎ.^‘‡£ú‡Ð¸{c9œóMBqvütû¬H¨@¢. ^ð¨ñNN•n#+ã¼ÊBvZ¼«¶0 ´*‹±M22Ü…‘ Ã,eSåõ?ý—ÿÀzR³%X˜‚1‚²±Xy–æ6¨À´ûÅ ªuåý;Hå±]\º!eHû¨‡Ü©±¦Ôµ÷‹ü"Q.±:áçåŠÁóOCæ`ÔóÂÛÑ›O^)gÖãH¡á¾ß<ÅÛ!ΧEš›ÅÊûv8±øæñ~ï{Ò&„°@Òù²µ¶ÐVd‰€Í«y¸hû##‰ܧ’½¼çg/rÕ­åSZuðôà53/^¬ñÕÚ-`}GOÖýìÓ–Ø—h½2“ep¼æˆÕpiãnÜà,^\#ÓÎKñäd6Å”Óé´–4¬ˆšv€QõÛXúõϳÛ|òI ×Àä<_ÝÓÃöël„ôZ +ªq¢0L€hgvÑ^øôiºýfO+¼äö²ö þ¼ ÛÑf¸®|ºïíáñ~q3»¸%àa>>>Чó…/CôAv¹Ûaû7½âÍáø¹ªÑÆ(µªU; PÊÏ`«}rzCóf³›Å­ÁqËþçHbDµ'Óz­v봌ƺ…bI,¦ÏA`·*ã°# 4¤pQ íå ­œ½å¸_à«1ä6›ømûÃÏ?æTa•ïDP§Z¿­ùÓwxÒtÊÝ­Û0ΕÏ- TJÏÍ zŒ‚¬eMƇnî9wÈ*HÊl”ޤR—æ‘•é›\éÖ|N c=Ú’&™ÝÿŠÕÅX{l(²˜c¸ažI tê0@© p#ºEKr£·ˆU|—Z¹Áܘê0´Dk…•Ó­’ÈÍp/ºVq>ï÷Îͼî퇦õÛ¶_GX­_–œz~æ$´š¼À Ô)Í/³YGrTÂþ2ƒá®9´µøùcnúm‹›ù Û-ñ‚¤·2f×0S2ÛX&F Ü eù¢Òþ›Ù‰r,3Ž!ýØ:®”TCä¿„Ä>Õ  U<­¦AúvÅYõÒ«­84 —Í2G– 2Ÿ)«vUÌ^H¬„&*ípÎÆÊÅd/«DYP@°[¢…Œ&^cÈ@F!"Ùcë`Î4 0k\0Š˜´Xý›x²d§¬¬’’CMÌ(%xßQ#‹ ¨¡ÄÅxŠXM:¥àL/¨~„Kµn$S:bkÅ& ³ì€“U¶£YMpÈÉ ¡²[ûhŃ%ŠÐd)ø]È8Of-ýiþŠRYçU7<™8Ü0¢GHjŒvå>€ìù—ÿëÿþ/Ü}tæ7ø½b2›\sÖ·˜ÏP‹ùÄý2]ÉŽ“Éáð:¯F±ñé.ó>–l¼Ÿp<­×þh£·w;¼¡Ã~sÊo)¹ï¸¸ ^Í£þÅ‚ê.YÉt:pè†G°YëÊÈé´ßSêͯ(å5Q\ š‰08³¡_M¯®ñÿ@qý=L[ã7-‘ò˜on»ßàªm[Ô·ÌÕ'·^Ôq]µ¡,+µax—ƒzÎnf—è5›Ð•|8–ú#›÷~·}Å•ÌK«:´—íítĹ½ñÔÕ]}Ýw@¦´Úúú¼þéç/ˆz^®ðê®"ªú=éôéñãû”!nÜÕ%­J‡»xûÐOëM§³ko¯ \{Ѷzc^\y}€"Ù·,\#"Q† [ÄÛÕ1÷ä2¤¾.ÞðêeýõëË矿|þý×/¿ÿúüÓËòËj·Â-ÝÑ'Ó9f8ýGþÛ‡§ÛßþÙò›în~÷»?¥^ek>ÃrŠW?ÿür8¼=]>Y'¼*¢é€c çÉT @oû.2»¿¹½ñ»›ÛüÑöÝyë—A:Á§¥×ð~ôôsÇí¢Y¦˜»¤ï%Øuü÷Yà¸õ?FÀÐK™|e™ÎGƒ<,˜BºU2²­(â—×lúô-§*_±Æîøùç—ÿwÿa»9þ»ÿëïps¿~þ²^­p/ñžïþô·¿þÕ¯?ýúWO¿þõ§û‡ÅÓÃÍì†îÑucxáxâA§GT¯+y†´åŒŒct&Š@°IŽÉJ.ÿáádª2‹TÝÏ|8CljÔAŽ$RÜJ€VKÅf™×;uÀ<;C­Øì(¤I©¬L:ÿΔAŒ",tÖË1Ó™<ñ †·æÐjÕÁV /䤸–A&Ôõôbzd%ZsâuÈ%|O·V_Ÿ_¾>?þúüó×ç/_—/+NÃöÛ2¨ý4&b]QŽAb‰zö‘¯S* ]1Ž™\™®f d_ ½}üáñîáöéWŸîŸ8뺽y¸e…™²ÜæN‹‘&¢ žñÇJÕª¶Ÿ[oæYõ§Àò·* ´¼‚$ÇDõ'ih‚\Ô3À€ÎwÎ ²3Ñ,-#•jüt self._max_recursion: return if v > 0: density = 1.0 else: density = 0.0 if len(cont) > 8: body = self.create_body(cont, h, v, density) if ret is not None: ret.append(body) if cont.v_next(): v += 1 self._objects_from_contours(recurs + 1, cont.v_next(), h, v, ret) v -= 1 if cont.h_next(): h += 1 self._objects_from_contours(recurs + 1, cont.h_next(), h, v, ret) h -= 1 def objects_from_contours(self, cont): ret = [] self._objects_from_contours(0, cont, 0, 0, ret) return ret def detect_outline(self, image, threshold=THRESHOLD): img_size = cv.GetSize(image) grayscale = cv.CreateImage(img_size, 8, 1) cv.CvtColor(image, grayscale, cv.CV_BGR2GRAY) cv.EqualizeHist(grayscale, grayscale) storage = cv.CreateMemStorage(0) cv.Threshold(grayscale, grayscale, threshold, 255, cv.CV_THRESH_BINARY) contours = cv.FindContours(grayscale, cv.CreateMemStorage(), cv.CV_RETR_TREE, cv.CV_CHAIN_APPROX_SIMPLE) if len(contours) > 0: return cv.ApproxPoly(contours, storage, cv.CV_POLY_APPROX_DP, 1.5, 1) return contours def bodies_from_image(self, image, flip=True): if flip: flipped = cv.CreateImage( (image.width, image.height), image.depth, image.channels) cv.Flip(image, flipped, flipMode=0) image = flipped contours = self.detect_outline(image) return self.objects_from_contours(contours) camera = None def get_image(): # Grab an image from the camera global camera try: # raise # <-- uncomment to force using the journal image camera = cv.CaptureFromCAM(-1) # need to hold onto this instance image = cv.QueryFrame(camera) if image is None: raise Exception('Invalid image captured?') except Exception as ex: print('Unable to grab an image from the camera. (%s)' % ex) print('Using the journal image instead.') image = cv.LoadImage('journal_image.png') return image def main(): # Create the world world = b2.b2World(gravity=(0, -10), doSleep=True) # Get the OpenCV/Box2D object image = get_image() # Bring that image into Box2D cvo = CVObject(world, image) # ... and the rest is standard pygame visualization screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), 0, 32) pygame.display.set_caption('pybox2d/OpenCV example') clock = pygame.time.Clock() # And a static body to hold the ground shape world.CreateStaticBody( position=(0, 0), shapes=b2.b2PolygonShape(box=(50, 1)), ) colors = { b2.b2_staticBody: (255, 255, 255, 255), b2.b2_dynamicBody: (127, 127, 127, 255), } def fix_vertices(vertices): return [(int(SCREEN_OFFSETX + v[0]), int(SCREEN_OFFSETY - v[1])) for v in vertices] def _draw_polygon(polygon, screen, body, fixture): transform = body.transform vertices = fix_vertices( [transform * v * PPM for v in polygon.vertices]) pygame.draw.polygon(screen, [c / 2.0 for c in colors[body.type]], vertices, 0) pygame.draw.polygon(screen, colors[body.type], vertices, 1) b2.b2PolygonShape.draw = _draw_polygon def _draw_circle(circle, screen, body, fixture): position = fix_vertices([body.transform * circle.pos * PPM])[0] pygame.draw.circle(screen, colors[body.type], position, int(circle.radius * PPM)) b2.b2CircleShape.draw = _draw_circle def _draw_edge(edge, screen, body, fixture): vertices = fix_vertices([body.transform * edge.vertex1 * PPM, body.transform * edge.vertex2 * PPM]) pygame.draw.line(screen, colors[body.type], vertices[0], vertices[1]) b2.b2EdgeShape.draw = _draw_edge display_image = True if display_image: # opencv image -> pygame image image_rgb = cv.CreateMat(image.height, image.width, cv.CV_8UC3) cv.CvtColor(image, image_rgb, cv.CV_BGR2RGB) pg_img = pygame.image.frombuffer( image_rgb.tostring(), cv.GetSize(image_rgb), "RGB") pg_img.set_alpha(100) running = True while running: # Check the event queue for event in pygame.event.get(): if (event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE)): # The user closed the window or pressed escape running = False screen.fill((0, 0, 0, 0)) if display_image: screen.blit(pg_img, (0, 0)) # Draw the world for body in world.bodies: for fixture in body.fixtures: fixture.shape.draw(screen, body, fixture) # Make Box2D simulate the physics of our world for one step. world.Step(TIME_STEP, 10, 10) # Flip the screen and try to keep at the target FPS pygame.display.flip() clock.tick(TARGET_FPS) pygame.quit() print('Done!') if __name__ == '__main__': import pygame from pygame.locals import (QUIT, KEYDOWN, K_ESCAPE) main() pybox2d-2.3.2/examples/opencv/triangulate_seidel.py000066400000000000000000000514651276457661000224640ustar00rootroot00000000000000# # Poly2Tri # Copyright (c) 2009, Mason Green # http://code.google.com/p/poly2tri/ # # 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, # self list of conditions and the following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, # self list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # Neither the name of Poly2Tri nor the names of its contributors may be # used to endorse or promote products derived from self 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 COPYRIGHT OWNER 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. # from random import shuffle from math import atan2, sqrt # # Based on Raimund Seidel'e paper "A simple and fast incremental randomized # algorithm for computing trapezoidal decompositions and for triangulating # polygons" (Ported from poly2tri) # # Shear transform. May effect numerical robustness SHEAR = 1e-3 class Point(object): def __init__(self, x, y): self.x = x self.y = y self.next, self.prev = None, None def __sub__(self, other): if isinstance(other, Point): return Point(self.x - other.x, self.y - other.y) else: return Point(self.x - other, self.y - other) def __add__(self, other): if isinstance(other, Point): return Point(self.x + other.x, self.y + other.y) else: return Point(self.x + other, self.y + other) def __mul__(self, f): return Point(self.x * f, self.y * f) def __div__(self, a): return Point(self.x / a, self.y / a) def cross(self, p): return self.x * p.y - self.y * p.x def dot(self, p): return self.x * p.x + self.y * p.y def length(self): return sqrt(self.x * self.x + self.y * self.y) def normalize(self): return self / self.length() def less(self, p): return self.x < p.x def neq(self, other): return other.x != self.x or other.y != self.y def clone(self): return Point(self.x, self.y) def orient2d(pa, pb, pc): acx = pa.x - pc.x bcx = pb.x - pc.x acy = pa.y - pc.y bcy = pb.y - pc.y return acx * bcy - acy * bcx class Edge(object): def __init__(self, p, q): self.p = p self.q = q self.slope = (q.y - p.y) / (q.x - p.x) if q.x - p.x != 0 else 0 self.b = p.y - (p.x * self.slope) self.above, self.below = None, None self.mpoints = [p, q] def is_above(self, point): return orient2d(self.p, self.q, point) < 0 def is_below(self, point): return orient2d(self.p, self.q, point) > 0 def add_mpoint(self, point): for mp in self.mpoints: if not mp.neq(point): return self.mpoints.append(point) class Trapezoid(object): def __init__(self, left_point, right_point, top, bottom): self.left_point = left_point self.right_point = right_point self.top = top self.bottom = bottom self.upper_left = None self.upper_right = None self.lower_left = None self.lower_right = None self.inside = True self.sink = None self.key = hash(self) def update_left(self, ul, ll): self.upper_left = ul if ul is not None: ul.upper_right = self self.lower_left = ll if ll is not None: ll.lower_right = self def update_right(self, ur, lr): self.upper_right = ur if ur is not None: ur.upper_left = self self.lower_right = lr if lr is not None: lr.lower_left = self def update_left_right(self, ul, ll, ur, lr): self.upper_left = ul if ul is not None: ul.upper_right = self self.lower_left = ll if ll is not None: ll.lower_right = self self.upper_right = ur if ur is not None: ur.upper_left = self self.lower_right = lr if lr is not None: lr.lower_left = self def trim_neighbors(self): if self.inside: self.inside = False if self.upper_left is not None: self.upper_left.trim_neighbors() if self.lower_left is not None: self.lower_left.trim_neighbors() if self.upper_right is not None: self.upper_right.trim_neighbors() if self.lower_right is not None: self.lower_right.trim_neighbors() def contains(self, point): return (point.x > self.left_point.x and point.x < self.right_point.x and self.top.is_above(point) and self.bottom.is_below(point)) def vertices(self): v1 = line_intersect(self.top, self.left_point.x) v2 = line_intersect(self.bottom, self.left_point.x) v3 = line_intersect(self.bottom, self.right_point.x) v4 = line_intersect(self.top, self.right_point.x) return v1, v2, v3, v4 def add_points(self): if self.left_point is not self.bottom.p: self.bottom.add_mpoint(self.left_point) if self.right_point is not self.bottom.q: self.bottom.add_mpoint(self.right_point) if self.left_point is not self.top.p: self.top.add_mpoint(self.left_point) if self.right_point is not self.top.q: self.top.add_mpoint(self.right_point) def area(self): p = list(self.vertices()) return 0.5 * abs(sum(x0 * y1 - x1 * y0 for ((x0, y0), (x1, y1)) in self.segments(p))) def segments(self, p): return zip(p, p[1:] + [p[0]]) def line_intersect(edge, x): y = edge.slope * x + edge.b return x, y class Triangulator(object): ## # Number of points should be > 3 ## def __init__(self, poly_line): self.polygons = [] self.trapezoids = [] self.xmono_poly = [] self.edge_list = self.init_edges(poly_line) self.trapezoidal_map = TrapezoidalMap() self.bounding_box = self.trapezoidal_map.bounding_box(self.edge_list) self.query_graph = QueryGraph(isink(self.bounding_box)) self.process() def triangles(self): triangles = [] for p in self.polygons: verts = [] for v in p: verts.append((v.x, v.y)) triangles.append(verts) return triangles def trapezoid_map(self): return self.trapezoidal_map.map # Build the trapezoidal map and query graph def process(self): for edge in self.edge_list: traps = self.query_graph.follow_edge(edge) for t in traps: # Remove old trapezods del self.trapezoidal_map.map[t.key] # Bisect old trapezoids and create new cp = t.contains(edge.p) cq = t.contains(edge.q) if cp and cq: tlist = self.trapezoidal_map.case1(t, edge) self.query_graph.case1(t.sink, edge, tlist) elif cp and not cq: tlist = self.trapezoidal_map.case2(t, edge) self.query_graph.case2(t.sink, edge, tlist) elif not cp and not cq: tlist = self.trapezoidal_map.case3(t, edge) self.query_graph.case3(t.sink, edge, tlist) else: tlist = self.trapezoidal_map.case4(t, edge) self.query_graph.case4(t.sink, edge, tlist) # Add new trapezoids to map for t in tlist: self.trapezoidal_map.map[t.key] = t self.trapezoidal_map.clear() # Mark outside trapezoids w/ depth-first search for k, t in self.trapezoidal_map.map.items(): self.mark_outside(t) # Collect interior trapezoids for k, t in self.trapezoidal_map.map.items(): if t.inside: self.trapezoids.append(t) t.add_points() # Generate the triangles self.create_mountains() def mono_polies(self): polies = [] for x in self.xmono_poly: polies.append(x.monoPoly) return polies def create_mountains(self): for edge in self.edge_list: if len(edge.mpoints) > 2: mountain = MonotoneMountain() points = merge_sort(edge.mpoints) for p in points: mountain.add(p) mountain.process() for t in mountain.triangles: self.polygons.append(t) self.xmono_poly.append(mountain) def mark_outside(self, t): if t.top is self.bounding_box.top or t.bottom is self.bounding_box.bottom: t.trim_neighbors() def init_edges(self, points): edge_list = [] size = len(points) for i in range(size): j = i + 1 if i < size - 1 else 0 p = points[i][0], points[i][1] q = points[j][0], points[j][1] edge_list.append((p, q)) return self.order_edges(edge_list) def order_edges(self, edge_list): edges = [] for e in edge_list: p = shear_transform(e[0]) q = shear_transform(e[1]) if p.x > q.x: edges.append(Edge(q, p)) else: edges.append(Edge(p, q)) # Randomized incremental algorithm shuffle(edges) return edges def shear_transform(point): return Point(point[0] + SHEAR * point[1], point[1]) def merge_sort(l): if len(l) > 1: lleft = merge_sort(l[:len(l) / 2]) lright = merge_sort(l[len(l) / 2:]) p1, p2, p = 0, 0, 0 while p1 < len(lleft) and p2 < len(lright): if lleft[p1].x < lright[p2].x: l[p] = lleft[p1] p += 1 p1 += 1 else: l[p] = lright[p2] p += 1 p2 += 1 if p1 < len(lleft): l[p:] = lleft[p1:] elif p2 < len(lright): l[p:] = lright[p2:] else: print("internal error") return l class TrapezoidalMap(object): def __init__(self): self.map = {} self.margin = 50.0 self.bcross = None self.tcross = None def clear(self): self.bcross = None self.tcross = None def case1(self, t, e): trapezoids = [] trapezoids.append(Trapezoid(t.left_point, e.p, t.top, t.bottom)) trapezoids.append(Trapezoid(e.p, e.q, t.top, e)) trapezoids.append(Trapezoid(e.p, e.q, e, t.bottom)) trapezoids.append(Trapezoid(e.q, t.right_point, t.top, t.bottom)) trapezoids[0].update_left(t.upper_left, t.lower_left) trapezoids[1].update_left_right( trapezoids[0], None, trapezoids[3], None) trapezoids[2].update_left_right( None, trapezoids[0], None, trapezoids[3]) trapezoids[3].update_right(t.upper_right, t.lower_right) return trapezoids def case2(self, t, e): rp = e.q if e.q.x == t.right_point.x else t.right_point trapezoids = [] trapezoids.append(Trapezoid(t.left_point, e.p, t.top, t.bottom)) trapezoids.append(Trapezoid(e.p, rp, t.top, e)) trapezoids.append(Trapezoid(e.p, rp, e, t.bottom)) trapezoids[0].update_left(t.upper_left, t.lower_left) trapezoids[1].update_left_right( trapezoids[0], None, t.upper_right, None) trapezoids[2].update_left_right( None, trapezoids[0], None, t.lower_right) self.bcross = t.bottom self.tcross = t.top e.above = trapezoids[1] e.below = trapezoids[2] return trapezoids def case3(self, t, e): lp = e.p if e.p.x == t.left_point.x else t.left_point rp = e.q if e.q.x == t.right_point.x else t.right_point trapezoids = [] if self.tcross is t.top: trapezoids.append(t.upper_left) trapezoids[0].update_right(t.upper_right, None) trapezoids[0].right_point = rp else: trapezoids.append(Trapezoid(lp, rp, t.top, e)) trapezoids[0].update_left_right( t.upper_left, e.above, t.upper_right, None) if self.bcross is t.bottom: trapezoids.append(t.lower_left) trapezoids[1].update_right(None, t.lower_right) trapezoids[1].right_point = rp else: trapezoids.append(Trapezoid(lp, rp, e, t.bottom)) trapezoids[1].update_left_right( e.below, t.lower_left, None, t.lower_right) self.bcross = t.bottom self.tcross = t.top e.above = trapezoids[0] e.below = trapezoids[1] return trapezoids def case4(self, t, e): lp = e.p if e.p.x == t.left_point.x else t.left_point trapezoids = [] if self.tcross is t.top: trapezoids.append(t.upper_left) trapezoids[0].right_point = e.q else: trapezoids.append(Trapezoid(lp, e.q, t.top, e)) trapezoids[0].update_left(t.upper_left, e.above) if self.bcross is t.bottom: trapezoids.append(t.lower_left) trapezoids[1].right_point = e.q else: trapezoids.append(Trapezoid(lp, e.q, e, t.bottom)) trapezoids[1].update_left(e.below, t.lower_left) trapezoids.append(Trapezoid(e.q, t.right_point, t.top, t.bottom)) trapezoids[2].update_left_right(trapezoids[0], trapezoids[ 1], t.upper_right, t.lower_right) return trapezoids def bounding_box(self, edges): margin = self.margin max = edges[0].p + margin min = edges[0].q - margin for e in edges: if e.p.x > max.x: max = Point(e.p.x + margin, max.y) if e.p.y > max.y: max = Point(max.x, e.p.y + margin) if e.q.x > max.x: max = Point(e.q.x + margin, max.y) if e.q.y > max.y: max = Point(max.x, e.q.y + margin) if e.p.x < min.x: min = Point(e.p.x - margin, min.y) if e.p.y < min.y: min = Point(min.x, e.p.y - margin) if e.q.x < min.x: min = Point(e.q.x - margin, min.y) if e.q.y < min.y: min = Point(min.x, e.q.y - margin) top = Edge(Point(min.x, max.y), Point(max.x, max.y)) bottom = Edge(Point(min.x, min.y), Point(max.x, min.y)) left = top.p right = top.q trap = Trapezoid(left, right, top, bottom) self.map[trap.key] = trap return trap class Node(object): def __init__(self, lchild, rchild): self.parent_list = [] self.lchild = lchild self.rchild = rchild if lchild is not None: lchild.parent_list.append(self) if rchild is not None: rchild.parent_list.append(self) def replace(self, node): for parent in node.parent_list: if parent.lchild is node: parent.lchild = self else: parent.rchild = self self.parent_list += node.parent_list class Sink(Node): def __init__(self, trapezoid): super(Sink, self).__init__(None, None) self.trapezoid = trapezoid trapezoid.sink = self def locate(self, edge): return self def isink(trapezoid): if trapezoid.sink is None: return Sink(trapezoid) return trapezoid.sink class XNode(Node): def __init__(self, point, lchild, rchild): super(XNode, self).__init__(lchild, rchild) self.point = point def locate(self, edge): if edge.p.x >= self.point.x: return self.rchild.locate(edge) return self.lchild.locate(edge) class YNode(Node): def __init__(self, edge, lchild, rchild): super(YNode, self).__init__(lchild, rchild) self.edge = edge def locate(self, edge): if self.edge.is_above(edge.p): return self.rchild.locate(edge) if self.edge.is_below(edge.p): return self.lchild.locate(edge) if edge.slope < self.edge.slope: return self.rchild.locate(edge) return self.lchild.locate(edge) class QueryGraph: def __init__(self, head): self.head = head def locate(self, edge): return self.head.locate(edge).trapezoid def follow_edge(self, edge): trapezoids = [self.locate(edge)] while(edge.q.x > trapezoids[-1].right_point.x): if edge.is_above(trapezoids[-1].right_point): trapezoids.append(trapezoids[-1].upper_right) else: trapezoids.append(trapezoids[-1].lower_right) return trapezoids def replace(self, sink, node): if sink.parent_list: node.replace(sink) else: self.head = node def case1(self, sink, edge, tlist): yNode = YNode(edge, isink(tlist[1]), isink(tlist[2])) qNode = XNode(edge.q, yNode, isink(tlist[3])) pNode = XNode(edge.p, isink(tlist[0]), qNode) self.replace(sink, pNode) def case2(self, sink, edge, tlist): yNode = YNode(edge, isink(tlist[1]), isink(tlist[2])) pNode = XNode(edge.p, isink(tlist[0]), yNode) self.replace(sink, pNode) def case3(self, sink, edge, tlist): yNode = YNode(edge, isink(tlist[0]), isink(tlist[1])) self.replace(sink, yNode) def case4(self, sink, edge, tlist): yNode = YNode(edge, isink(tlist[0]), isink(tlist[1])) qNode = XNode(edge.q, yNode, isink(tlist[2])) self.replace(sink, qNode) PI_SLOP = 3.1 class MonotoneMountain: def __init__(self): self.size = 0 self.tail = None self.head = None self.positive = False self.convex_points = set() self.mono_poly = [] self.triangles = [] self.convex_polies = [] def add(self, point): if self.size is 0: self.head = point self.size = 1 elif self.size is 1: self.tail = point self.tail.prev = self.head self.head.next = self.tail self.size = 2 else: self.tail.next = point point.prev = self.tail self.tail = point self.size += 1 def remove(self, point): next = point.next prev = point.prev point.prev.next = next point.next.prev = prev self.size -= 1 def process(self): self.positive = self.angle_sign() self.gen_mono_poly() p = self.head.next while p.neq(self.tail): a = self.angle(p) if a >= PI_SLOP or a <= -PI_SLOP or a == 0: self.remove(p) elif self.is_convex(p): self.convex_points.add(p) p = p.next self.triangulate() def triangulate(self): while self.convex_points: ear = self.convex_points.pop() a = ear.prev b = ear c = ear.next triangle = (a, b, c) self.triangles.append(triangle) self.remove(ear) if self.valid(a): self.convex_points.add(a) if self.valid(c): self.convex_points.add(c) # assert self.size <= 3, "Triangulation bug, please report" def valid(self, p): return p.neq(self.head) and p.neq(self.tail) and self.is_convex(p) def gen_mono_poly(self): p = self.head while(p is not None): self.mono_poly.append(p) p = p.next def angle(self, p): a = p.next - p b = p.prev - p return atan2(a.cross(b), a.dot(b)) def angle_sign(self): a = self.head.next - self.head b = self.tail - self.head return atan2(a.cross(b), a.dot(b)) >= 0 def is_convex(self, p): if self.positive != (self.angle(p) >= 0): return False return True pybox2d-2.3.2/examples/pgu/000077500000000000000000000000001276457661000155345ustar00rootroot00000000000000pybox2d-2.3.2/examples/pgu/__init__.py000066400000000000000000000001471276457661000176470ustar00rootroot00000000000000"""Phil's pyGame Utilities """ __version__ = '0.14' # vim: set filetype=python sts=4 sw=4 noet si : pybox2d-2.3.2/examples/pgu/gui/000077500000000000000000000000001276457661000163205ustar00rootroot00000000000000pybox2d-2.3.2/examples/pgu/gui/__init__.py000066400000000000000000000023121276457661000204270ustar00rootroot00000000000000"""Modules for creating a widget-based user interface. See the examples folder for sample scripts that use this module.""" import pygame # The basestring class was removed in Python 3, but we want to keep it to maintain # compatibility with previous versions of python. try: __builtins__["basestring"] except KeyError: __builtins__["basestring"] = str from .theme import Theme from .style import Style from .widget import Widget from .surface import subsurface, ProxySurface from .const import * from .container import Container from .app import App, Desktop from .table import Table from .document import Document #html from .area import SlideBox, ScrollArea, List from .form import Form from .group import Group from .basic import Spacer, Color, Label, Image, parse_color from .button import Icon, Button, Switch, Checkbox, Radio, Tool, Link from .input import Input, Password from .keysym import Keysym from .slider import VSlider, HSlider, VScrollBar, HScrollBar from .select import Select from .misc import ProgressBar from .menus import Menus from .dialog import Dialog, FileDialog from .textarea import TextArea from .deprecated import Toolbox, action_open, action_setvalue, action_quit, action_exec pybox2d-2.3.2/examples/pgu/gui/app.py000066400000000000000000000221641276457661000174570ustar00rootroot00000000000000"""Defines the top-level application widget""" import pygame from pygame.locals import * from . import pguglobals from . import container from .const import * class App(container.Container): """The top-level widget for an application. Example: import pygame from pgu import gui widget = gui.Button("Testing") app = gui.App() app.init(widget=widget) app.run() """ # The top-level widget in the application widget = None # The pygame display for rendering the GUI. Note this may be a subsurface # of the full surface. screen = None # The region of the (full) pygame display that contains the GUI. If set, # this is used when transforming the mouse position from screen # coordinates into the subsurface coordinates. appArea = None def __init__(self, theme=None, **params): """Create a new application given the (optional) theme instance.""" self.set_global_app() if theme == None: from .theme import Theme theme = Theme() self.theme = theme params['decorate'] = 'app' container.Container.__init__(self,**params) self._quit = False self.widget = None self._chsize = False self._repaint = False self.screen = None self.container = None def set_global_app(self): """Registers this app as _the_ global PGU application. You generally shouldn't need to call this function.""" # Keep a global reference to this application instance so that PGU # components can easily find it. pguglobals.app = self # For backwards compatibility we keep a reference in the class # itself too. App.app = self def resize(self): if self.screen: # The user has explicitly specified a screen surface size = self.screen.get_size() elif pygame.display.get_surface(): # Use the existing pygame display self.screen = pygame.display.get_surface() size = self.screen.get_size() else: # Otherwise we must allocate a new pygame display if self.style.width != 0 and self.style.height != 0: # Create a new screen based on the desired app size size = (self.style.width, self.style.height) else: # Use the size of the top-most widget size = self.widget.rect.size = self.widget.resize() # Create the display self.screen = pygame.display.set_mode(size, SWSURFACE) #use screen to set up size of this widget self.style.width,self.style.height = size self.rect.size = size self.rect.topleft = (0, 0) self.widget.rect.topleft = (0, 0) self.widget.rect.size = self.widget.resize(*size) for w in self.windows: w.rect.size = w.resize() self._chsize = False def init(self, widget=None, screen=None, area=None): """Initialize the application. Keyword arguments: widget -- the top-level widget in the application screen -- the pygame surface to render to area -- the rectangle (within 'screen') to use for rendering """ self.set_global_app() if (widget): # Set the top-level widget self.widget = widget if (screen): if (area): # Take a subsurface of the given screen self.appArea = area self.screen = screen.subsurface(area) else: # Use the entire screen for the app self.screen = screen self.resize() w = self.widget self.widgets = [] self.widgets.append(w) w.container = self self.focus(w) pygame.key.set_repeat(500,30) self._repaint = True self._quit = False self.send(INIT) def event(self,ev): """Pass an event to the main widget. If you are managing your own mainloop, this function should be called periodically when you are processing pygame events. """ self.set_global_app() if (self.appArea and hasattr(ev, "pos")): # Translate into subsurface coordinates pos = (ev.pos[0]-self.appArea.x, ev.pos[1]-self.appArea.y) args = {"pos" : pos} # Copy over other misc mouse parameters for name in ("buttons", "rel", "button"): if (hasattr(ev, name)): args[name] = getattr(ev, name) ev = pygame.event.Event(ev.type, args) #NOTE: might want to deal with ACTIVEEVENT in the future. self.send(ev.type, ev) container.Container.event(self, ev) if ev.type == MOUSEBUTTONUP: if ev.button not in (4,5): # Ignores the mouse wheel # Also issue a "CLICK" event sub = pygame.event.Event(CLICK,{ 'button' : ev.button, 'pos' : ev.pos}) self.send(sub.type,sub) container.Container.event(self,sub) def loop(self): """Performs one iteration of the PGU application loop, which processes events and update the pygame display.""" self.set_global_app() for e in pygame.event.get(): if not (e.type == QUIT and self.mywindow): self.event(e) rects = self.update(self.screen) pygame.display.update(rects) def paint(self,screen=None): """Renders the application onto the given pygame surface""" if (screen): self.screen = screen if self._chsize: self._chsize = False self.resize() if self.background: self.background.paint(self.screen) container.Container.paint(self, self.screen) def update(self,screen=None): """Update the screen in a semi-efficient manner, and returns a list of pygame rects to be updated.""" if (screen): self.screen = screen if self._chsize: self.resize() self._chsize = False return None if self._repaint: self.paint(self.screen) self._repaint = False rects = [pygame.Rect(0, 0, self.screen.get_width(), self.screen.get_height())] else: rects = container.Container.update(self,self.screen) if (self.appArea): # Translate the rects from subsurface coordinates into # full display coordinates. for r in rects: r.move_ip(self.appArea.topleft) return rects def run(self, widget=None, screen=None, delay=10): """Run an application. Automatically calls App.init and then forever loops while calling App.event and App.update Keyword arguments: widget -- the top-level widget to use screen -- the pygame surface to render to delay -- the delay between updates (in milliseconds) """ self.init(widget,screen) while not self._quit: self.loop() pygame.time.wait(delay) def reupdate(self,w=None): pass def repaint(self,w=None): self._repaint = True def repaintall(self): self._repaint = True def chsize(self): if (not self._chsize): self._chsize = True self._repaint = True def quit(self,value=None): self._quit = True def open(self, w, pos=None): """Opens the given PGU window and positions it on the screen""" w.container = self if (w.rect.w == 0 or w.rect.h == 0): w.rect.size = w.resize() if (not pos): # Auto-center the window w.rect.center = self.rect.center else: # Show the window in a particular location w.rect.topleft = pos self.windows.append(w) self.mywindow = w self.focus(w) self.repaint(w) w.send(OPEN) def close(self, w): """Closes the previously opened PGU window""" if self.myfocus is w: self.blur(w) if w not in self.windows: return #no need to remove it twice! happens. self.windows.remove(w) self.mywindow = None if self.windows: self.mywindow = self.windows[-1] self.focus(self.mywindow) if not self.mywindow: self.myfocus = self.widget #HACK: should be done fancier, i think.. if not self.myhover: self.enter(self.widget) self.repaintall() w.send(CLOSE) class Desktop(App): """Create an App using the desktop theme class.""" def __init__(self,**params): params.setdefault('cls','desktop') App.__init__(self,**params) pybox2d-2.3.2/examples/pgu/gui/area.py000066400000000000000000000364221276457661000176110ustar00rootroot00000000000000""" """ import os from . import pguglobals from .const import * from . import surface from . import container, table from . import group from . import basic, button, slider class SlideBox(container.Container): """A scrollable area with no scrollbars. Example: c = SlideBox(w,100,100) c.offset = (10,10) c.repaint() """ _widget = None def __init__(self, widget, width, height, **params): """SlideBox constructor. Arguments: widget -- widget to be able to scroll around width, height -- size of scrollable area """ params.setdefault('width', width) params.setdefault('height', height) container.Container.__init__(self, **params) self.offset = [0, 0] self.widget = widget @property def widget(self): return self._widget @widget.setter def widget(self, val): # Remove the old widget first if self._widget: self.remove(self._widget) # Now add in the new widget self._widget = val self.add(val, 0, 0) def paint(self, s): #if not hasattr(self,'surface'): self.surface = pygame.Surface((self.max_rect.w,self.max_rect.h),0,s) #self.surface.fill((0,0,0,0)) pguglobals.app.theme.render(self.surface,self.style.background,pygame.Rect(0,0,self.max_rect.w,self.max_rect.h)) self.bkgr = pygame.Surface((s.get_width(),s.get_height()),0,s) self.bkgr.blit(s,(0,0)) container.Container.paint(self,self.surface) s.blit(self.surface,(-self.offset[0],-self.offset[1])) self._offset = self.offset[:] return def paint_for_when_pygame_supports_other_tricks(self,s): #this would be ideal if pygame had support for it! #and if pgu also had a paint(self,s,rect) method to paint small parts sr = (self.offset[0],self.offset[1],self.max_rect.w,self.max_rect.h) cr = (-self.offset[0],-self.offset[1],s.get_width(),s.get_height()) s2 = s.subsurface(sr) s2.set_clip(cr) container.Container.paint(self,s2) def proxy_paint(self, s): container.Container.paint(self, surface.ProxySurface(parent=None, rect=self.max_rect, real_surface=s, offset=self.offset)) def update(self, s): rects = container.Container.update(self,self.surface) rets = [] s_rect = pygame.Rect(0,0,s.get_width(),s.get_height()) if self.offset == self._offset: for r in rects: r2 = r.move((-self.offset[0],-self.offset[1])) if r2.colliderect(s_rect): s.blit(self.surface.subsurface(r),r2) rets.append(r2) else: s.blit(self.bkgr,(0,0)) sub = pygame.Rect(self.offset[0],self.offset[1],min(s.get_width(),self.max_rect.w-self.offset[0]),min(s.get_height(),self.max_rect.h-self.offset[1])) # print sub # print self.surface.get_width(),self.surface.get_height() # print s.get_width(),s.get_height() # print self.offset # print self.style.width,self.style.height s.blit(self.surface.subsurface(sub),(0,0)) rets.append(s_rect) self._offset = self.offset[:] return rets def proxy_update(self, s): rects = container.Container.update(self, surface.ProxySurface(parent=None, rect=self.max_rect, real_surface=s, offset=self.offset)) result = [] for r in rects: result.append(pygame.Rect(r).move(self.offset)) return result def resize(self, width=None, height=None): container.Container.resize(self) self.max_rect = pygame.Rect(self.widget.rect) #self.max_rect.w = max(self.max_rect.w,self.style.width) #self.max_rect.h = max(self.max_rect.h,self.style.height) return self.style.width,self.style.height #self.rect = pygame.Rect(self.rect[0], self.rect[1], self.style.width, self.style.height) def event(self, e): if e.type in [MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION]: pos = (e.pos[0] + self.offset[0], e.pos[1] + self.offset[1]) if self.max_rect.collidepoint(pos): e_params = {'pos': pos } if e.type == MOUSEMOTION: e_params['buttons'] = e.buttons e_params['rel'] = e.rel else: e_params['button'] = e.button e = pygame.event.Event(e.type, e_params) container.Container.event(self, e) #class SlideBox(Area): # def __init__(self,*args,**params): # print 'gui.SlideBox','Scheduled to be renamed to Area.' # Area.__init__(self,*args,**params) class ScrollArea(table.Table): """A scrollable area with scrollbars.""" _widget = None def __init__(self, widget, width=0, height=0, hscrollbar=True, vscrollbar=True,step=24, **params): """ScrollArea constructor. Arguments: widget -- widget to be able to scroll around width, height -- size of scrollable area. Set either to 0 to default to size of widget. hscrollbar -- set to False if you do not wish to have a horizontal scrollbar vscrollbar -- set to False if you do not wish to have a vertical scrollbar step -- set to how far clicks on the icons will step """ w= widget params.setdefault('cls', 'scrollarea') table.Table.__init__(self, width=width,height=height,**params) self.sbox = SlideBox(w, width=width, height=height, cls=self.cls+".content") self.widget = w self.vscrollbar = vscrollbar self.hscrollbar = hscrollbar self.step = step @property def widget(self): return self._widget @widget.setter def widget(self, val): self._widget = val self.sbox.widget = val def resize(self,width=None,height=None): widget = self.widget box = self.sbox #self.clear() table.Table.clear(self) #print 'resize',self,self._rows self.tr() self.td(box) widget.rect.w, widget.rect.h = widget.resize() my_width,my_height = self.style.width,self.style.height if not my_width: my_width = widget.rect.w self.hscrollbar = False if not my_height: my_height = widget.rect.h self.vscrollbar = False box.style.width,box.style.height = my_width,my_height #self.style.width,self.style.height box.rect.w,box.rect.h = box.resize() #print widget.rect #print box.rect #r = table.Table.resize(self,width,height) #print r #return r #print box.offset # #this old code automatically adds in a scrollbar if needed # #but it doesn't always work # self.vscrollbar = None # if widget.rect.h > box.rect.h: # self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step) # self.td(self.vscrollbar) # self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None) # # vs = self.vscrollbar # vs.rect.w,vs.rect.h = vs.resize() # box.style.width = self.style.width - vs.rect.w # # # self.hscrollbar = None # if widget.rect.w > box.rect.w: # self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step) # self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None) # self.tr() # self.td(self.hscrollbar) # # hs = self.hscrollbar # hs.rect.w,hs.rect.h = hs.resize() # box.style.height = self.style.height - hs.rect.h xt,xr,xb,xl = pguglobals.app.theme.getspacing(box) if self.vscrollbar: self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step) self.td(self.vscrollbar) self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None) vs = self.vscrollbar vs.rect.w,vs.rect.h = vs.resize() if self.style.width: box.style.width = self.style.width - (vs.rect.w + xl+xr) if self.hscrollbar: self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step) self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None) self.tr() self.td(self.hscrollbar) hs = self.hscrollbar hs.rect.w,hs.rect.h = hs.resize() if self.style.height: box.style.height = self.style.height - (hs.rect.h + xt + xb) if self.hscrollbar: hs = self.hscrollbar hs.min = 0 hs.max = widget.rect.w - box.style.width hs.style.width = box.style.width hs.size = hs.style.width * box.style.width / max(1,widget.rect.w) else: box.offset[0] = 0 if self.vscrollbar: vs = self.vscrollbar vs.min = 0 vs.max = widget.rect.h - box.style.height vs.style.height = box.style.height vs.size = vs.style.height * box.style.height / max(1,widget.rect.h) else: box.offset[1] = 0 #print self.style.width,box.style.width, hs.style.width r = table.Table.resize(self,width,height) return r def x_resize(self, width=None, height=None): w,h = table.Table.resize(self, width, height) if self.hscrollbar: if self.widget.rect.w <= self.sbox.rect.w: self.hscrollbar.size = self.hscrollbar.style.width else: self.hscrollbar.size = max(20,self.hscrollbar.style.width * self.sbox.rect.w / self.widget.rect.w) self._hscrollbar_changed(None) if self.widget.rect.h <= self.sbox.rect.h: self.vscrollbar.size = self.vscrollbar.style.height else: self.vscrollbar.size = max(20,self.vscrollbar.style.height * self.sbox.rect.h / self.widget.rect.h) self._vscrollbar_changed(None) return w,h def _vscrollbar_changed(self, xxx): #y = (self.widget.rect.h - self.sbox.rect.h) * self.vscrollbar.value / 1000 #if y >= 0: self.sbox.offset[1] = -y self.sbox.offset[1] = self.vscrollbar.value self.sbox.reupdate() def _hscrollbar_changed(self, xxx): #x = (self.widget.rect.w - self.sbox.rect.w) * self.hscrollbar.value / 1000 #if x >= 0: self.sbox.offset[0] = -x self.sbox.offset[0] = self.hscrollbar.value self.sbox.reupdate() def set_vertical_scroll(self, percents): #if not self.vscrollbar: return if not hasattr(self.vscrollbar,'value'): return self.vscrollbar.value = percents #min(max(percents*10, 0), 1000) self._vscrollbar_changed(None) def set_horizontal_scroll(self, percents): #if not self.hscrollbar: return if not hasattr(self.hscrollbar,'value'): return self.hscrollbar.value = percents #min(max(percents*10, 0), 1000) self._hscrollbar_changed(None) def event(self, e): #checking for event recipient if (table.Table.event(self, e)): return True #mouse wheel scrolling if self.vscrollbar: if not hasattr(self.vscrollbar,'value'): return False if e.type == pygame.locals.MOUSEBUTTONDOWN: if e.button == 4: #wheel up self.vscrollbar._click(-1) return True elif e.button == 5: #wheel down self.vscrollbar._click(1) return True return False class _List_Item(button._button): def __init__(self,label=None,image=None,value=None,**params): #TODO label= could conflict with the module label #param image: an imagez.Image object (optional) #param text: a string object params.setdefault('cls','list.item') button._button.__init__(self,**params) self.group = None self.value = value #(self, value) self.widget = None if type(label) == str: label = basic.Label(label, cls=self.cls+".label") if image and label: self.widget = container.Container() self.widget.add(image, 0, 0) #HACK: improper use of .resize() image.rect.w,image.rect.h = image.resize() self.widget.add(label, image.rect.w, 0) elif image: self.widget = image elif label: self.widget = label self.pcls = "" def resize(self,width=None,height=None): self.widget.rect.w,self.widget.rect.h = self.widget.resize() return self.widget.rect.w,self.widget.rect.h # self.widget._resize() # self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h def event(self,e): button._button.event(self,e) if self.group.value == self.value: self.pcls = "down" def paint(self,s): if self.group.value == self.value: self.pcls = "down" self.widget.paint(surface.subsurface(s,self.widget.rect)) def click(self): self.group.value = self.value for w in self.group.widgets: if w != self: w.pcls = "" class List(ScrollArea): """A list of items in an area. This widget can be a form element, it has a value set to whatever item is selected. """ def _change(self, value): self.value = self.group.value self.send(CHANGE) def __init__(self, width, height, **params): params.setdefault('cls', 'list') self.table = table.Table(width=width) ScrollArea.__init__(self, self.table, width, height,hscrollbar=False ,**params) self.items = [] g = group.Group() self.group = g g.connect(CHANGE,self._change,None) self.value = self.group.value = None self.add = self._add self.remove = self._remove def clear(self): """Clear the list.""" self.items = [] self.group = group.Group() self.group.connect(CHANGE,self._change,None) self.table.clear() self.set_vertical_scroll(0) self.blur(self.myfocus) def _add(self, label, image = None, value=None): item = _List_Item(label,image=image,value=value) self.table.tr() self.table.add(item) self.items.append(item) item.group = self.group item.group.add(item) def _remove(self, item): for i in self.items: if i.value == item: item = i if item not in self.items: return item.blur() self.items.remove(item) self.group.widgets.remove(item) self.table.remove_row(item.style.row) pybox2d-2.3.2/examples/pgu/gui/basic.py000066400000000000000000000103471276457661000177600ustar00rootroot00000000000000"""These widgets are all grouped together because they are non-interactive widgets. """ import pygame from .const import * from . import widget # Turns a descriptive string or a tuple into a pygame color def parse_color(desc): if (is_color(desc)): # Already a color return desc elif (desc and desc[0] == "#"): # Because of a bug in pygame 1.8.1 we need to explicitly define the # alpha value otherwise it will default to transparent. if (len(desc) == 7): desc += "FF" return pygame.Color(desc) # Determines if the given object is a pygame-compatible color or not def is_color(col): # In every version of pygame (up to 1.8.1 so far) will interpret # a tuple as a color. if (type(col) == tuple): return col if (hasattr(pygame, "Color") and type(pygame.Color) == type): # This is a recent version of pygame that uses a proper type # instance for colors. return (isinstance(col, pygame.Color)) # Otherwise, this version of pygame only supports tuple colors return False class Spacer(widget.Widget): """An invisible space widget.""" def __init__(self,width,height,**params): params.setdefault('focusable',False) widget.Widget.__init__(self,width=width,height=height,**params) class Color(widget.Widget): """A widget that renders as a solid block of color. Note the color can be changed by setting the 'value' field, and the widget will automatically be repainted, eg: c = Color() c.value = (255,0,0) c.value = (0,255,0) """ _value = None def __init__(self,value=None,**params): params.setdefault('focusable',False) if value != None: params['value']=value widget.Widget.__init__(self,**params) def paint(self,s): if hasattr(self,'value'): s.fill(self.value) @property def value(self): return self._value @value.setter def value(self, val): if (isinstance(val, basestring)): # Parse the string as a color val = parse_color(val) oldval = self._value self._value = val if (oldval != val): # Emit a change signal self.send(CHANGE) self.repaint() class Label(widget.Widget): """A text label widget.""" def __init__(self, value="", **params): params.setdefault('focusable', False) params.setdefault('cls', 'label') widget.Widget.__init__(self, **params) self.value = value self.font = self.style.font self.style.width, self.style.height = self.font.size(self.value) def paint(self,s): """Renders the label onto the given surface in the upper-left corner.""" s.blit(self.font.render(self.value, 1, self.style.color),(0,0)) def set_text(self, txt): """Set the text of this label.""" self.value = txt # Signal to the application that we need to resize this widget self.chsize() def set_font(self, font): """Set the font used to render this label.""" this.font = font # Signal to the application that we need a resize this.chsize() def resize(self,width=None,height=None): # Calculate the size of the rendered text (self.style.width, self.style.height) = self.font.size(self.value) return (self.style.width, self.style.height) class Image(widget.Widget): """An image widget. The constructor takes a file name or a pygame surface.""" def __init__(self,value,**params): params.setdefault('focusable',False) widget.Widget.__init__(self,**params) if type(value) == str: value = pygame.image.load(value) ow,oh = iw,ih = value.get_width(),value.get_height() sw,sh = self.style.width,self.style.height if sw and not sh: iw,ih = sw,ih*sw/iw elif sh and not sw: iw,ih = iw*sh/ih,sh elif sw and sh: iw,ih = sw,sh if (ow,oh) != (iw,ih): value = pygame.transform.scale(value,(iw,ih)) self.style.width,self.style.height = iw,ih self.value = value def paint(self,s): s.blit(self.value,(0,0)) pybox2d-2.3.2/examples/pgu/gui/button.py000066400000000000000000000233571276457661000202170ustar00rootroot00000000000000"""Contains various types of button widgets.""" from pygame.locals import * from .const import * from . import widget, surface from . import basic class _button(widget.Widget): # The underlying 'value' accessed by the getter and setters below _value = None def __init__(self,**params): widget.Widget.__init__(self,**params) self.state = 0 def event(self,e): if e.type == ENTER: self.repaint() elif e.type == EXIT: self.repaint() elif e.type == FOCUS: self.repaint() elif e.type == BLUR: self.repaint() elif e.type == KEYDOWN: if e.key == K_SPACE or e.key == K_RETURN: self.state = 1 self.repaint() elif e.type == MOUSEBUTTONDOWN: self.state = 1 self.repaint() elif e.type == KEYUP: if self.state == 1: sub = pygame.event.Event(CLICK,{'pos':(0,0),'button':1}) #self.send(sub.type,sub) self._event(sub) self.state = 0 self.repaint() elif e.type == MOUSEBUTTONUP: self.state = 0 self.repaint() elif e.type == CLICK: self.click() self.pcls = "" if self.state == 0 and self.is_hovering(): self.pcls = "hover" if self.state == 1 and self.is_hovering(): self.pcls = "down" def click(self): pass class Button(_button): """A button, buttons can be clicked, they are usually used to set up callbacks. Example: w = gui.Button("Click Me") w.connect(gui.CLICK, fnc, value) """ def __init__(self, value=None, **params): """Button constructor, which takes either a string label or widget. See Widget documentation for additional style parameters. """ params.setdefault('cls', 'button') _button.__init__(self, **params) self.value = value @property def value(self): return self._value @value.setter def value(self, val): if (isinstance(val, basestring)): # Allow the choice of font to propagate to the button label params = {} if (self.style.font): params["font"] = self.style.font val = basic.Label(val, cls=self.cls+".label", **params) val.container = self oldval = self._value self._value = val if (val != oldval): self.send(CHANGE) self.chsize() def resize(self,width=None,height=None): self.value.rect.x,self.value.rect.y = 0,0 self.value.rect.w,self.value.rect.h = self.value.resize(width,height) return self.value.rect.w,self.value.rect.h def paint(self,s): self.value.pcls = self.pcls self.value.paint(surface.subsurface(s,self.value.rect)) class Switch(_button): """A switch can have two states, on or off.""" def __init__(self,value=False,**params): params.setdefault('cls','switch') _button.__init__(self,**params) self.value = value img = self.style.off self.style.width = img.get_width() self.style.height = img.get_height() def paint(self,s): #self.pcls = "" #if self.container.myhover is self: self.pcls = "hover" if self.value: img = self.style.on else: img = self.style.off s.blit(img,(0,0)) @property def value(self): return self._value @value.setter def value(self, val): oldval = self._value self._value = val if oldval != val: self.send(CHANGE) self.repaint() def click(self): self.value = not self.value class Checkbox(_button): """A type of switch that can be grouped with other checkboxes. Example: # The 'value' parameter indicates which checkboxes are on by default g = gui.Group(name='colors',value=['r','b']) t = gui.Table() t.tr() t.td(gui.Label('Red')) t.td(gui.Checkbox(g,'r')) t.tr() t.td(gui.Label('Green')) t.td(gui.Checkbox(g,'g')) t.tr() t.td(gui.Label('Blue')) t.td(gui.Checkbox(g,'b')) """ def __init__(self,group,value=None,**params): """Checkbox constructor. Keyword arguments: group -- the Group that this checkbox belongs to value -- the initial value (True or False) See Widget documentation for additional style parameters. """ params.setdefault('cls','checkbox') _button.__init__(self,**params) self.group = group self.group.add(self) if self.group.value == None: self.group.value = [] self.value = value img = self.style.off self.style.width = img.get_width() self.style.height = img.get_height() def paint(self,s): #self.pcls = "" #if self.container.myhover is self: self.pcls = "hover" if self.value in self.group.value: img = self.style.on else: img = self.style.off s.blit(img,(0,0)) def click(self): if self.value in self.group.value: self.group.value.remove(self.value) else: self.group.value.append(self.value) self.group._change() class Radio(_button): """A type of switch that can be grouped with other radio buttons, except that only one radio button can be active at a time. Example: g = gui.Group(name='colors',value='g') t = gui.Table() t.tr() t.td(gui.Label('Red')) t.td(gui.Radio(g,'r')) t.tr() t.td(gui.Label('Green')) t.td(gui.Radio(g,'g')) t.tr() t.td(gui.Label('Blue')) t.td(gui.Radio(g,'b')) """ def __init__(self,group=None,value=None,**params): """Radio constructor. Keyword arguments: group -- the Group this radio button belongs to value -- the initial value (True or False) """ params.setdefault('cls','radio') _button.__init__(self,**params) self.group = group self.group.add(self) self.value = value img = self.style.off self.style.width = img.get_width() self.style.height = img.get_height() def paint(self,s): #self.pcls = "" #if self.container.myhover is self: self.pcls = "hover" if self.group.value == self.value: img = self.style.on else: img = self.style.off s.blit(img,(0,0)) def click(self): self.group.value = self.value class Tool(_button): """Within a Group of Tool widgets only one may be selected at a time. Example: g = gui.Group(name='colors',value='g') t = gui.Table() t.tr() t.td(gui.Tool(g,'Red','r')) t.tr() t.td(gui.Tool(g,'Green','g')) t.tr() t.td(gui.Tool(g,'Blue','b')) """ def __init__(self,group,widget=None,value=None,**params): #TODO widget= could conflict with module widget """Tool constructor. Keyword arguments: group -- a gui.Group for the Tool to belong to widget -- a widget to appear on the Tool (similar to a Button) value -- the value """ params.setdefault('cls','tool') _button.__init__(self,**params) self.group = group self.group.add(self) self.value = value if widget: self.setwidget(widget) if self.group.value == self.value: self.pcls = "down" def setwidget(self,w): self.widget = w def resize(self,width=None,height=None): self.widget.rect.w,self.widget.rect.h = self.widget.resize() #self.widget._resize() #self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h return self.widget.rect.w,self.widget.rect.h def event(self,e): _button.event(self,e) if self.group.value == self.value: self.pcls = "down" def paint(self,s): if self.group.value == self.value: self.pcls = "down" self.widget.paint(surface.subsurface(s,self.widget.rect)) def click(self): self.group.value = self.value for w in self.group.widgets: if w != self: w.pcls = "" class Icon(_button): """TODO - might be deprecated """ def __init__(self,cls,**params): params['cls'] = cls _button.__init__(self,**params) s = self.style.image self.style.width = s.get_width() self.style.height = s.get_height() self.state = 0 def paint(self,s): #self.pcls = "" #if self.state == 0 and hasattr(self.container,'myhover') and self.container.myhover is self: self.pcls = "hover" #if self.state == 1 and hasattr(self.container,'myhover') and self.container.myhover is self: self.pcls = "down" s.blit(self.style.image,(0,0)) class Link(_button): """A link, links can be clicked, they are usually used to set up callbacks. Basically the same as the button widget, just text only with a different cls. Made for convenience. Example: w = gui.Link("Click Me") w.connect(gui.CLICK,fnc,value) """ def __init__(self,value,**params): params.setdefault('focusable',True) params.setdefault('cls','link') _button.__init__(self,**params) self.value = value self.font = self.style.font self.style.width, self.style.height = self.font.size(self.value) def paint(self,s): s.blit(self.font.render(self.value, 1, self.style.color),(0,0)) pybox2d-2.3.2/examples/pgu/gui/const.py000066400000000000000000000012331276457661000200170ustar00rootroot00000000000000"""Constants. From pygame: QUIT MOUSEBUTTONDOWN MOUSEBUTTONUP MOUSEMOTION KEYDOWN PGU specific: ENTER EXIT BLUR FOCUS CLICK CHANGE OPEN CLOSE INIT Other: NOATTR """ import pygame from pygame.locals import QUIT, MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION, KEYDOWN, USEREVENT ENTER = pygame.locals.USEREVENT + 0 EXIT = pygame.locals.USEREVENT + 1 BLUR = pygame.locals.USEREVENT + 2 FOCUS = pygame.locals.USEREVENT + 3 CLICK = pygame.locals.USEREVENT + 4 CHANGE = pygame.locals.USEREVENT + 5 OPEN = pygame.locals.USEREVENT + 6 CLOSE = pygame.locals.USEREVENT + 7 INIT = 'init' class NOATTR: pass pybox2d-2.3.2/examples/pgu/gui/container.py000066400000000000000000000323641276457661000206640ustar00rootroot00000000000000""" """ import pygame from pygame.locals import * from .const import * from . import widget, surface from . import pguglobals class Container(widget.Widget): """The base container widget, can be used as a template as well as stand alone.""" def __init__(self,**params): widget.Widget.__init__(self,**params) self.myfocus = None self.mywindow = None self.myhover = None #self.background = 0 self.widgets = [] self.windows = [] self.toupdate = {} self.topaint = {} def update(self,s): updates = [] if self.myfocus: self.toupdate[self.myfocus] = self.myfocus for w in self.topaint: if w is self.mywindow: continue else: sub = surface.subsurface(s,w.rect) #if (hasattr(w, "_container_bkgr")): # sub.blit(w._container_bkgr,(0,0)) w.paint(sub) updates.append(pygame.rect.Rect(w.rect)) for w in self.toupdate: if w is self.mywindow: continue else: us = w.update(surface.subsurface(s,w.rect)) if us: for u in us: updates.append(pygame.rect.Rect(u.x + w.rect.x,u.y+w.rect.y,u.w,u.h)) for w in self.topaint: if w is self.mywindow: w.paint(self.top_surface(s,w)) updates.append(pygame.rect.Rect(w.rect)) else: continue for w in self.toupdate: if w is self.mywindow: us = w.update(self.top_surface(s,w)) else: continue if us: for u in us: updates.append(pygame.rect.Rect(u.x + w.rect.x,u.y+w.rect.y,u.w,u.h)) self.topaint = {} self.toupdate = {} return updates def repaint(self,w=None): if not w: return widget.Widget.repaint(self) self.topaint[w] = w self.reupdate() def reupdate(self,w=None): if not w: return widget.Widget.reupdate(self) self.toupdate[w] = w self.reupdate() def paint(self,s): self.toupdate = {} self.topaint = {} for w in self.widgets: try: sub = surface.subsurface(s, w.rect) except: print('container.paint(): %s not inside %s' % ( w.__class__.__name__,self.__class__.__name__)) print(s.get_width(), s.get_height(), w.rect) print("") else: # if (not hasattr(w,'_container_bkgr') or # w._container_bkgr.get_size() != sub.get_size()): # #w._container_bkgr.get_width() == sub.get_width() and # #w._container_bkgr.get_height() == sub.get_height())): # w._container_bkgr = sub.copy() # w._container_bkgr.fill((0,0,0,0)) # w._container_bkgr.blit(sub,(0,0)) w.paint(sub) for w in self.windows: w.paint(self.top_surface(s,w)) def top_surface(self,s,w): x,y = s.get_abs_offset() s = s.get_abs_parent() return surface.subsurface(s,(x+w.rect.x,y+w.rect.y,w.rect.w,w.rect.h)) def event(self,e): used = False if self.mywindow and e.type == MOUSEBUTTONDOWN: w = self.mywindow if self.myfocus is w: if not w.collidepoint(e.pos): self.blur(w) if not self.myfocus: if w.collidepoint(e.pos): self.focus(w) if not self.mywindow: #### by Gal Koren ## ## if e.type == FOCUS: if e.type == FOCUS and not self.myfocus: #self.first() pass elif e.type == EXIT: if self.myhover: self.exit(self.myhover) elif e.type == BLUR: if self.myfocus: self.blur(self.myfocus) elif e.type == MOUSEBUTTONDOWN: h = None for w in self.widgets: if not w.disabled: # Focusable not considered, since that is only for tabs if w.collidepoint(e.pos): h = w if self.myfocus is not w: self.focus(w) if not h and self.myfocus: self.blur(self.myfocus) elif e.type == MOUSEMOTION: if 1 in e.buttons: if self.myfocus: ws = [self.myfocus] else: ws = [] else: ws = self.widgets h = None for w in ws: if w.collidepoint(e.pos): h = w if self.myhover is not w: self.enter(w) break if not h and self.myhover: self.exit(self.myhover) w = self.myhover if w and w is not self.myfocus: sub = pygame.event.Event(e.type,{ 'buttons':e.buttons, 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y), 'rel':e.rel}) used = w._event(sub) w = self.myfocus if w: if e.type == MOUSEBUTTONUP or e.type == MOUSEBUTTONDOWN: sub = pygame.event.Event(e.type,{ 'button':e.button, 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y)}) elif e.type == CLICK and self.myhover is w: sub = pygame.event.Event(e.type,{ 'button':e.button, 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y)}) elif e.type == MOUSEMOTION: sub = pygame.event.Event(e.type,{ 'buttons':e.buttons, 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y), 'rel':e.rel}) elif (e.type == KEYDOWN or e.type == KEYUP): sub = e else: sub = None #elif e.type == CLICK: #a dead click # sub = None if (sub): used = w._event(sub) if not used and e.type is KEYDOWN: if e.key is K_TAB and self.myfocus: if (e.mod&KMOD_SHIFT) == 0: self.myfocus.next() else: self.myfocus.previous() return True elif e.key == K_UP: self._move_focus(0,-1) return True elif e.key == K_RIGHT: self._move_focus(1,0) return True elif e.key == K_DOWN: self._move_focus(0,1) return True elif e.key == K_LEFT: self._move_focus(-1,0) return True return used def _move_focus(self,dx_,dy_): myfocus = self.myfocus if not self.myfocus: return widgets = self._get_widgets(pguglobals.app) #if myfocus not in widgets: return #widgets.remove(myfocus) if myfocus in widgets: widgets.remove(myfocus) rect = myfocus.get_abs_rect() fx,fy = rect.centerx,rect.centery def sign(v): if v < 0: return -1 if v > 0: return 1 return 0 dist = [] for w in widgets: wrect = w.get_abs_rect() wx,wy = wrect.centerx,wrect.centery dx,dy = wx-fx,wy-fy if dx_ > 0 and wrect.left < rect.right: continue if dx_ < 0 and wrect.right > rect.left: continue if dy_ > 0 and wrect.top < rect.bottom: continue if dy_ < 0 and wrect.bottom > rect.top: continue dist.append((dx*dx+dy*dy,w)) if not len(dist): return dist.sort() d,w = dist.pop(0) w.focus() def _get_widgets(self,c): widgets = [] if c.mywindow: widgets.extend(self._get_widgets(c.mywindow)) else: for w in c.widgets: if isinstance(w,Container): widgets.extend(self._get_widgets(w)) elif not w.disabled and w.focusable: widgets.append(w) return widgets def remove(self,w): """Remove a widget from the container.""" self.blur(w) self.widgets.remove(w) #self.repaint() self.chsize() def add(self,w,x,y): """Add a widget to the container given the position.""" w.style.x = x w.style.y = y w.container = self #NOTE: this might fix it, sort of... #but the thing is, we don't really want to resize #something if it is going to get resized again later #for no reason... #w.rect.x,w.rect.y = w.style.x,w.style.y #w.rect.w, w.rect.h = w.resize() self.widgets.append(w) self.chsize() def open(self,w=None,x=None,y=None): if (not w): w = self if (x != None): # The position is relative to this container rect = self.get_abs_rect() pos = (rect.x + x, rect.y + y) else: pos = None # Have the application open the window pguglobals.app.open(w, pos) def focus(self,w=None): widget.Widget.focus(self) ### by Gal koren # if not w: # return widget.Widget.focus(self) if not w: return if self.myfocus: self.blur(self.myfocus) if self.myhover is not w: self.enter(w) self.myfocus = w w._event(pygame.event.Event(FOCUS)) #print self.myfocus,self.myfocus.__class__.__name__ def blur(self,w=None): if not w: return widget.Widget.blur(self) if self.myfocus is w: if self.myhover is w: self.exit(w) self.myfocus = None w._event(pygame.event.Event(BLUR)) def enter(self,w): if self.myhover: self.exit(self.myhover) self.myhover = w w._event(pygame.event.Event(ENTER)) def exit(self,w): if self.myhover and self.myhover is w: self.myhover = None w._event(pygame.event.Event(EXIT)) # def first(self): # for w in self.widgets: # if w.focusable: # self.focus(w) # return # if self.container: self.container.next(self) # def next(self,w): # if w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... # # for w in self.widgets[self.widgets.index(w)+1:]: # if w.focusable: # self.focus(w) # return # if self.container: return self.container.next(self) def _next(self,orig=None): start = 0 if orig in self.widgets: start = self.widgets.index(orig)+1 for w in self.widgets[start:]: if not w.disabled and w.focusable: if isinstance(w,Container): if w._next(): return True else: self.focus(w) return True return False def _previous(self,orig=None): end = len(self.widgets) if orig in self.widgets: end = self.widgets.index(orig) ws = self.widgets[:end] ws.reverse() for w in ws: if not w.disabled and w.focusable: if isinstance(w,Container): if w._previous(): return True else: self.focus(w) return True return False def next(self,w=None): if w != None and w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... if self._next(w): return True if self.container: return self.container.next(self) def previous(self,w=None): if w != None and w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... if self._previous(w): return True if self.container: return self.container.previous(self) def resize(self,width=None,height=None): #r = self.rect #r.w,r.h = 0,0 ww,hh = 0,0 if self.style.width: ww = self.style.width if self.style.height: hh = self.style.height for w in self.widgets: #w.rect.w,w.rect.h = 0,0 w.rect.x,w.rect.y = w.style.x,w.style.y w.rect.w, w.rect.h = w.resize() #w._resize() ww = max(ww,w.rect.right) hh = max(hh,w.rect.bottom) return ww,hh # Returns the widget with the given name def find(self, name): for w in self.widgets: if (w.name == name): return w elif (isinstance(w, Container)): tmp = w.find(name) if (tmp): return tmp return None pybox2d-2.3.2/examples/pgu/gui/deprecated.py000066400000000000000000000045071276457661000210000ustar00rootroot00000000000000import pygame from .const import * from . import table from . import group from . import button, basic from . import pguglobals def action_open(value): print('gui.action_open',"Scheduled to be deprecated.") value.setdefault('x',None) value.setdefault('y',None) value['container'].open(value['window'],value['x'],value['y']) def action_setvalue(value): print('gui.action_setvalue',"Scheduled to be deprecated.") a,b = value b.value = a.value def action_quit(value): print('gui.action_quit',"Scheduled to be deprecated.") value.quit() def action_exec(value): print('gui.action_exec',"Scheduled to be deprecated.") exec(value['script'],globals(),value['dict']) class Toolbox(table.Table): def __setattr__(self,k,v): _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.group.value = v for w in self.group.widgets: if w.value != v: w.pcls = "" else: w.pcls = "down" self.repaint() def _change(self,value): self.value = self.group.value self.send(CHANGE) def __init__(self,data,cols=0,rows=0,tool_cls='tool',value=None,**params): print('gui.Toolbox','Scheduled to be deprecated.') params.setdefault('cls','toolbox') table.Table.__init__(self,**params) if cols == 0 and rows == 0: cols = len(data) if cols != 0 and rows != 0: rows = 0 self.tools = {} _value = value g = group.Group() self.group = g g.connect(CHANGE,self._change,None) self.group.value = _value x,y,p,s = 0,0,None,1 for ico,value in data: #from __init__ import theme img = pguglobals.app.theme.get(tool_cls+"."+ico,"","image") if img: i = basic.Image(img) else: i = basic.Label(ico,cls=tool_cls+".label") p = button.Tool(g,i,value,cls=tool_cls) self.tools[ico] = p #p.style.hexpand = 1 #p.style.vexpand = 1 self.add(p,x,y) s = 0 if cols != 0: x += 1 if cols != 0 and x == cols: x,y = 0,y+1 if rows != 0: y += 1 if rows != 0 and y == rows: x,y = x+1,0 pybox2d-2.3.2/examples/pgu/gui/dialog.py000066400000000000000000000116621276457661000201370ustar00rootroot00000000000000""" """ import os from .const import * from . import table, area from . import basic, input, button from . import pguglobals class Dialog(table.Table): """A dialog window with a title bar and an "close" button on the bar. Example: title = gui.Label("My Title") main = gui.Container() #add stuff to the container... d = gui.Dialog(title,main) d.open() """ def __init__(self,title,main,**params): """Dialog constructor. Arguments: title -- title widget, usually a label main -- main widget, usually a container """ params.setdefault('cls','dialog') table.Table.__init__(self,**params) self.tr() self.td(title,align=-1,cls=self.cls+'.bar') clos = button.Icon(self.cls+".bar.close") clos.connect(CLICK,self.close,None) self.td(clos,align=1,cls=self.cls+'.bar') self.tr() self.td(main,colspan=2,cls=self.cls+".main") # self.tr() # # # t = table.Table(cls=self.cls+".bar") # t.tr() # t.td(title) # clos = button.Icon(self.cls+".bar.close") # t.td(clos,align=1) # clos.connect(CLICK,self.close,None) # self.add(t,0,0) # # main.rect.w,main.rect.h = main.resize() # clos.rect.w,clos.rect.h = clos.resize() # title.container.style.width = main.rect.w - clos.rect.w # # self.tr() # self.td(main,cls=self.cls+".main") # class FileDialog(Dialog): """A file picker dialog window.""" def __init__(self, title_txt="File Browser", button_txt="Okay", cls="dialog", path=None): """FileDialog constructor. Keyword arguments: title_txt -- title text button_txt -- button text path -- initial path """ cls1 = 'filedialog' if not path: self.curdir = os.getcwd() else: self.curdir = path self.dir_img = basic.Image( pguglobals.app.theme.get(cls1+'.folder', '', 'image')) td_style = {'padding_left': 4, 'padding_right': 4, 'padding_top': 2, 'padding_bottom': 2} self.title = basic.Label(title_txt, cls=cls+".title.label") self.body = table.Table() self.list = area.List(width=350, height=150) self.input_dir = input.Input() self.input_file = input.Input() self._list_dir_() self.button_ok = button.Button(button_txt) self.body.tr() self.body.td(basic.Label("Folder"), style=td_style, align=-1) self.body.td(self.input_dir, style=td_style) self.body.tr() self.body.td(self.list, colspan=3, style=td_style) self.list.connect(CHANGE, self._item_select_changed_, None) self.button_ok.connect(CLICK, self._button_okay_clicked_, None) self.body.tr() self.body.td(basic.Label("File"), style=td_style, align=-1) self.body.td(self.input_file, style=td_style) self.body.td(self.button_ok, style=td_style) self.value = None Dialog.__init__(self, self.title, self.body) def _list_dir_(self): self.input_dir.value = self.curdir self.input_dir.pos = len(self.curdir) self.input_dir.vpos = 0 dirs = [] files = [] try: for i in os.listdir(self.curdir): if os.path.isdir(os.path.join(self.curdir, i)): dirs.append(i) else: files.append(i) except: self.input_file.value = "Opps! no access" #if '..' not in dirs: dirs.append('..') dirs.sort() dirs = ['..'] + dirs files.sort() for i in dirs: #item = ListItem(image=self.dir_img, text=i, value=i) self.list.add(i,image=self.dir_img,value=i) for i in files: #item = ListItem(image=None, text=i, value=i) self.list.add(i,value=i) #self.list.resize() self.list.set_vertical_scroll(0) #self.list.repaintall() def _item_select_changed_(self, arg): self.input_file.value = self.list.value fname = os.path.abspath(os.path.join(self.curdir, self.input_file.value)) if os.path.isdir(fname): self.input_file.value = "" self.curdir = fname self.list.clear() self._list_dir_() def _button_okay_clicked_(self, arg): if self.input_dir.value != self.curdir: if os.path.isdir(self.input_dir.value): self.input_file.value = "" self.curdir = os.path.abspath(self.input_dir.value) self.list.clear() self._list_dir_() else: self.value = os.path.join(self.curdir, self.input_file.value) self.send(CHANGE) self.close() pybox2d-2.3.2/examples/pgu/gui/document.py000066400000000000000000000050741276457661000205160ustar00rootroot00000000000000""" """ import pygame from . import container from . import layout class _document_widget: def __init__(self,w,align=None): #w.rect.w,w.rect.h = w.resize() #self.rect = w.rect self.widget = w if align != None: self.align = align class Document(container.Container): """A document is a container that structures widgets in a left-to-right flow.""" def __init__(self,**params): params.setdefault('cls','document') container.Container.__init__(self,**params) self.layout = layout.Layout(pygame.Rect(0,0,self.rect.w,self.rect.h)) def add(self,e,align=None): """Add a widget to the document flow. Arguments: e -- widget align -- alignment (None,-1,0,1) """ dw = _document_widget(e,align) self.layout.add(dw) e.container = self e._c_dw = dw self.widgets.append(e) self.chsize() def remove(self,e): self.layout._widgets.remove(e._c_dw) self.widgets.remove(e) self.chsize() def block(self,align): """Start a new block given the alignment (-1, 0, 1)""" self.layout.add(align) def space(self, size): """Add a spacer given the size.""" self.layout.add(size) def br(self,height): """Add a line break, given the height.""" self.layout.add((0, height)) def resize(self,width=None,height=None): if self.style.width: width = self.style.width if self.style.height: height = self.style.height for w in self.widgets: w.rect.w,w.rect.h = w.resize() if (width != None and w.rect.w > width) or (height != None and w.rect.h > height): w.rect.w,w.rect.h = w.resize(width,height) dw = w._c_dw dw.rect = pygame.Rect(0,0,w.rect.w,w.rect.h) if width == None: width = 65535 self.layout.rect = pygame.Rect(0,0,width,0) self.layout.resize() _max_w = 0 for w in self.widgets: #xt,xl,xb,xr = w.getspacing() dw = w._c_dw w.style.x,w.style.y,w.rect.w,w.rect.h = dw.rect.x,dw.rect.y,dw.rect.w,dw.rect.h #w.resize() w.rect.x,w.rect.y = w.style.x,w.style.y _max_w = max(_max_w,w.rect.right) #self.rect.w = _max_w #self.layout.rect.w #self.rect.h = self.layout.rect.h #print 'document',_max_w,self.layout.rect.h return _max_w,self.layout.rect.h pybox2d-2.3.2/examples/pgu/gui/form.py000066400000000000000000000051061276457661000176370ustar00rootroot00000000000000""" """ from . import widget class Form(widget.Widget): """A form that automatically will contain all named widgets. After a form is created, all named widget that are subsequently created are added to that form. You may use dict style access to access named widgets. Example: f = gui.Form() w = gui.Input("Phil",name="firstname") w = gui.Input("Hassey",name="lastname") print f.results() print '' print f.items() print '' print f['firstname'].value print f['lastname'].value """ # The current form instance form = None # The list of PGU widgets that are tracked by this form _elist = None # A mapping of PGU widgets tracked by this form (name -> instance) _emap = None # The dirty flag is set when a new widget is added to the form _dirty = 0 def __init__(self): widget.Widget.__init__(self,decorate=False) self._elist = [] self._emap = {} self._dirty = 0 # Register this form as the one used by new widgets Form.form = self def add(self,e,name=None,value=None): """Adds a PGU widget to this form""" if name != None: e.name = name if value != None: e.value = value self._elist.append(e) self._dirty = 1 def _clean(self): # Remove elements from our list if they no longer have an assigned name for e in self._elist[:]: if not hasattr(e,'name') or e.name == None: self._elist.remove(e) # Update the name-to-widget mapping self._emap = {} for e in self._elist: self._emap[e.name] = e self._dirty = 0 def __getitem__(self,k): """Returns the widget instance given the name of the widget""" if self._dirty: self._clean() return self._emap[k] def __contains__(self,k): """Returns true if this form contains the named widget""" if self._dirty: self._clean() if k in self._emap: return True return False def results(self): """Return a dict of name, widget-value pairs.""" if self._dirty: self._clean() r = {} for e in self._elist: # Make sure the widget has a 'value' (eg tables do not) if (hasattr(e, "value")): r[e.name] = e.value else: r[e.name] = None return r def items(self): """Return a list of name, widget pairs.""" return self.results().items() pybox2d-2.3.2/examples/pgu/gui/group.py000066400000000000000000000021471276457661000200320ustar00rootroot00000000000000""" """ from .const import * from . import widget class Group(widget.Widget): """An object for grouping together Form elements. When the value changes, an gui.CHANGE event is sent. Although note, that when the value is a list, it may have to be sent by hand via g.send(gui.CHANGE). """ _value = None widgets = None def __init__(self,name=None,value=None): """Create Group instance. Arguments: name -- name as used in the Form value -- values that are currently selected in the group """ widget.Widget.__init__(self,name=name,value=value) self.widgets = [] def add(self,w): """Add a widget to this group.""" self.widgets.append(w) @property def value(self): return self._value @value.setter def value(self, val): oldval = self._value self._value = val if (oldval != val): self._change() def _change(self): self.send(CHANGE) if (self.widgets): for w in self.widgets: w.repaint() pybox2d-2.3.2/examples/pgu/gui/input.py000066400000000000000000000111141276457661000200270ustar00rootroot00000000000000""" """ import pygame from pygame.locals import * from .const import * from . import widget class Input(widget.Widget): """A single line text input. Example: w = Input(value="Cuzco the Goat",size=20) w = Input("Marbles") """ _value = None def __init__(self,value="",size=20,**params): """Create a new Input widget. Keyword arguments: value -- initial text size -- size for the text box, in characters """ params.setdefault('cls','input') widget.Widget.__init__(self,**params) self.value = value self.pos = len(str(value)) self.vpos = 0 self.font = self.style.font w,h = self.font.size("e"*size) if not self.style.height: self.style.height = h if not self.style.width: self.style.width = w #self.style.height = max(self.style.height,h) #self.style.width = max(self.style.width,w) #self.rect.w=w+self.style.padding_left+self.style.padding_right; #self.rect.h=h+self.style.padding_top+self.style.padding_bottom; def paint(self,s): r = pygame.Rect(0,0,self.rect.w,self.rect.h) cs = 2 #NOTE: should be in a style w,h = self.font.size(self.value[0:self.pos]) x = w-self.vpos if x < 0: self.vpos -= -x if x+cs > s.get_width(): self.vpos += x+cs-s.get_width() s.blit(self.font.render(self.value, 1, self.style.color),(-self.vpos,0)) if self.container.myfocus is self: w,h = self.font.size(self.value[0:self.pos]) r.x = w-self.vpos r.w = cs r.h = h s.fill(self.style.color,r) def _setvalue(self,v): #self.__dict__['value'] = v self._value = v self.send(CHANGE) def event(self,e): used = None if e.type == KEYDOWN: if e.key == K_BACKSPACE: if self.pos: self._setvalue(self.value[:self.pos-1] + self.value[self.pos:]) self.pos -= 1 elif e.key == K_DELETE: if len(self.value) > self.pos: self._setvalue(self.value[:self.pos] + self.value[self.pos+1:]) elif e.key == K_HOME: self.pos = 0 elif e.key == K_END: self.pos = len(self.value) elif e.key == K_LEFT: if self.pos > 0: self.pos -= 1 used = True elif e.key == K_RIGHT: if self.pos < len(self.value): self.pos += 1 used = True elif e.key == K_RETURN: self.next() elif e.key == K_TAB: pass else: #c = str(e.unicode) try: c = (e.unicode).encode('latin-1') if c: self._setvalue(self.value[:self.pos] + c + self.value[self.pos:]) self.pos += 1 except: #ignore weird characters pass self.repaint() elif e.type == FOCUS: self.repaint() elif e.type == BLUR: self.repaint() self.pcls = "" if self.container.myfocus is self: self.pcls = "focus" return used @property def value(self): return self._value @value.setter def value(self, val): if (val == None): val = "" val = str(val) self.pos = len(val) oldval = self._value self._value = val if (oldval != val): self.send(CHANGE) self.repaint() class Password(Input): """A password input, in which text is rendered with '*' characters.""" def paint(self,s): hidden="*" show=len(self.value)*hidden #print "self.value:",self.value if self.pos == None: self.pos = len(self.value) r = pygame.Rect(0,0,self.rect.w,self.rect.h) cs = 2 #NOTE: should be in a style w,h = self.font.size(show) x = w-self.vpos if x < 0: self.vpos -= -x if x+cs > s.get_width(): self.vpos += x+cs-s.get_width() s.blit(self.font.render(show, 1, self.style.color),(-self.vpos,0)) if self.container.myfocus is self: #w,h = self.font.size(self.value[0:self.pos]) w,h = self.font.size(show[0:self.pos]) r.x = w-self.vpos r.w = cs r.h = h s.fill(self.style.color,r) pybox2d-2.3.2/examples/pgu/gui/keysym.py000066400000000000000000000034601276457661000202160ustar00rootroot00000000000000""" """ import pygame from pygame.locals import * from .const import * from . import widget class Keysym(widget.Widget): """A keysym input. This is deprecated and is scheduled to be removed from PGU.""" _value = None def __init__(self,value=None,**params): params.setdefault('cls','keysym') widget.Widget.__init__(self,**params) self.value = value self.font = self.style.font w,h = self.font.size("Right Super") #"Right Shift") self.style.width,self.style.height = w,h #self.rect.w=w+self.style.padding_left+self.style.padding_right #self.rect.h=h+self.style.padding_top+self.style.padding_bottom def event(self,e): used = None if e.type == FOCUS or e.type == BLUR: self.repaint() elif e.type == KEYDOWN: if e.key != K_TAB: self.value = e.key self.repaint() self.send(CHANGE) used = True self.next() self.pcls = "" if self.container.myfocus is self: self.pcls = "focus" return used def paint(self,s): r = pygame.rect.Rect(0,0,self.rect.w,self.rect.h) #render_box(s,self.style.background,r) if self.value == None: return name = "" for p in pygame.key.name(self.value).split(): name += p.capitalize()+" " #r.x = self.style.padding_left; #r.y = self.style.padding_bottom; s.blit(self.style.font.render(name, 1, self.style.color), r) @property def value(self): return self._value @value.setter def value(self, val): if (val != None): val = int(val) oldval = self._value self._value = val if (oldval != val): self.send(CHANGE) self.repaint() pybox2d-2.3.2/examples/pgu/gui/layout.py000066400000000000000000000114451276457661000202140ustar00rootroot00000000000000"""Document layout engine.""" class Layout: """The document layout engine.""" def __init__(self,rect=None): """initialize the object with the size of the box.""" self._widgets = [] self.rect = rect def add(self,e): """Add a document element to the layout. The document element may be * a tuple (w,h) if it is a whitespace element * a tuple (0,h) if it is a linebreak element * an integer -1,0,1 if it is a command to start a new block of elements that are aligned either left,center, or right. * an object with a .rect (for size) -- such as a word element * an object with a .rect (for size) and .align -- such as an image element """ self._widgets.append(e) def resize(self): """Resize the layout. This method recalculates the position of all document elements after they have been added to the document. .rect.x,y will be updated for all objects. """ self.init() self.widgets = [] for e in self._widgets: if type(e) is tuple and e[0] != 0: self.do_space(e) elif type(e) is tuple and e[0] == 0: self.do_br(e[1]) elif type(e) is int: self.do_block(align=e) elif hasattr(e,'align'): self.do_align(e) else: self.do_item(e) self.line() self.rect.h = max(self.y,self.left_bottom,self.right_bottom) def init(self): self.x,self.y = self.rect.x,self.rect.y self.left = self.rect.left self.right = self.rect.right self.left_bottom = 0 self.right_bottom = 0 self.y = self.rect.y self.x = self.rect.x self.h = 0 self.items = [] self.align = -1 def getleft(self): if self.y > self.left_bottom: self.left = self.rect.left return self.left def getright(self): if self.y > self.right_bottom: self.right = self.rect.right return self.right def do_br(self,h): self.line() self.h = h def do_block(self,align=-1): self.line() self.align = align def do_align(self,e): align = e.align ox,oy,oh = self.x,self.y,self.h w,h = e.rect.w,e.rect.h if align == 0: self.line() self.x = self.rect.left + (self.rect.width-w)/2 self.fit = 0 elif align == -1: self.line() self.y = max(self.left_bottom,self.y + self.h) self.h = 0 self.x = self.rect.left elif align == 1: self.line() self.y = max(self.right_bottom,self.y + self.h) self.h = 0 self.x = self.rect.left + (self.rect.width-w) e.rect.x,e.rect.y = self.x,self.y self.x = self.x + w self.y = self.y if align == 0: self.h = max(self.h,h) self.y = self.y + self.h self.x = self.getleft() self.h = 0 elif align == -1: self.left = self.x self.left_bottom = self.y + h self.x,self.y,self.h = ox + w,oy,oh elif align == 1: self.right = self.x - w self.right_bottom = self.y + h self.x,self.y,self.h = ox,oy,oh self.widgets.append(e) def do_space(self,e): w,h = e if self.x+w >= self.getright(): self.line() else: self.items.append(e) self.h = max(self.h,h) self.x += w def do_item(self,e): w,h = e.rect.w,e.rect.h if self.x+w >= self.getright(): self.line() self.items.append(e) self.h = max(self.h,h) self.x += w def line(self): x1 = self.getleft() x2 = self.getright() align = self.align y = self.y if len(self.items) != 0 and type(self.items[-1]) == tuple: del self.items[-1] w = 0 for e in self.items: if type(e) == tuple: w += e[0] else: w += e.rect.w if align == -1: x = x1 elif align == 0: x = x1 + ((x2-x1)-w)/2 self.fit = 0 elif align == 1: x = x2 - w for e in self.items: if type(e) == tuple: x += e[0] else: e.rect.x,e.rect.y = x,y self.widgets.append(e) x += e.rect.w self.items = [] self.y = self.y + self.h self.x = self.getleft() self.h = 0 pybox2d-2.3.2/examples/pgu/gui/menus.py000066400000000000000000000064041276457661000200250ustar00rootroot00000000000000""" """ from .const import * from . import table from . import basic, button class _Menu_Options(table.Table): def __init__(self,menu,**params): table.Table.__init__(self,**params) self.menu = menu def event(self,e): handled = False arect = self.get_abs_rect() if e.type == MOUSEMOTION: abspos = e.pos[0]+arect.x,e.pos[1]+arect.y for w in self.menu.container.widgets: if not w is self.menu: mrect = w.get_abs_rect() if mrect.collidepoint(abspos): self.menu._close(None) w._open(None) handled = True if not handled: table.Table.event(self,e) class _Menu(button.Button): def __init__(self,parent,widget=None,**params): #TODO widget= could conflict with module widget params.setdefault('cls','menu') button.Button.__init__(self,widget,**params) self.parent = parent self._cls = self.cls self.options = _Menu_Options(self, cls=self.cls+".options") self.connect(CLICK,self._open,None) self.pos = 0 def _open(self,value): self.parent.value = self self.pcls = 'down' self.repaint() self.container.open(self.options,self.rect.x,self.rect.bottom) self.options.connect(BLUR,self._close,None) self.options.focus() self.repaint() def _pass(self,value): pass def _close(self,value): self.pcls = '' self.parent.value = None self.repaint() self.options.close() def _valuefunc(self,value): self._close(None) if value['fnc'] != None: value['fnc'](value['value']) def event(self,e): button.Button.event(self,e) if self.parent.value == self: self.pcls = 'down' def add(self,w,fnc=None,value=None): w.style.align = -1 b = button.Button(w,cls=self.cls+".option") b.connect(CLICK,self._valuefunc,{'fnc':fnc,'value':value}) self.options.tr() self.options.add(b) return b class Menus(table.Table): """A drop down menu bar. Example: data = [ ('File/Save', fnc_save, None), ('File/New', fnc_new, None), ('Edit/Copy', fnc_copy, None), ('Edit/Cut', fnc_cut, None), ('Help/About', fnc_help, help_about_content), ('Help/Reference', fnc_help, help_reference_content), ] w = Menus(data) """ def __init__(self,data,menu_cls='menu',**params): params.setdefault('cls','menus') table.Table.__init__(self,**params) self.value = None n,m,mt = 0,None,None for path,cmd,value in data: parts = path.split("/") if parts[0] != mt: mt = parts[0] m = _Menu(self,basic.Label(mt,cls=menu_cls+".label"),cls=menu_cls) self.add(m,n,0) n += 1 print ("add", parts[1], cmd, value) m.add(basic.Label(parts[1],cls=m.cls+".option.label"),cmd,value) pybox2d-2.3.2/examples/pgu/gui/misc.py000066400000000000000000000020311276457661000176210ustar00rootroot00000000000000from .const import * from . import widget from . import pguglobals class ProgressBar(widget.Widget): """A progress bar widget. Example: w = gui.ProgressBar(0,0,100) w.value = 25 """ _value = None def __init__(self,value,min,max,**params): params.setdefault('cls','progressbar') widget.Widget.__init__(self,**params) self.min,self.max,self.value = min,max,value def paint(self,s): if (self.value != None): r = pygame.rect.Rect(0,0,self.rect.w,self.rect.h) r.w = r.w*(self.value-self.min)/(self.max-self.min) self.bar = r pguglobals.app.theme.render(s,self.style.bar,r) @property def value(self): return self._value @value.setter def value(self, val): val = int(val) val = max(val, self.min) val = min(val, self.max) oldval = self._value self._value = val if (oldval != val): self.send(CHANGE) self.repaint() pybox2d-2.3.2/examples/pgu/gui/pguglobals.py000066400000000000000000000005501276457661000210310ustar00rootroot00000000000000"""Contains the global reference to the PGU application.""" # pguglobals.py - A place to stick global variables that need to be accessed # from other modules. To avoid problems with circular imports # this module should not import any other PGU module. # A global reference to the application instance (App class) app = None pybox2d-2.3.2/examples/pgu/gui/readme.txt000066400000000000000000000001431276457661000203140ustar00rootroot00000000000000This is the GUI module from Phil's pyGame Utilities: http://www.imitationpickles.org/pgu/wiki/indexpybox2d-2.3.2/examples/pgu/gui/select.py000066400000000000000000000107721276457661000201600ustar00rootroot00000000000000""" """ import traceback from .const import * from .button import Button from .basic import Label, Image from .table import Table class Select(Table): """A combo dropdown box widget. Example: w = Select(value="goats") w.add("Cats","cats") w.add("Goats","goats") w.add("Dogs","Dogs") w.value = 'dogs' #changes the value from goats to dogs """ # The drop-down arrow button for the selection widget top_arrow = None # A button displaying the currently selected item top_selection = None # The first option added to the selector firstOption = None # The PGU table of options options = None _value = None def __init__(self,value=None,**params): params.setdefault('cls','select') Table.__init__(self,**params) label = Label(" ",cls=self.cls+".option.label") self.top_selected = Button(label, cls=self.cls+".selected") Table.add(self,self.top_selected) #,hexpand=1,vexpand=1)#,0,0) self.top_arrow = Button(Image(self.style.arrow), cls=self.cls+".arrow") Table.add(self,self.top_arrow) #,hexpand=1,vexpand=1) #,1,0) self.options = Table(cls=self.cls+".options") self.options.connect(BLUR,self._close,None) self.options.name = "pulldown-table" self.values = [] self.value = value def resize(self,width=None,height=None): max_w,max_h = 0,0 for w in self.options.widgets: w.rect.w,w.rect.h = w.resize() max_w,max_h = max(max_w,w.rect.w),max(max_h,w.rect.h) #xt,xr,xb,xl = self.top_selected.getspacing() self.top_selected.style.width = max_w #+ xl + xr self.top_selected.style.height = max_h #+ xt + xb self.top_arrow.connect(CLICK,self._open,None) self.top_selected.connect(CLICK,self._open,None) w,h = Table.resize(self,width,height) self.options.style.width = w #HACK: sort of, but not a big one.. self.options.resize() return w,h def _open(self,value): opts = self.options opts.rect.w, opts.rect.h = opts.resize() # y = self.rect.y # c = self.container # while hasattr(c, 'container'): # y += c.rect.y # if (not c.container): # break # c = c.container # if y + self.rect.h + opts.rect.h <= c.rect.h: #down # dy = self.rect.y + self.rect.h # else: #up # dy = self.rect.y - self.rect.h opts.rect.w, opts.rect.h = opts.resize() # TODO - make sure there is enough space to open down # ... yp = self.rect.bottom-1 self.container.open(opts, self.rect.x, yp) self.firstOption.focus() # TODO - this is a hack for opt in self.options.widgets: opt.repaint() def _close(self,value): self.options.close() self.top_selected.focus() def _setvalue(self,value): self.value = value._value if self.container: #self.chsize() #HACK: improper use of resize() #self.resize() #to recenter the new value, etc. pass # #self._resize() self._close(None) #self.repaint() #this will happen anyways @property def value(self): return self._value @value.setter def value(self, val): mywidget = None for w in self.values: if w._value == val: mywidget = w oldval = self._value self._value = val if (oldval != val): self.send(CHANGE) self.repaint() if not mywidget: mywidget = Label(" ",cls=self.cls+".option.label") self.top_selected.value = mywidget def add(self,w,value=None): """Add a widget and associated value to the dropdown box.""" if type(w) == str: w = Label(w,cls=self.cls+".option.label") w.style.align = -1 btn = Button(w,cls=self.cls+".option") btn.connect(CLICK,self._setvalue,w) self.options.tr() self.options.add(btn) if (not self.firstOption): self.firstOption = btn if value != None: w._value = value else: w._value = w if self.value == w._value: self.top_selected.value = w self.values.append(w) pybox2d-2.3.2/examples/pgu/gui/slider.py000066400000000000000000000255741276457661000201710ustar00rootroot00000000000000import pygame from pygame.locals import * from .const import * from . import widget from . import table from . import basic from . import pguglobals _SLIDER_HORIZONTAL = 0 _SLIDER_VERTICAL = 1 class _slider(widget.Widget): _value = None def __init__(self,value,orient,min,max,size,step=1,**params): params.setdefault('cls','slider') widget.Widget.__init__(self,**params) self.min,self.max,self.value,self.orient,self.size,self.step = min,max,value,orient,size,step def paint(self,s): self.value = self.value r = pygame.rect.Rect(0,0,self.style.width,self.style.height) if self.orient == _SLIDER_HORIZONTAL: r.x = (self.value-self.min) * (r.w-self.size) / max(1,self.max-self.min); r.w = self.size; else: r.y = (self.value-self.min) * (r.h-self.size) / max(1,self.max-self.min); r.h = self.size; self.bar = r pguglobals.app.theme.render(s,self.style.bar,r) def event(self,e): used = None r = pygame.rect.Rect(0,0,self.style.width,self.style.height) adj = 0 if e.type == ENTER: self.repaint() elif e.type == EXIT: self.repaint() elif e.type == MOUSEBUTTONDOWN: if self.bar.collidepoint(e.pos): self.grab = e.pos[0],e.pos[1] self.grab_value = self.value else: x,y,adj = e.pos[0],e.pos[1],1 self.grab = None self.repaint() elif e.type == MOUSEBUTTONUP: #x,y,adj = e.pos[0],e.pos[1],1 self.repaint() elif e.type == MOUSEMOTION: if 1 in e.buttons and self.container.myfocus is self: if self.grab != None: rel = e.pos[0]-self.grab[0],e.pos[1]-self.grab[1] if self.orient == _SLIDER_HORIZONTAL: d = (r.w - self.size) if d != 0: self.value = self.grab_value + ((self.max-self.min) * rel[0] / d) else: d = (r.h - self.size) if d != 0: self.value = self.grab_value + ((self.max-self.min) * rel[1] / d) else: x,y,adj = e.pos[0],e.pos[1],1 elif e.type is KEYDOWN: if self.orient == _SLIDER_HORIZONTAL and e.key == K_LEFT: self.value -= self.step used = True elif self.orient == _SLIDER_HORIZONTAL and e.key == K_RIGHT: self.value += self.step used = True elif self.orient == _SLIDER_VERTICAL and e.key == K_UP: self.value -= self.step used = True elif self.orient == _SLIDER_VERTICAL and e.key == K_DOWN: self.value += self.step used = True if adj: if self.orient == _SLIDER_HORIZONTAL: d = self.size/2 - (r.w/(self.max-self.min+1))/2 self.value = (x-d) * (self.max-self.min) / (r.w-self.size+1) + self.min else: d = self.size/2 - (r.h/(self.max-self.min+1))/2 self.value = (y-d) * (self.max-self.min) / (r.h-self.size+1) + self.min self.pcls = "" if self.container.myhover is self: self.pcls = "hover" if (self.container.myfocus is self and 1 in pygame.mouse.get_pressed()): self.pcls = "down" return used # TODO - replace this with property functions and setters def __setattr__(self,k,v): if k == 'value': v = int(v) v = max(v,self.min) v = min(v,self.max) _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint() if hasattr(self,'size'): sz = min(self.size,max(self.style.width,self.style.height)) sz = max(sz,min(self.style.width,self.style.height)) self.__dict__['size'] = sz #self.size = sz if hasattr(self,'max') and hasattr(self,'min'): if self.max < self.min: self.max = self.min # @property # def value(self): # return self._value # # @value.setter # def value(self, val): # val = int(val) # val = max(val, self.min) # val = min(val, self.max) # # oldval = self._value # self._value = val # if (oldval != val): # self.send(CHANGE) # self.repaint() # # if hasattr(self,'size'): # sz = min(self.size,max(self.style.width,self.style.height)) # sz = max(sz,min(self.style.width,self.style.height)) # self.size = sz # # if hasattr(self,'max') and hasattr(self,'min'): # if self.max < self.min: self.max = self.min class VSlider(_slider): """A verticle slider.""" def __init__(self,value,min,max,size,step=1,**params): """Construct a veritcal slider widget. Arguments: value -- the default position of the slider, between min and max min -- the minimum value for the slider max -- the maximum value size -- the length of the slider bar in pixels step -- how much to jump when using the keyboard """ params.setdefault('cls','vslider') _slider.__init__(self,value,_SLIDER_VERTICAL,min,max,size,step,**params) class HSlider(_slider): """A horizontal slider.""" def __init__(self,value,min,max,size,step=1,**params): params.setdefault('cls','hslider') _slider.__init__(self,value,_SLIDER_HORIZONTAL,min,max,size,step,**params) class HScrollBar(table.Table): """A horizontal scroll bar.""" def __init__(self,value,min,max,size,step=1,**params): params.setdefault('cls','hscrollbar') table.Table.__init__(self,**params) self.slider = _slider(value,_SLIDER_HORIZONTAL,min,max,size,step=step,cls=self.cls+'.slider') self.minus = basic.Image(self.style.minus) self.minus.connect(MOUSEBUTTONDOWN,self._click,-1) self.slider.connect(CHANGE,self.send,CHANGE) self.minus2 = basic.Image(self.style.minus) self.minus2.connect(MOUSEBUTTONDOWN,self._click,-1) self.plus = basic.Image(self.style.plus) self.plus.connect(MOUSEBUTTONDOWN,self._click,1) self.size = size def _click(self,value): self.slider.value += self.slider.step*value def resize(self,width=None,height=None): self.clear() self.tr() w = self.style.width h = self.slider.style.height ww = 0 if w > (h*2 + self.minus.style.width+self.plus.style.width): self.td(self.minus) ww += self.minus.style.width self.td(self.slider) if w > (h*2 + self.minus.style.width+self.minus2.style.width+self.plus.style.width): self.td(self.minus2) ww += self.minus2.style.width if w > (h*2 + self.minus.style.width+self.plus.style.width): self.td(self.plus) ww += self.plus.style.width #HACK: handle theme sizing properly xt,xr,xb,xl = pguglobals.app.theme.getspacing(self.slider) ww += xr+xl self.slider.style.width = self.style.width - ww setattr(self.slider,'size',self.size * self.slider.style.width / max(1,self.style.width)) #self.slider.size = self.size * self.slider.style.width / max(1,self.style.width) return table.Table.resize(self,width,height) @property def min(self): return self.slider.min @min.setter def min(self, value): self.slider.min = value @property def max(self): return self.slider.max @max.setter def max(self, value): self.slider.max = value @property def value(self): return self.slider.value @value.setter def value(self, value): self.slider.value = value @property def step(self): return self.slider.step @step.setter def step(self, value): self.slider.step = value # def __setattr__(self,k,v): # if k in ('min','max','value','step'): # return setattr(self.slider,k,v) # self.__dict__[k]=v # def __getattr__(self,k): # if k in ('min','max','value','step'): # return getattr(self.slider,k) # return table.Table.__getattr__(self,k) #self.__dict__[k] class VScrollBar(table.Table): """A vertical scroll bar.""" def __init__(self,value,min,max,size,step=1,**params): params.setdefault('cls','vscrollbar') table.Table.__init__(self,**params) self.minus = basic.Image(self.style.minus) self.minus.connect(MOUSEBUTTONDOWN,self._click,-1) self.minus2 = basic.Image(self.style.minus) self.minus2.connect(MOUSEBUTTONDOWN,self._click,-1) self.plus = basic.Image(self.style.plus) self.plus.connect(MOUSEBUTTONDOWN,self._click,1) self.slider = _slider(value,_SLIDER_VERTICAL,min,max,size,step=step,cls=self.cls+'.slider') self.slider.connect(CHANGE,self.send,CHANGE) self.size = size def _click(self,value): self.slider.value += self.slider.step*value def resize(self,width=None,height=None): self.clear() h = self.style.height w = self.slider.style.width hh = 0 if h > (w*2 + self.minus.style.height+self.plus.style.height): self.tr() self.td(self.minus) hh += self.minus.style.height self.tr() self.td(self.slider) if h > (w*2 + self.minus.style.height+self.minus2.style.height+self.plus.style.height): self.tr() self.td(self.minus2) hh += self.minus2.style.height if h > (w*2 + self.minus.style.height+self.plus.style.height): self.tr() self.td(self.plus) hh += self.plus.style.height #HACK: handle theme sizing properly xt,xr,xb,xl = pguglobals.app.theme.getspacing(self.slider) hh += xt+xb self.slider.style.height = self.style.height - hh setattr(self.slider,'size',self.size * self.slider.style.height / max(1,self.style.height)) return table.Table.resize(self,width,height) def __setattr__(self,k,v): if k in ('min','max','value','step'): return setattr(self.slider,k,v) self.__dict__[k]=v def __getattr__(self,k): if k in ('min','max','value','step'): return getattr(self.slider,k) return table.Table.__getattr__(self,k) pybox2d-2.3.2/examples/pgu/gui/style.py000066400000000000000000000017371276457661000200420ustar00rootroot00000000000000""" """ from . import pguglobals class Style: """The class used by widget for the widget.style This object is used mainly as a dictionary, accessed via widget.style.attr, as opposed to widget.style['attr']. It automatically grabs information from the theme via value = theme.get(widget.cls,widget.pcls,attr) """ def __init__(self, obj, dict): self.obj = obj for k,v in dict.items(): self.__dict__[k]=v def __getattr__(self, attr): value = pguglobals.app.theme.get(self.obj.cls, self.obj.pcls, attr) if attr in ( 'border_top','border_right','border_bottom','border_left', 'padding_top','padding_right','padding_bottom','padding_left', 'margin_top','margin_right','margin_bottom','margin_left', 'align','valign','width','height', ): self.__dict__[attr] = value return value def __setattr__(self, attr, value): self.__dict__[attr] = value pybox2d-2.3.2/examples/pgu/gui/surface.py000066400000000000000000000106101276457661000203200ustar00rootroot00000000000000"""Funtions for manipulating pygame surfaces.""" import pygame def subsurface(s,r): """Return the subsurface of a surface, with some help, checks.""" r = pygame.Rect(r) if r.x < 0 or r.y < 0: raise Exception("rectangle out of bounds: surface=%dx%d, rect=%s" % ( s.get_width(),s.get_height(),r)) w,h = s.get_width(),s.get_height() if r.right > w: r.w -= r.right-w if r.bottom > h: r.h -= r.bottom-h assert(r.w >= 0 and r.h >= 0) return s.subsurface(r) class ProxySurface: """ A surface-like object which smartly handle out-of-area blitting. Note that only one of parent and real_surface should be supplied. Arguments: parent -- a ProxySurface object real_surface -- a pygame Surface object Attributes: mysubsurface -- a real and valid pygame.Surface object to be used for blitting. x, y -- if the proxy surface is to the left or above the parent offset -- an option which let you scroll the whole blitted content """ def __init__(self, parent, rect, real_surface, offset=(0, 0)): self.offset = offset self.x = self.y = 0 if rect.x < 0: self.x = rect.x if rect.y < 0: self.y = rect.y self.real_surface = real_surface if real_surface == None: self.mysubsurface = parent.mysubsurface.subsurface( parent.mysubsurface.get_rect().clip(rect)) else: self.mysubsurface = real_surface.subsurface( real_surface.get_rect().clip(rect)) rect.topleft = (0, 0) self.rect = rect def blit(self, s, pos, rect=None): if rect == None: rect = s.get_rect() pos = (pos[0] + self.offset[0] + self.x, pos[1] + self.offset[1] + self.y) self.mysubsurface.blit(s, pos, rect) def subsurface(self, rect): r = pygame.Rect(rect).move(self.offset[0] + self.x, self.offset[1] + self.y) return ProxySurface(self, r, self.real_surface) def fill(self, color, rect=None): if rect != None: self.mysubsurface.fill(color, rect) else: self.mysubsurface.fill(color) def get_rect(self): return self.rect def get_width(self): return self.rect[2] def get_height(self): return self.rect[3] def get_abs_offset(): return self.rect[:2] def get_abs_parent(): return self.mysubsurface.get_abs_parent() def set_clip(self, rect=None): if rect == None: self.mysubsurface.set_clip(self.mysubsurface.get_rect()) else: rect = [rect[0] + self.offset[0] + self.x, rect[1] + self.offset[0] + self.y, rect[2], rect[3]] self.mysubsurface.set_clip(rect) class xProxySurface: """This class is obsolete and is scheduled to be removed.""" def __init__(self, parent, rect, real_surface, offset=(0, 0)): self.offset = offset self.x = self.y = 0 if rect[0] < 0: self.x = rect[0] if rect[1] < 0: self.y = rect[1] self.real_surface = real_surface if real_surface == None: self.mysubsurface = parent.mysubsurface.subsurface(parent.mysubsurface.get_rect().clip(rect)) else: self.mysubsurface = real_surface.subsurface(real_surface.get_rect().clip(rect)) rect[0], rect[1] = 0, 0 self.rect = rect def blit(self, s, pos, rect=None): if rect == None: rect = s.get_rect() pos = (pos[0] + self.offset[0] + self.x, pos[1] + self.offset[1] + self.y) self.mysubsurface.blit(s, pos, rect) def subsurface(self, rect): return ProxySurface(self, pygame.Rect(rect).move(self.offset[0] + self.x, self.offset[1] + self.y),self.real_surface) def fill(self, color, rect=None): if rect != None: self.mysubsurface.fill(color, rect) else: self.mysubsurface.fill(color) def get_rect(self): return self.rect def get_width(self): return self.rect[2] def get_height(self): return self.rect[3] def get_abs_offset(): return self.rect[:2] def get_abs_parent(): return self.mysubsurface.get_abs_parent() def set_clip(self, rect=None): if rect == None: self.mysubsurface.set_clip(self.mysubsurface.get_rect()) else: rect = [rect[0] + self.offset[0] + self.x, rect[1] + self.offset[0] + self.y, rect[2], rect[3]] self.mysubsurface.set_clip(rect) pybox2d-2.3.2/examples/pgu/gui/table.py000066400000000000000000000311731276457661000177660ustar00rootroot00000000000000""" """ import sys from .const import * from . import container class Table(container.Container): """A table style container widget. Example: t = gui.Table() # This starts a new row of the table t.tr() # The 'td' call creates a new table cell t.td(gui.Label("Name:"), align=-1) t.td(gui.Input()) t.tr() # The table cells can span multiple columns t.td(gui.Label("Email"), align=-1, colspan=2) t.tr() t.td(gui.Input(), colspan=2) """ def __init__(self, **params): params.setdefault('cls','table') container.Container.__init__(self, **params) self._rows = [] self._curRow = 0 self._trok = False self._hpadding = params.get("hpadding", 0) self._vpadding = params.get("vpadding", 0) def getRows(self): return len(self._rows) def getColumns(self): if self._rows: return len(self._rows[0]) else: return 0 def remove_row(self, n): #NOTE: won't work in all cases. if n >= self.getRows(): print("Trying to remove a nonexistant row:", n, "there are only", self.getRows(), "rows") return for cell in self._rows[n]: if isinstance(cell, dict) and cell["widget"] in self.widgets: #print 'removing widget' self.widgets.remove(cell["widget"]) del self._rows[n] #print "got here" for w in self.widgets: if w.style.row > n: w.style.row -= 1 if self._curRow >= n: self._curRow -= 1 #self.rect.w, self.rect.h = self.resize() #self.repaint() self.chsize() def clear(self): self._rows = [] self._curRow = 0 self._trok = False self.widgets = [] self.chsize() #print 'clear',self,self._rows def _addRow(self): self._rows.append([None for x in range(self.getColumns())]) def tr(self): """Start on the next row.""" if not self._trok: self._trok = True return self._curRow += 1 if self.getRows() <= self._curRow: self._addRow() def _addColumn(self): if not self._rows: self._addRow() for row in self._rows: row.append(None) def _setCell(self, w, col, row, colspan=1, rowspan=1): #make room for the widget by adding columns and rows while self.getColumns() < col + colspan: self._addColumn() while self.getRows() < row + rowspan: self._addRow() #print w.__class__.__name__,col,row,colspan,rowspan #actual widget setting and modification stuff w.container = self w.style.row = row #HACK - to work with gal's list w.style.col = col #HACK - to work with gal's list self._rows[row][col] = {"widget":w, "colspan":colspan, "rowspan":rowspan} self.widgets.append(self._rows[row][col]["widget"]) #set the spanned columns #for acell in range(col + 1, col + colspan): # self._rows[row][acell] = True #set the spanned rows and the columns on them #for arow in range(row + 1, row + rowspan): # for acell in range(col, col + colspan): #incorrect? # self._rows[arow][acell] = True for arow in range(row, row + rowspan): for acell in range(col, col + colspan): #incorrect? if row != arow or col != acell: self._rows[arow][acell] = True def td(self, w, col=None, row=None, colspan=1, rowspan=1, **params): """Add a widget to a table after wrapping it in a TD container. Keyword arguments: w -- widget col -- column row -- row colspan -- colspan rowspan -- rowspan align -- horizontal alignment (-1,0,1) valign -- vertical alignment (-1,0,1) params -- other params for the TD container, style information, etc """ Table.add(self,_Table_td(w, **params), col=col, row=row, colspan=colspan, rowspan=rowspan) def add(self, w, col=None, row=None, colspan=1, rowspan=1): """Add a widget directly into the table, without wrapping it in a TD container. See Table.td for an explanation of the parameters. """ self._trok = True #if no row was specifically specified, set it to the current row if row is None: row = self._curRow #print row #if its going to be a new row, have it be on the first column if row >= self.getRows(): col = 0 #try to find an open cell for the widget if col is None: for cell in range(self.getColumns()): if col is None and not self._rows[row][cell]: col = cell break #otherwise put the widget in a new column if col is None: col = self.getColumns() self._setCell(w, col, row, colspan=colspan, rowspan=rowspan) self.chsize() return def remove(self,w): if hasattr(w,'_table_td'): w = w._table_td row,col = w.style.row,w.style.col cell = self._rows[row][col] colspan,rowspan = cell['colspan'],cell['rowspan'] for arow in range(row , row + rowspan): for acell in range(col, col + colspan): #incorrect? self._rows[arow][acell] = False self.widgets.remove(w) self.chsize() def resize(self, width=None, height=None): #if 1 or self.getRows() == 82: #print '' #print 'resize',self.getRows(),self.getColumns(),width,height #import inspect #for obj,fname,line,fnc,code,n in inspect.stack()[9:20]: # print fname,line,':',fnc,code[0].strip() #resize the widgets to their smallest size for w in self.widgets: w.rect.w, w.rect.h = w.resize() #calculate row heights and column widths rowsizes = [0 for y in range(self.getRows())] columnsizes = [0 for x in range(self.getColumns())] for row in range(self.getRows()): for cell in range(self.getColumns()): if self._rows[row][cell] and self._rows[row][cell] is not True: if not self._rows[row][cell]["colspan"] > 1: columnsizes[cell] = max(columnsizes[cell], self._rows[row][cell]["widget"].rect.w) if not self._rows[row][cell]["rowspan"] > 1: rowsizes[row] = max(rowsizes[row], self._rows[row][cell]["widget"].rect.h) #distribute extra space if necessary for wide colspanning/rowspanning def _table_div(a,b,c): v,r = a/b, a%b if r != 0 and (c%b) 1: columns = range(cell, cell + self._rows[row][cell]["colspan"]) totalwidth = 0 for acol in columns: totalwidth += columnsizes[acol] if totalwidth < self._rows[row][cell]["widget"].rect.w: for acol in columns: columnsizes[acol] += _table_div(self._rows[row][cell]["widget"].rect.w - totalwidth, self._rows[row][cell]["colspan"],acol) if self._rows[row][cell]["rowspan"] > 1: rows = range(row, row + self._rows[row][cell]["rowspan"]) totalheight = 0 for arow in rows: totalheight += rowsizes[arow] if totalheight < self._rows[row][cell]["widget"].rect.h: for arow in rows: rowsizes[arow] += _table_div(self._rows[row][cell]["widget"].rect.h - totalheight, self._rows[row][cell]["rowspan"],arow) # Now calculate the total width and height occupied by the rows and columns rowsizes = [sz+2*self._vpadding for sz in rowsizes] columnsizes = [sz+2*self._hpadding for sz in columnsizes] # Now possibly expand the table cells to fill out the specified width w = sum(columnsizes) if (w > 0 and w < self.style.width): amount = (self.style.width - w)/float(w) for n in range(0, len(columnsizes)): columnsizes[n] += columnsizes[n] * amount # Do the same for the table height h = sum(rowsizes) if (h > 0 and h < self.style.height): amount = (self.style.height - h) / float(h) for n in range(0, len(rowsizes)): rowsizes[n] += rowsizes[n] * amount #set the widget's position by calculating their row/column x/y offset cellpositions = [[[sum(columnsizes[0:cell]), sum(rowsizes[0:row])] for cell in range(self.getColumns())] for row in range(self.getRows())] for row in range(self.getRows()): for cell in range(self.getColumns()): if self._rows[row][cell] and self._rows[row][cell] is not True: x, y = cellpositions[row][cell] w = sum(columnsizes[cell:cell+self._rows[row][cell]["colspan"]]) h = sum(rowsizes[row:row+self._rows[row][cell]["rowspan"]]) widget = self._rows[row][cell]["widget"] widget.rect.x = x widget.rect.y = y if 1 and (w,h) != (widget.rect.w,widget.rect.h): # if h > 20: # print widget.widget.__class__.__name__, (widget.rect.w,widget.rect.h),'=>',(w,h) widget.rect.w, widget.rect.h = widget.resize(w, h) #print self._rows[row][cell]["widget"].rect #print columnsizes #print sum(columnsizes) #size = sum(columnsizes), sum(rowsizes); print size #return the tables final size return sum(columnsizes),sum(rowsizes) class _Table_td(container.Container): def __init__(self,widget,**params):#hexpand=0,vexpand=0, container.Container.__init__(self,**params) self.widget = widget #self.hexpand=hexpand #self.vexpand=vexpand widget._table_td = self self.add(widget,0,0) def resize(self,width=None,height=None): w = self.widget #expansion code, but i didn't like the idea that much.. #a bit obscure, fairly useless when a user can just #add a widget to a table instead of td it in. #ww,hh=None,None #if self.hexpand: ww = self.style.width #if self.vexpand: hh = self.style.height #if self.hexpand and width != None: ww = max(ww,width) #if self.vexpand and height != None: hh = max(hh,height) #w.rect.w,w.rect.h = w.resize(ww,hh) #why bother, just do the lower mentioned item... w.rect.w,w.rect.h = w.resize() #this should not be needed, widgets should obey their sizing on their own. # if (self.style.width!=0 and w.rect.w > self.style.width) or (self.style.height!=0 and w.rect.h > self.style.height): # ww,hh = None,None # if self.style.width: ww = self.style.width # if self.style.height: hh = self.style.height # w.rect.w,w.rect.h = w.resize(ww,hh) #in the case that the widget is too big, we try to resize it if (width != None and width < w.rect.w) or (height != None and height < w.rect.h): (w.rect.w, w.rect.h) = w.resize(width, height) # In python3 max and min no longer accept None as an argument if (width == None): width = -sys.maxsize if (height == None): height = -sys.maxsize width = max(width, w.rect.w, self.style.width) #,self.style.cell_width) height = max(height, w.rect.h, self.style.height) #,self.style.cell_height) dx = width-w.rect.w dy = height-w.rect.h w.rect.x = (self.style.align+1)*dx/2 w.rect.y = (self.style.valign+1)*dy/2 return width,height pybox2d-2.3.2/examples/pgu/gui/textarea.py000066400000000000000000000263021276457661000205120ustar00rootroot00000000000000""" """ import pygame from pygame.locals import * from .const import * from . import widget class TextArea(widget.Widget): """A multi-line text input. Example: w = TextArea(value="Cuzco the Goat",size=20) w = TextArea("Marbles") w = TextArea("Groucho\nHarpo\nChico\nGummo\nZeppo\n\nMarx", 200, 400, 12) """ def __init__(self,value="",width = 120, height = 30, size=20,**params): params.setdefault('cls','input') params.setdefault('width', width) params.setdefault('height', height) widget.Widget.__init__(self,**params) self.value = value # The value of the TextArea self.pos = len(str(value)) # The position of the cursor self.vscroll = 0 # The number of lines that the TextArea is currently scrolled self.font = self.style.font # The font used for rendering the text self.cursor_w = 2 # Cursor width (NOTE: should be in a style) w,h = self.font.size("e"*size) if not self.style.height: self.style.height = h if not self.style.width: self.style.width = w ## BUG: This causes textarea to grow every time table._Table_td calculates its ## size. ## def resize(self,width=None,height=None): ## if (width != None) and (height != None): ## print 'TextArea RESIZE' ## self.rect = pygame.Rect(self.rect.x, self.rect.y, width, height) ## return self.rect.w, self.rect.h def paint(self,s): # TODO: What's up with this 20 magic number? It's the margin of the left and right sides, but I'm not sure how this should be gotten other than by trial and error. max_line_w = self.rect.w - 20 # Update the line allocation for the box's value self.doLines(max_line_w) # Make sure that the vpos and hpos of the cursor is set properly self.updateCursorPos() # Make sure that we're scrolled vertically such that the cursor is visible if (self.vscroll < 0): self.vscroll = 0 if (self.vpos < self.vscroll): self.vscroll = self.vpos elif ((self.vpos - self.vscroll + 1) * self.line_h > self.rect.h): self.vscroll = - (self.rect.h / self.line_h - self.vpos - 1) # Blit each of the lines in turn cnt = 0 for line in self.lines: line_pos = (0, (cnt - self.vscroll) * self.line_h) if (line_pos[1] >= 0) and (line_pos[1] < self.rect.h): s.blit( self.font.render(line, 1, self.style.color), line_pos ) cnt += 1 # If the textarea is focused, then also show the cursor if self.container.myfocus is self: r = self.getCursorRect() s.fill(self.style.color,r) # This function updates self.vpos and self.hpos based on self.pos def updateCursorPos(self): self.vpos = 0 # Reset the current line that the cursor is on self.hpos = 0 line_cnt = 0 char_cnt = 0 for line in self.lines: line_char_start = char_cnt # The number of characters at the start of the line # Keep track of the character count for words char_cnt += len(line) # If our cursor count is still less than the cursor position, then we can update our cursor line to assume that it's at least on this line if (char_cnt > self.pos): self.vpos = line_cnt self.hpos = self.pos - line_char_start break # Now that we know where our cursor is, we exit the loop line_cnt += 1 if (char_cnt <= self.pos) and (len(self.lines) > 0): self.vpos = len(self.lines) - 1 self.hpos = len(self.lines[ self.vpos ] ) # Returns a rectangle that is of the size and position of where the cursor is drawn def getCursorRect(self): lw = 0 if (len(self.lines) > 0): lw, lh = self.font.size( self.lines[ self.vpos ][ 0:self.hpos ] ) r = pygame.Rect(lw, (self.vpos - self.vscroll) * self.line_h, self.cursor_w, self.line_h) return r # This function sets the cursor position according to an x/y value (such as by from a mouse click) def setCursorByXY(self, pos): (x, y) = pos self.vpos = ((int) (y / self.line_h)) + self.vscroll if (self.vpos >= len(self.lines)): self.vpos = len(self.lines) - 1 currentLine = self.lines[ self.vpos ] for cnt in range(0, len(currentLine) ): self.hpos = cnt lw, lh = self.font.size( currentLine[ 0:self.hpos + 1 ] ) if (lw > x): break lw, lh = self.font.size( currentLine ) if (lw < x): self.hpos = len(currentLine) self.setCursorByHVPos() # This function sets the cursor position by the horizontal/vertical cursor position. def setCursorByHVPos(self): line_cnt = 0 char_cnt = 0 for line in self.lines: line_char_start = char_cnt # The number of characters at the start of the line # Keep track of the character count for words char_cnt += len(line) # If we're on the proper line if (line_cnt == self.vpos): # Make sure that we're not trying to go over the edge of the current line if ( self.hpos > len(line) ): self.hpos = len(line) - 1 # Set the cursor position self.pos = line_char_start + self.hpos break # Now that we've set our cursor position, we exit the loop line_cnt += 1 # Splits up the text found in the control's value, and assigns it into the lines array def doLines(self, max_line_w): self.line_h = 10 self.lines = [] # Create an empty starter list to start things out. inx = 0 line_start = 0 while inx >= 0: # Find the next breakable whitespace # HACK: Find a better way to do this to include tabs and system characters and whatnot. prev_word_start = inx # Store the previous whitespace spc_inx = self.value.find(' ', inx+1) nl_inx = self.value.find('\n', inx+1) if (min(spc_inx, nl_inx) == -1): inx = max(spc_inx, nl_inx) else: inx = min(spc_inx, nl_inx) # Measure the current line lw, self.line_h = self.font.size( self.value[ line_start : inx ] ) # If we exceeded the max line width, then create a new line if (lw > max_line_w): #Fall back to the previous word start self.lines.append(self.value[ line_start : prev_word_start + 1 ]) line_start = prev_word_start + 1 # TODO: Check for extra-long words here that exceed the length of a line, to wrap mid-word # If we reached the end of our text if (inx < 0): # Then make sure we added the last of the line if (line_start < len( self.value ) ): self.lines.append( self.value[ line_start : len( self.value ) ] ) else: self.lines.append('') # If we reached a hard line break elif (self.value[inx] == "\n"): # Then make a line break here as well. newline = self.value[ line_start : inx + 1 ] newline = newline.replace("\n", " ") # HACK: We know we have a newline character, which doesn't print nicely, so make it into a space. Comment this out to see what I mean. self.lines.append( newline ) line_start = inx + 1 else: # Otherwise, we just continue progressing to the next space pass def _setvalue(self,v): self.__dict__['value'] = v self.send(CHANGE) def event(self,e): used = None if e.type == KEYDOWN: used = True if e.key == K_BACKSPACE: if self.pos: self._setvalue(self.value[:self.pos-1] + self.value[self.pos:]) self.pos -= 1 elif e.key == K_DELETE: if len(self.value) > self.pos: self._setvalue(self.value[:self.pos] + self.value[self.pos+1:]) elif e.key == K_HOME: # Find the previous newline newPos = self.value.rfind('\n', 0, self.pos) if (newPos >= 0): self.pos = newPos elif e.key == K_END: # Find the previous newline newPos = self.value.find('\n', self.pos, len(self.value) ) if (newPos >= 0): self.pos = newPos elif e.key == K_LEFT: if self.pos > 0: self.pos -= 1 # used = True elif e.key == K_RIGHT: if self.pos < len(self.value): self.pos += 1 # used = True elif e.key == K_UP: self.vpos -= 1 self.setCursorByHVPos() elif e.key == K_DOWN: self.vpos += 1 self.setCursorByHVPos() # The following return/tab keys are standard for PGU widgets, but I took them out here to facilitate multi-line text editing # elif e.key == K_RETURN: # self.next() # elif e.key == K_TAB: # pass else: #c = str(e.unicode) used = None try: if (e.key == K_RETURN): c = "\n" elif (e.key == K_TAB): c = " " else: c = (e.unicode).encode('latin-1') if c: used = True self._setvalue(self.value[:self.pos] + c + self.value[self.pos:]) self.pos += len(c) except: #ignore weird characters pass self.repaint() elif e.type == MOUSEBUTTONDOWN: self.setCursorByXY(e.pos) self.repaint() elif e.type == FOCUS: self.repaint() elif e.type == BLUR: self.repaint() self.pcls = "" if self.container.myfocus is self: self.pcls = "focus" return used def __setattr__(self,k,v): if k == 'value': if v == None: v = '' v = str(v) self.pos = len(v) _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint() # The first version of this code was done by Clint Herron, and is a modified version of input.py (by Phil Hassey). # It is under the same license as the rest of the PGU library. pybox2d-2.3.2/examples/pgu/gui/theme.py000066400000000000000000000402511276457661000177760ustar00rootroot00000000000000# theme.py """ """ import os, re import pygame from .const import * from . import widget from . import surface from .basic import parse_color, is_color __file__ = os.path.abspath(__file__) def _list_themes(dir): d = {} for entry in os.listdir(dir): if os.path.exists(os.path.join(dir, entry, 'config.txt')): d[entry] = os.path.join(dir, entry) return d class Theme: """Theme interface. If you wish to create your own theme, create a class with this interface, and pass it to gui.App via gui.App(theme=MyTheme()). """ def __init__(self,dirs='default'): """Theme constructor. Keyword arguments: dirs -- Name of the theme dir to load a theme from. May be an absolute path to a theme, if pgu is not installed, or if you created your own theme. May include several dirs in a list if data is spread across several themes. Example: theme = gui.Theme("default") theme = gui.Theme(["mytheme","mytheme2"]) """ self.config = {} self._loaded = [] self.cache = {} self._preload(dirs) pygame.font.init() def _preload(self,ds): if not isinstance(ds, list): ds = [ds] for d in ds: if d not in self._loaded: self._load(d) self._loaded.append(d) def _load(self, name): #theme_dir = themes[name] #try to load the local dir, or absolute path dnames = [name] #if the package isn't installed and people are just #trying out the scripts or examples dnames.append(os.path.join(os.path.dirname(__file__),"..","..","data","themes",name)) #if the package is installed, and the package is installed #in /usr/lib/python2.3/site-packages/pgu/ #or c:\python23\lib\site-packages\pgu\ #the data is in ... lib/../share/ ... dnames.append(os.path.join(os.path.dirname(__file__),"..","..","..","..","share","pgu","themes",name)) dnames.append(os.path.join(os.path.dirname(__file__),"..","..","..","..","..","share","pgu","themes",name)) dnames.append(os.path.join(os.path.dirname(__file__),"..","..","share","pgu","themes",name)) for dname in dnames: if os.path.isdir(dname): break if not os.path.isdir(dname): raise Exception('could not find theme '+name) fname = os.path.join(dname,"config.txt") if os.path.isfile(fname): try: f = open(fname) for line in f.readlines(): args = line.strip().split() if len(args) < 3: continue pcls = "" (cls, attr, vals) = (args[0], args[1], args[2:]) if (":" in cls): (cls, pcls) = cls.split(":") self.config[cls, pcls, attr] = (dname, vals) finally: f.close() fname = os.path.join(dname,"style.ini") if os.path.isfile(fname): import ConfigParser cfg = ConfigParser.ConfigParser() f = open(fname,'r') cfg.readfp(f) for section in cfg.sections(): cls = section pcls = '' if cls.find(":")>=0: cls,pcls = cls.split(":") for attr in cfg.options(section): vals = cfg.get(section,attr).strip().split() self.config[cls,pcls,attr] = (dname, vals) image_extensions = (".gif", ".jpg", ".bmp", ".png", ".tga") def _get(self, cls, pcls, attr): key = (cls, pcls, attr) if not key in self.config: return if key in self.cache: # This property is already in the cache return self.cache[key] (dname, vals) = self.config[key] if (os.path.splitext(vals[0].lower())[1] in self.image_extensions): # This is an image attribute v = pygame.image.load(os.path.join(dname, vals[0])) elif (attr == "color" or attr == "background"): # This is a color value v = parse_color(vals[0]) elif (attr == "font"): # This is a font value name = vals[0] size = int(vals[1]) if (name.endswith(".ttf")): # Load the font from a file v = pygame.font.Font(os.path.join(dname, name), size) else: # Must be a system font v = pygame.font.SysFont(name, size) else: try: v = int(vals[0]) except: v = vals[0] self.cache[key] = v return v def get(self,cls,pcls,attr): """Interface method -- get the value of a style attribute. Arguments: cls -- class, for example "checkbox", "button", etc. pcls -- pseudo class, for example "hover", "down", etc. attr -- attribute, for example "image", "background", "font", "color", etc. This method is called from [[gui-style]] """ if not self._loaded: # Load the default theme self._preload("default") o = (cls, pcls, attr) #if o in self.cache: # return self.cache[o] v = self._get(cls, pcls, attr) if v: #self.cache[o] = v return v v = self._get(cls, "", attr) if v: #self.cache[o] = v return v v = self._get("default", "", attr) if v: #self.cache[o] = v return v self.cache[o] = 0 return 0 def box(self,w,s): style = w.style c = (0,0,0) if style.border_color != 0: c = style.border_color w,h = s.get_width(),s.get_height() s.fill(c,(0,0,w,style.border_top)) s.fill(c,(0,h-style.border_bottom,w,style.border_bottom)) s.fill(c,(0,0,style.border_left,h)) s.fill(c,(w-style.border_right,0,style.border_right,h)) def getspacing(self,w): # return the top, right, bottom, left spacing around the widget if not hasattr(w,'_spacing'): #HACK: assume spacing doesn't change re pcls s = w.style xt = s.margin_top+s.border_top+s.padding_top xr = s.padding_right+s.border_right+s.margin_right xb = s.padding_bottom+s.border_bottom+s.margin_bottom xl = s.margin_left+s.border_left+s.padding_left w._spacing = xt,xr,xb,xl return w._spacing def resize(self,w,m): # Returns the rectangle expanded in each direction def expand_rect(rect, left, top, right, bottom): return pygame.Rect(rect.x - left, rect.y - top, rect.w + left + right, rect.h + top + bottom) def func(width=None,height=None): s = w.style pt,pr,pb,pl = (s.padding_top,s.padding_right, s.padding_bottom,s.padding_left) bt,br,bb,bl = (s.border_top,s.border_right, s.border_bottom,s.border_left) mt,mr,mb,ml = (s.margin_top,s.margin_right, s.margin_bottom,s.margin_left) # Calculate the total space on each side top = pt+bt+mt right = pr+br+mr bottom = pb+bb+mb left = pl+bl+ml ttw = left+right tth = top+bottom ww,hh = None,None if width != None: ww = width-ttw if height != None: hh = height-tth ww,hh = m(ww,hh) if width == None: width = ww if height == None: height = hh #if the widget hasn't respected the style.width, #style height, we'll add in the space for it... width = max(width-ttw, ww, w.style.width) height = max(height-tth, hh, w.style.height) #width = max(ww,w.style.width-tw) #height = max(hh,w.style.height-th) r = pygame.Rect(left,top,width,height) w._rect_padding = expand_rect(r, pl, pt, pr, pb) w._rect_border = expand_rect(w._rect_padding, bl, bt, br, bb) w._rect_margin = expand_rect(w._rect_border, ml, mt, mr, mb) # align it within it's zone of power. rect = pygame.Rect(left, top, ww, hh) dx = width-rect.w dy = height-rect.h rect.x += (w.style.align+1)*dx/2 rect.y += (w.style.valign+1)*dy/2 w._rect_content = rect return (w._rect_margin.w, w._rect_margin.h) return func def paint(self,w,m): def func(s): # if w.disabled: # if not hasattr(w,'_disabled_bkgr'): # w._disabled_bkgr = s.convert() # orig = s # s = w._disabled_bkgr.convert() # if not hasattr(w,'_theme_paint_bkgr'): # w._theme_paint_bkgr = s.convert() # else: # s.blit(w._theme_paint_bkgr,(0,0)) # # if w.disabled: # orig = s # s = w._theme_paint_bkgr.convert() if w.disabled: if (not (hasattr(w,'_theme_bkgr') and w._theme_bkgr.get_width() == s.get_width() and w._theme_bkgr.get_height() == s.get_height())): w._theme_bkgr = s.copy() orig = s s = w._theme_bkgr s.fill((0,0,0,0)) s.blit(orig,(0,0)) if w.background: w.background.paint(surface.subsurface(s,w._rect_border)) self.box(w,surface.subsurface(s,w._rect_border)) r = m(surface.subsurface(s,w._rect_content)) if w.disabled: s.set_alpha(128) orig.blit(s,(0,0)) # if w.disabled: # orig.blit(w._disabled_bkgr,(0,0)) # s.set_alpha(128) # orig.blit(s,(0,0)) w._painted = True return r return func def event(self,w,m): def func(e): rect = w._rect_content if (not rect): # This should never be the case, but it sometimes happens that _rect_content isn't # set before a mouse event is received. In this case we'll ignore the event. return m(e) if e.type == MOUSEBUTTONUP or e.type == MOUSEBUTTONDOWN: sub = pygame.event.Event(e.type,{ 'button':e.button, 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y)}) elif e.type == CLICK: sub = pygame.event.Event(e.type,{ 'button':e.button, 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y)}) elif e.type == MOUSEMOTION: sub = pygame.event.Event(e.type,{ 'buttons':e.buttons, 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y), 'rel':e.rel}) else: sub = e return m(sub) return func def update(self,w,m): def func(s): if w.disabled: return [] r = m(surface.subsurface(s,w._rect_content)) if type(r) == list: dx,dy = w._rect_content.topleft for rr in r: rr.x,rr.y = rr.x+dx,rr.y+dy return r return func def open(self,w,m): def func(widget=None,x=None,y=None): if not hasattr(w,'_rect_content'): # HACK: so that container.open won't resize again! w.rect.w,w.rect.h = w.resize() rect = w._rect_content ##print w.__class__.__name__, rect if x != None: x += rect.x if y != None: y += rect.y return m(widget,x,y) return func #def open(self,w,m): # def func(widget=None): # return m(widget) # return func def decorate(self,widget,level): """Interface method -- decorate a widget. The theme system is given the opportunity to decorate a widget methods at the end of the Widget initializer. Arguments: widget -- the widget to be decorated level -- the amount of decoration to do, False for none, True for normal amount, 'app' for special treatment of App objects. """ w = widget if level == False: return if type(w.style.background) != int: w.background = Background(w,self) if level == 'app': return for k,v in list(w.style.__dict__.items()): if k in ('border','margin','padding'): for kk in ('top','bottom','left','right'): setattr(w.style,'%s_%s'%(k,kk),v) w.paint = self.paint(w,w.paint) w.event = self.event(w,w.event) w.update = self.update(w,w.update) w.resize = self.resize(w,w.resize) w.open = self.open(w,w.open) def render(self,s,box,r): """Interface method - render a special widget feature. Arguments: s -- a pygame surface box -- box data, a value returned from Theme.get, typically a surface r -- pygame.Rect with the size that the box data should be rendered """ if box == 0: return if is_color(box): s.fill(box,r) return x,y,w,h=r.x,r.y,r.w,r.h ww,hh=int(box.get_width()/3),int(box.get_height()/3) xx,yy=x+w,y+h src = pygame.rect.Rect(0,0,ww,hh) dest = pygame.rect.Rect(0,0,ww,hh) s.set_clip(pygame.Rect(x+ww,y+hh,w-ww*2,h-hh*2)) src.x,src.y = ww,hh for dest.y in range(y+hh,yy-hh,hh): for dest.x in range(x+ww,xx-ww,ww): s.blit(box,dest,src) s.set_clip(pygame.Rect(x+ww,y,w-ww*3,hh)) src.x,src.y,dest.y = ww,0,y for dest.x in range(x+ww,xx-ww*2,ww): s.blit(box,dest,src) dest.x = xx-ww*2 s.set_clip(pygame.Rect(x+ww,y,w-ww*2,hh)) s.blit(box,dest,src) s.set_clip(pygame.Rect(x+ww,yy-hh,w-ww*3,hh)) src.x,src.y,dest.y = ww,hh*2,yy-hh for dest.x in range(x+ww,xx-ww*2,ww): s.blit(box,dest,src) dest.x = xx-ww*2 s.set_clip(pygame.Rect(x+ww,yy-hh,w-ww*2,hh)) s.blit(box,dest,src) s.set_clip(pygame.Rect(x,y+hh,xx,h-hh*3)) src.y,src.x,dest.x = hh,0,x for dest.y in range(y+hh,yy-hh*2,hh): s.blit(box,dest,src) dest.y = yy-hh*2 s.set_clip(pygame.Rect(x,y+hh,xx,h-hh*2)) s.blit(box,dest,src) s.set_clip(pygame.Rect(xx-ww,y+hh,xx,h-hh*3)) src.y,src.x,dest.x=hh,ww*2,xx-ww for dest.y in range(y+hh,yy-hh*2,hh): s.blit(box,dest,src) dest.y = yy-hh*2 s.set_clip(pygame.Rect(xx-ww,y+hh,xx,h-hh*2)) s.blit(box,dest,src) s.set_clip(s.get_rect()) src.x,src.y,dest.x,dest.y = 0,0,x,y s.blit(box,dest,src) src.x,src.y,dest.x,dest.y = ww*2,0,xx-ww,y s.blit(box,dest,src) src.x,src.y,dest.x,dest.y = 0,hh*2,x,yy-hh s.blit(box,dest,src) src.x,src.y,dest.x,dest.y = ww*2,hh*2,xx-ww,yy-hh s.blit(box,dest,src) class Background(widget.Widget): def __init__(self,value,theme,**params): params['decorate'] = False widget.Widget.__init__(self,**params) self.value = value self.theme = theme def paint(self,s): r = pygame.Rect(0,0,s.get_width(),s.get_height()) v = self.value.style.background if is_color(v): s.fill(v) else: self.theme.render(s,v,r) pybox2d-2.3.2/examples/pgu/gui/widget.py000066400000000000000000000262521276457661000201640ustar00rootroot00000000000000"""This modules defines the Widget class, which is the base of the PGU widget hierarchy.""" import pygame from . import pguglobals from . import style class SignalCallback: # The function to call func = None # The parameters to pass to the function (as a list) params = None class Widget(object): """Base class for all PGU graphical objects. Example - Creating your own Widget: class Draw(gui.Widget): def paint(self,s): # Paint the pygame.Surface return def update(self,s): # Update the pygame.Surface and return the update rects return [pygame.Rect(0,0,self.rect.w,self.rect.h)] def event(self,e): # Handle the pygame.Event return def resize(self,width=None,height=None): # Return the width and height of this widget return 256,256 """ # The name of the widget (or None if not defined) name = None # The container this widget belongs to container = None # Whether this widget has been painted yet _painted = False # The widget used to paint the background background = None # ... _rect_content = None # A dictionary of signal callbacks, hashed by signal ID connects = None def __init__(self, **params): """Create a new Widget instance given the style parameters. Keyword arguments: decorate -- whether to call theme.decorate(self) to allow the theme a chance to decorate the widget. (default is true) style -- a dict of style parameters. x, y -- position parameters width, height -- size parameters align, valign -- alignment parameters, passed along to style font -- the font to use with this widget color -- the color property, if applicable background -- the widget used to paint the background cls -- class name as used by Theme name -- name of widget as used by Form. If set, will call form.add(self,name) to add the widget to the most recently created Form. focusable -- True if this widget can receive focus via Tab, etc. (default is True) disabled -- True of this widget is disabled (defaults is False) value -- initial value """ #object.Object.__init__(self) self.connects = {} params.setdefault('decorate',True) params.setdefault('style',{}) params.setdefault('focusable',True) params.setdefault('disabled',False) self.focusable = params['focusable'] self.disabled = params['disabled'] self.rect = pygame.Rect(params.get('x',0), params.get('y',0), params.get('width',0), params.get('height',0)) s = params['style'] #some of this is a bit "theme-ish" but it is very handy, so these #things don't have to be put directly into the style. for att in ('align','valign','x','y','width','height','color','font','background'): if att in params: s[att] = params[att] self.style = style.Style(self,s) self.cls = 'default' if 'cls' in params: self.cls = params['cls'] if 'name' in params: from . import form self.name = params['name'] if form.Form.form: form.Form.form.add(self) self.form = form.Form.form if 'value' in params: self.value = params['value'] self.pcls = "" if params['decorate'] != False: if (not pguglobals.app): # TODO - fix this somehow from . import app app.App() pguglobals.app.theme.decorate(self,params['decorate']) def focus(self): """Focus this Widget.""" if self.container: if self.container.myfocus != self: ## by Gal Koren self.container.focus(self) def blur(self): """Blur this Widget.""" if self.container: self.container.blur(self) def open(self): """Open this widget as a modal dialog.""" #if getattr(self,'container',None) != None: self.container.open(self) pguglobals.app.open(self) def close(self, w=None): """Close this widget, if it is currently an open dialog.""" #if getattr(self,'container',None) != None: self.container.close(self) if (not w): w = self pguglobals.app.close(w) def is_open(self): return (self in pguglobals.app.windows) def is_hovering(self): """Returns true if the mouse is hovering over this widget.""" if self.container: return (self.container.myhover is self) return False def resize(self,width=None,height=None): """Resize this widget and all sub-widgets, returning the new size. This should be implemented by a subclass. """ return (self.style.width, self.style.height) def chsize(self): """Signal that this widget has changed its size.""" if (not self._painted): return if (not self.container): return if (pguglobals.app): pguglobals.app.chsize() def update(self,s): """Updates the surface and returns a rect list of updated areas This should be implemented by a subclass. """ return def paint(self,s): """Render this widget onto the given surface This should be implemented by a subclass. """ return def repaint(self): """Request a repaint of this Widget.""" if self.container: self.container.repaint(self) def repaintall(self): """Request a repaint of all Widgets.""" if self.container: self.container.repaintall() def reupdate(self): """Request a reupdate of this Widget.""" if self.container: self.container.reupdate(self) def next(self): """Pass focus to next Widget. Widget order determined by the order they were added to their container. """ if self.container: self.container.next(self) def previous(self): """Pass focus to previous Widget. Widget order determined by the order they were added to their container. """ if self.container: self.container.previous(self) def get_abs_rect(self): """Returns the absolute rect of this widget on the App screen.""" x, y = self.rect.x, self.rect.y cnt = self.container while cnt: x += cnt.rect.x y += cnt.rect.y if cnt._rect_content: x += cnt._rect_content.x y += cnt._rect_content.y cnt = cnt.container return pygame.Rect(x, y, self.rect.w, self.rect.h) def connect(self,code,func,*params): """Connect an event code to a callback function. Note that there may be multiple callbacks per event code. Arguments: code -- event type fnc -- callback function *values -- values to pass to callback. Please note that callbacks may also have "magicaly" parameters. Such as: _event -- receive the event _code -- receive the event code _widget -- receive the sending widget Example: def onclick(value): print 'click', value w = Button("PGU!") w.connect(gui.CLICK,onclick,'PGU Button Clicked') """ if (not code in self.connects): self.connects[code] = [] for cb in self.connects[code]: if (cb.func == func): # Already connected to this callback function return # Wrap the callback function and add it to the list cb = SignalCallback() cb.func = func cb.params = params self.connects[code].append(cb) # Remove signal handlers from the given event code. If func is specified, # only those handlers will be removed. If func is None, all handlers # will be removed. def disconnect(self, code, func=None): if (not code in self.connects): return if (not func): # Remove all signal handlers del self.connects[code] else: # Remove handlers that call 'func' n = 0 callbacks = self.connects[code] while (n < len(callbacks)): if (callbacks[n].func == func): # Remove this callback del callbacks[n] else: n += 1 def send(self,code,event=None): """Send a code, event callback trigger.""" if (not code in self.connects): return # Trigger all connected signal handlers for cb in self.connects[code]: func = cb.func values = list(cb.params) # Attempt to be compatible with previous versions of python try: code = func.__code__ except: code = func.func_code nargs = code.co_argcount names = list(code.co_varnames)[:nargs] # If the function is bound to an instance, remove the first argument name. Again # we keep compatibility with older versions of python. if (hasattr(func, "__self__") and hasattr(func.__self__, "__class__") or hasattr(func,'im_class')): names.pop(0) args = [] magic = {'_event':event,'_code':code,'_widget':self} for name in names: if name in magic.keys(): args.append(magic[name]) elif len(values): args.append(values.pop(0)) else: break args.extend(values) func(*args) def _event(self,e): if self.disabled: return self.send(e.type,e) return self.event(e) def event(self,e): """Called when an event is passed to this object. Please note that if you use an event, returning the value True will stop parent containers from also using the event. (For example, if your widget handles TABs or arrow keys, and you don't want those to also alter the focus.) This should be implemented by a subclass. """ return def get_toplevel(self): """Returns the top-level widget (usually the Desktop) by following the chain of 'container' references.""" top = self while (top.container): top = top.container return top def collidepoint(self, pos): """Test if the given point hits this widget. Over-ride this function for more advanced collision testing.""" return self.rect.collidepoint(pos) pybox2d-2.3.2/examples/pinball.py000066400000000000000000000070121276457661000167340ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2CircleShape, b2FixtureDef, b2LoopShape, b2PolygonShape, b2RevoluteJointDef, b2_pi) class Pinball (Framework): name = "Pinball" description = ('This tests bullet collision and provides an example of a gameplay scenario.\n' 'Press A to control the flippers.') bodies = [] joints = [] def __init__(self): super(Pinball, self).__init__() # The ground ground = self.world.CreateBody( shapes=b2LoopShape(vertices=[(0, -2), (8, 6), (8, 20), (-8, 20), (-8, 6)]), ) # Flippers p1, p2 = (-2, 0), (2, 0) fixture = b2FixtureDef(shape=b2PolygonShape(box=(1.75, 0.1)), density=1) flipper = {'fixtures': fixture} self.leftFlipper = self.world.CreateDynamicBody( position=p1, **flipper ) self.rightFlipper = self.world.CreateDynamicBody( position=p2, **flipper ) rjd = b2RevoluteJointDef( bodyA=ground, bodyB=self.leftFlipper, localAnchorA=p1, localAnchorB=(0, 0), enableMotor=True, enableLimit=True, maxMotorTorque=1000, motorSpeed=0, lowerAngle=-30.0 * b2_pi / 180.0, upperAngle=5.0 * b2_pi / 180.0, ) self.leftJoint = self.world.CreateJoint(rjd) rjd.motorSpeed = 0 rjd.localAnchorA = p2 rjd.bodyB = self.rightFlipper rjd.lowerAngle = -5.0 * b2_pi / 180.0 rjd.upperAngle = 30.0 * b2_pi / 180.0 self.rightJoint = self.world.CreateJoint(rjd) # Ball self.ball = self.world.CreateDynamicBody( fixtures=b2FixtureDef( shape=b2CircleShape(radius=0.2), density=1.0), bullet=True, position=(1, 15)) self.pressed = False def Keyboard(self, key): if key == Keys.K_a: self.pressed = True def KeyboardUp(self, key): if key == Keys.K_a: self.pressed = False def Step(self, settings): if self.pressed: self.leftJoint.motorSpeed = 20 self.rightJoint.motorSpeed = -20 else: self.leftJoint.motorSpeed = -10 self.rightJoint.motorSpeed = 10 super(Pinball, self).Step(settings) if __name__ == "__main__": main(Pinball) pybox2d-2.3.2/examples/pulley.py000066400000000000000000000046211276457661000166300ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D.b2 import (edgeShape, circleShape, fixtureDef, polygonShape) class Pulley (Framework): name = "Pulley" def __init__(self): super(Pulley, self).__init__() y, L, a, b = 16.0, 12.0, 1.0, 2.0 # The ground ground = self.world.CreateStaticBody( shapes=[edgeShape(vertices=[(-40, 0), (40, 0)]), circleShape(radius=2, pos=(-10.0, y + b + L)), circleShape(radius=2, pos=(10.0, y + b + L))] ) bodyA = self.world.CreateDynamicBody( position=(-10, y), fixtures=fixtureDef(shape=polygonShape(box=(a, b)), density=5.0), ) bodyB = self.world.CreateDynamicBody( position=(10, y), fixtures=fixtureDef(shape=polygonShape(box=(a, b)), density=5.0), ) self.pulley = self.world.CreatePulleyJoint( bodyA=bodyA, bodyB=bodyB, anchorA=(-10.0, y + b), anchorB=(10.0, y + b), groundAnchorA=(-10.0, y + b + L), groundAnchorB=(10.0, y + b + L), ratio=1.5, ) def Step(self, settings): super(Pulley, self).Step(settings) ratio = self.pulley.ratio L = self.pulley.length1 + self.pulley.length2 * ratio self.Print('L1 + %4.2f * L2 = %4.2f' % (ratio, L)) if __name__ == "__main__": main(Pulley) pybox2d-2.3.2/examples/pyramid.py000066400000000000000000000037151276457661000167660ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2EdgeShape, b2FixtureDef, b2PolygonShape, b2Vec2) class Pyramid (Framework): name = "Pyramid" def __init__(self): super(Pyramid, self).__init__() # The ground ground = self.world.CreateStaticBody( shapes=b2EdgeShape(vertices=[(-40, 0), (40, 0)]) ) box_half_size = (0.5, 0.5) box_density = 5.0 box_rows = 20 x = b2Vec2(-7, 0.75) deltaX = (0.5625, 1.25) deltaY = (1.125, 0) for i in range(box_rows): y = x.copy() for j in range(i, box_rows): self.world.CreateDynamicBody( position=y, fixtures=b2FixtureDef( shape=b2PolygonShape(box=box_half_size), density=box_density) ) y += deltaY x += deltaX if __name__ == "__main__": main(Pyramid) pybox2d-2.3.2/examples/raycast.py000066400000000000000000000165401276457661000167670ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from random import random from math import sqrt, sin, cos from Box2D import (b2BodyDef, b2CircleShape, b2Color, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2RayCastCallback, b2Vec2, b2_dynamicBody, b2_pi) class RayCastClosestCallback(b2RayCastCallback): """This callback finds the closest hit""" def __repr__(self): return 'Closest hit' def __init__(self, **kwargs): b2RayCastCallback.__init__(self, **kwargs) self.fixture = None self.hit = False def ReportFixture(self, fixture, point, normal, fraction): ''' Called for each fixture found in the query. You control how the ray proceeds by returning a float that indicates the fractional length of the ray. By returning 0, you set the ray length to zero. By returning the current fraction, you proceed to find the closest point. By returning 1, you continue with the original ray clipping. By returning -1, you will filter out the current fixture (the ray will not hit it). ''' self.hit = True self.fixture = fixture self.point = b2Vec2(point) self.normal = b2Vec2(normal) # NOTE: You will get this error: # "TypeError: Swig director type mismatch in output value of # type 'float32'" # without returning a value return fraction class RayCastAnyCallback(b2RayCastCallback): """This callback finds any hit""" def __repr__(self): return 'Any hit' def __init__(self, **kwargs): b2RayCastCallback.__init__(self, **kwargs) self.fixture = None self.hit = False def ReportFixture(self, fixture, point, normal, fraction): self.hit = True self.fixture = fixture self.point = b2Vec2(point) self.normal = b2Vec2(normal) return 0.0 class RayCastMultipleCallback(b2RayCastCallback): """This raycast collects multiple hits.""" def __repr__(self): return 'Multiple hits' def __init__(self, **kwargs): b2RayCastCallback.__init__(self, **kwargs) self.fixture = None self.hit = False self.points = [] self.normals = [] def ReportFixture(self, fixture, point, normal, fraction): self.hit = True self.fixture = fixture self.points.append(b2Vec2(point)) self.normals.append(b2Vec2(normal)) return 1.0 class Raycast (Framework): name = "Raycast" description = "Press 1-5 to drop stuff, d to delete, m to switch callback modes" p1_color = b2Color(0.4, 0.9, 0.4) s1_color = b2Color(0.8, 0.8, 0.8) s2_color = b2Color(0.9, 0.9, 0.4) def __init__(self): super(Raycast, self).__init__() self.world.gravity = (0, 0) # The ground ground = self.world.CreateBody( shapes=b2EdgeShape(vertices=[(-40, 0), (40, 0)]) ) # The various shapes w = 1.0 b = w / (2.0 + sqrt(2.0)) s = sqrt(2.0) * b self.shapes = [ b2PolygonShape(vertices=[(-0.5, 0), (0.5, 0), (0, 1.5)]), b2PolygonShape(vertices=[(-0.1, 0), (0.1, 0), (0, 1.5)]), b2PolygonShape( vertices=[(0.5 * s, 0), (0.5 * w, b), (0.5 * w, b + s), (0.5 * s, w), (-0.5 * s, w), (-0.5 * w, b + s), (-0.5 * w, b), (-0.5 * s, 0.0)] ), b2PolygonShape(box=(0.5, 0.5)), b2CircleShape(radius=0.5), ] self.angle = 0 self.callbacks = [RayCastClosestCallback, RayCastAnyCallback, RayCastMultipleCallback] self.callback_class = self.callbacks[0] def CreateShape(self, shapeindex): try: shape = self.shapes[shapeindex] except IndexError: return pos = (10.0 * (2.0 * random() - 1.0), 10.0 * (2.0 * random())) defn = b2BodyDef( type=b2_dynamicBody, fixtures=b2FixtureDef(shape=shape, friction=0.3), position=pos, angle=(b2_pi * (2.0 * random() - 1.0)), ) if isinstance(shape, b2CircleShape): defn.angularDamping = 0.02 self.world.CreateBody(defn) def DestroyBody(self): for body in self.world.bodies: if not self.world.locked: self.world.DestroyBody(body) break def Keyboard(self, key): if key in (Keys.K_1, Keys.K_2, Keys.K_3, Keys.K_4, Keys.K_5): self.CreateShape(key - Keys.K_1) elif key == Keys.K_d: self.DestroyBody() elif key == Keys.K_m: idx = ((self.callbacks.index(self.callback_class) + 1) % len(self.callbacks)) self.callback_class = self.callbacks[idx] def Step(self, settings): super(Raycast, self).Step(settings) def draw_hit(cb_point, cb_normal): cb_point = self.renderer.to_screen(cb_point) head = b2Vec2(cb_point) + 0.5 * cb_normal cb_normal = self.renderer.to_screen(cb_normal) self.renderer.DrawPoint(cb_point, 5.0, self.p1_color) self.renderer.DrawSegment(point1, cb_point, self.s1_color) self.renderer.DrawSegment(cb_point, head, self.s2_color) # Set up the raycast line length = 11 point1 = b2Vec2(0, 10) d = (length * cos(self.angle), length * sin(self.angle)) point2 = point1 + d callback = self.callback_class() self.world.RayCast(callback, point1, point2) # The callback has been called by this point, and if a fixture was hit it will have been # set to callback.fixture. point1 = self.renderer.to_screen(point1) point2 = self.renderer.to_screen(point2) if callback.hit: if hasattr(callback, 'points'): for point, normal in zip(callback.points, callback.normals): draw_hit(point, normal) else: draw_hit(callback.point, callback.normal) else: self.renderer.DrawSegment(point1, point2, self.s1_color) self.Print("Callback: %s" % callback) if callback.hit: self.Print("Hit") if not settings.pause or settings.singleStep: self.angle += 0.25 * b2_pi / 180 if __name__ == "__main__": main(Raycast) pybox2d-2.3.2/examples/restitution.py000066400000000000000000000035651276457661000177150ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef) class Restitution (Framework): name = "Restitution example" description = "Note the difference in bounce height of the circles" def __init__(self): super(Restitution, self).__init__() # The ground ground = self.world.CreateStaticBody( shapes=b2EdgeShape(vertices=[(-20, 0), (20, 0)]) ) radius = 1.0 density = 1.0 # The bodies for i, restitution in enumerate([0.0, 0.1, 0.3, 0.5, 0.75, 0.9, 1.0]): self.world.CreateDynamicBody( position=(-10 + 3.0 * i, 20), fixtures=b2FixtureDef( shape=b2CircleShape(radius=radius), density=density, restitution=restitution) ) if __name__ == "__main__": main(Restitution) pybox2d-2.3.2/examples/rope.py000066400000000000000000000073341276457661000162670ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2EdgeShape, b2FixtureDef, b2PolygonShape, b2RopeJointDef) # From the original C++ testbed example: # "This test shows how a rope joint can be used to stabilize a chain of bodies # with a heavy payload. Notice that the rope joint just prevents excessive # stretching and has no other effect. By disabling the rope joint you can see # that the Box2D solver has trouble supporting heavy bodies with light bodies. # Try playing around with the densities, time step, and iterations to see how # they affect stability. This test also shows how to use contact filtering. # Filtering is configured so that the payload does not collide with the # chain." class Rope (Framework): name = "Rope Joint Test" description = "Press j to toggle the rope joint." def __init__(self): super(Rope, self).__init__() # The ground ground = self.world.CreateBody( shapes=b2EdgeShape(vertices=[(-40, 0), (40, 0)])) shape = b2PolygonShape(box=(0.5, 0.125)) fd = b2FixtureDef( shape=shape, friction=0.2, density=20, categoryBits=0x0001, maskBits=(0xFFFF & ~0x0002), ) N = 10 y = 15.0 prevBody = ground for i in range(N): if i < N - 1: body = self.world.CreateDynamicBody( position=(0.5 + i, y), fixtures=fd, ) else: shape.box = (1.5, 1.5) fd.density = 100 fd.categoryBits = 0x0002 body = self.world.CreateDynamicBody( position=(i, y), fixtures=fd, angularDamping=0.4, ) self.world.CreateRevoluteJoint( bodyA=prevBody, bodyB=body, anchor=(i, y), collideConnected=False, ) prevBody = body extraLength = 0.01 self.rd = rd = b2RopeJointDef( bodyA=ground, bodyB=body, maxLength=N - 1.0 + extraLength, localAnchorA=(0, y), localAnchorB=(0, 0) ) self.rope = self.world.CreateJoint(rd) def Step(self, settings): super(Rope, self).Step(settings) if self.rope: self.Print('Rope ON') else: self.Print('Rope OFF') def Keyboard(self, key): if key == Keys.K_j: if self.rope: self.world.DestroyJoint(self.rope) self.rope = None else: self.rope = self.world.CreateJoint(self.rd) if __name__ == "__main__": main(Rope) pybox2d-2.3.2/examples/settings.py000066400000000000000000000101441276457661000171530ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. class fwSettings(object): # The default backend to use in (can be: pyglet, pygame, etc.) backend = 'pygame' # Physics options hz = 60.0 velocityIterations = 8 positionIterations = 3 # Makes physics results more accurate (see Box2D wiki) enableWarmStarting = True enableContinuous = True # Calculate time of impact enableSubStepping = False # Drawing drawStats = True drawShapes = True drawJoints = True drawCoreShapes = False drawAABBs = False drawOBBs = False drawPairs = False drawContactPoints = False maxContactPoints = 100 drawContactNormals = False drawFPS = True drawMenu = True # toggle by pressing F1 drawCOMs = False # Centers of mass pointSize = 2.5 # pixel radius for drawing points # Miscellaneous testbed options pause = False singleStep = False # run the test's initialization without graphics, and then quit (for # testing) onlyInit = False # text variable checkboxes = (("Warm Starting", "enableWarmStarting"), ("Time of Impact", "enableContinuous"), ("Sub-Stepping", "enableSubStepping"), ("Draw", None), ("Shapes", "drawShapes"), ("Joints", "drawJoints"), ("AABBs", "drawAABBs"), ("Pairs", "drawPairs"), ("Contact Points", "drawContactPoints"), ("Contact Normals", "drawContactNormals"), ("Center of Masses", "drawCOMs"), ("Statistics", "drawStats"), ("FPS", "drawFPS"), ("Control", None), ("Pause", "pause"), ("Single Step", "singleStep")) sliders = [ {'name': 'hz', 'text': 'Hertz', 'min': 5, 'max': 200}, {'name': 'positionIterations', 'text': 'Pos Iters', 'min': 0, 'max': 100}, {'name': 'velocityIterations', 'text': 'Vel Iters', 'min': 1, 'max': 500}, ] from optparse import OptionParser parser = OptionParser() list_options = [i for i in dir(fwSettings) if not i.startswith('_')] for opt_name in list_options: value = getattr(fwSettings, opt_name) if isinstance(value, bool): if value: parser.add_option('', '--no-' + opt_name, dest=opt_name, default=value, action='store_' + str(not value).lower(), help="don't " + opt_name) else: parser.add_option('', '--' + opt_name, dest=opt_name, default=value, action='store_' + str(not value).lower(), help=opt_name) else: if isinstance(value, int): opttype = 'int' elif isinstance(value, float): opttype = 'float' else: opttype = 'string' parser.add_option('', '--' + opt_name, dest=opt_name, default=value, type=opttype, help='sets the %s option' % (opt_name,)) fwSettings, args = parser.parse_args() pybox2d-2.3.2/examples/simple/000077500000000000000000000000001276457661000162325ustar00rootroot00000000000000pybox2d-2.3.2/examples/simple/simple_01.py000066400000000000000000000066361276457661000204100ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ An attempt at some simple, self-contained pygame-based examples. Example 01 In short: One static body: a big polygon to represent the ground One dynamic body: a rotated big polygon And some drawing code to get you going. kne """ import pygame from pygame.locals import (QUIT, KEYDOWN, K_ESCAPE) import Box2D # The main library # Box2D.b2 maps Box2D.b2Vec2 to vec2 (and so on) from Box2D.b2 import (world, polygonShape, staticBody, dynamicBody) # --- constants --- # Box2D deals with meters, but we want to display pixels, # so define a conversion factor: PPM = 20.0 # pixels per meter TARGET_FPS = 60 TIME_STEP = 1.0 / TARGET_FPS SCREEN_WIDTH, SCREEN_HEIGHT = 640, 480 # --- pygame setup --- screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), 0, 32) pygame.display.set_caption('Simple pygame example') clock = pygame.time.Clock() # --- pybox2d world setup --- # Create the world world = world(gravity=(0, -10), doSleep=True) # And a static body to hold the ground shape ground_body = world.CreateStaticBody( position=(0, 1), shapes=polygonShape(box=(50, 5)), ) # Create a dynamic body dynamic_body = world.CreateDynamicBody(position=(10, 15), angle=15) # And add a box fixture onto it (with a nonzero density, so it will move) box = dynamic_body.CreatePolygonFixture(box=(2, 1), density=1, friction=0.3) colors = { staticBody: (255, 255, 255, 255), dynamicBody: (127, 127, 127, 255), } # --- main game loop --- running = True while running: # Check the event queue for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): # The user closed the window or pressed escape running = False screen.fill((0, 0, 0, 0)) # Draw the world for body in (ground_body, dynamic_body): # or: world.bodies # The body gives us the position and angle of its shapes for fixture in body.fixtures: # The fixture holds information like density and friction, # and also the shape. shape = fixture.shape # Naively assume that this is a polygon shape. (not good normally!) # We take the body's transform and multiply it with each # vertex, and then convert from meters to pixels with the scale # factor. vertices = [(body.transform * v) * PPM for v in shape.vertices] # But wait! It's upside-down! Pygame and Box2D orient their # axes in different ways. Box2D is just like how you learned # in high school, with positive x and y directions going # right and up. Pygame, on the other hand, increases in the # right and downward directions. This means we must flip # the y components. vertices = [(v[0], SCREEN_HEIGHT - v[1]) for v in vertices] pygame.draw.polygon(screen, colors[body.type], vertices) # Make Box2D simulate the physics of our world for one step. # Instruct the world to perform a single step of simulation. It is # generally best to keep the time step and iterations fixed. # See the manual (Section "Simulating the World") for further discussion # on these parameters and their implications. world.Step(TIME_STEP, 10, 10) # Flip the screen and try to keep at the target FPS pygame.display.flip() clock.tick(TARGET_FPS) pygame.quit() print('Done!') pybox2d-2.3.2/examples/simple/simple_02.py000066400000000000000000000057671276457661000204150ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ An attempt at some simple, self-contained pygame-based examples. Example 02 In short: One static body: + One fixture: big polygon to represent the ground Two dynamic bodies: + One fixture: a polygon + One fixture: a circle And some drawing code that extends the shape classes. kne """ import pygame from pygame.locals import (QUIT, KEYDOWN, K_ESCAPE) import Box2D # The main library # Box2D.b2 maps Box2D.b2Vec2 to vec2 (and so on) from Box2D.b2 import (world, polygonShape, circleShape, staticBody, dynamicBody) # --- constants --- # Box2D deals with meters, but we want to display pixels, # so define a conversion factor: PPM = 20.0 # pixels per meter TARGET_FPS = 60 TIME_STEP = 1.0 / TARGET_FPS SCREEN_WIDTH, SCREEN_HEIGHT = 640, 480 # --- pygame setup --- screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), 0, 32) pygame.display.set_caption('Simple pygame example') clock = pygame.time.Clock() # --- pybox2d world setup --- # Create the world world = world(gravity=(0, -10), doSleep=True) # And a static body to hold the ground shape ground_body = world.CreateStaticBody( position=(0, 0), shapes=polygonShape(box=(50, 1)), ) # Create a couple dynamic bodies body = world.CreateDynamicBody(position=(20, 45)) circle = body.CreateCircleFixture(radius=0.5, density=1, friction=0.3) body = world.CreateDynamicBody(position=(30, 45), angle=15) box = body.CreatePolygonFixture(box=(2, 1), density=1, friction=0.3) colors = { staticBody: (255, 255, 255, 255), dynamicBody: (127, 127, 127, 255), } # Let's play with extending the shape classes to draw for us. def my_draw_polygon(polygon, body, fixture): vertices = [(body.transform * v) * PPM for v in polygon.vertices] vertices = [(v[0], SCREEN_HEIGHT - v[1]) for v in vertices] pygame.draw.polygon(screen, colors[body.type], vertices) polygonShape.draw = my_draw_polygon def my_draw_circle(circle, body, fixture): position = body.transform * circle.pos * PPM position = (position[0], SCREEN_HEIGHT - position[1]) pygame.draw.circle(screen, colors[body.type], [int( x) for x in position], int(circle.radius * PPM)) # Note: Python 3.x will enforce that pygame get the integers it requests, # and it will not convert from float. circleShape.draw = my_draw_circle # --- main game loop --- running = True while running: # Check the event queue for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): # The user closed the window or pressed escape running = False screen.fill((0, 0, 0, 0)) # Draw the world for body in world.bodies: for fixture in body.fixtures: fixture.shape.draw(body, fixture) # Make Box2D simulate the physics of our world for one step. world.Step(TIME_STEP, 10, 10) # Flip the screen and try to keep at the target FPS pygame.display.flip() clock.tick(TARGET_FPS) pygame.quit() print('Done!') pybox2d-2.3.2/examples/simple_cv.py000066400000000000000000000032351276457661000172770ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ A small self contained example showing how to use OpencvDrawFuncs to integrate pybox2d into an opencv mainloop In short: One static body: + One fixture: big polygon to represent the ground Two dynamic bodies: + One fixture: a polygon + One fixture: a circle And some drawing code that extends the shape classes. John Stowers """ import cv2 import Box2D from Box2D.b2 import (polygonShape, world) from opencv_draw import OpencvDrawFuncs # --- constants --- # Box2D deals with meters, but we want to display pixels, # so define a conversion factor: TARGET_FPS = 60 TIME_STEP = 1.0 / TARGET_FPS # --- pybox2d world setup --- # Create the world world = world(gravity=(0, -10), doSleep=True) # And a static body to hold the ground shape ground_body = world.CreateStaticBody( position=(0, 0), shapes=polygonShape(box=(50, 1)), ) # Create a couple dynamic bodies bodyc = world.CreateDynamicBody(position=(20, 45)) circle = bodyc.CreateCircleFixture(radius=0.5, density=1, friction=0.3) bodyb = world.CreateDynamicBody(position=(30, 45), angle=15) box = bodyb.CreatePolygonFixture(box=(2, 1), density=1, friction=0.3) world.CreateWeldJoint(bodyA=bodyc, bodyB=bodyb, anchor=bodyb.worldCenter) drawer = OpencvDrawFuncs(w=640, h=480, ppm=20) drawer.install() while True: key = 0xFF & cv2.waitKey(int(TIME_STEP * 1000)) # milliseconds if key == 27: break drawer.clear_screen() drawer.draw_world(world) # Make Box2D simulate the physics of our world for one step. world.Step(TIME_STEP, 10, 10) # Flip the screen and try to keep at the target FPS cv2.imshow("world", drawer.screen) pybox2d-2.3.2/examples/theo_jansen.py000066400000000000000000000147661276457661000176260ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2Vec2, b2_pi) # Original inspired by a contribution by roman_m # Dimensions scooped from APE (http://www.cove.org/ape/index.htm) class TheoJansen (Framework): name = "Theo Jansen" description = "Keys: left = a, brake = s, right = d, toggle motor = m" motorSpeed = 2 motorOn = True offset = (0, 8) def __init__(self): super(TheoJansen, self).__init__() # ball_count = 40 pivot = b2Vec2(0, 0.8) # The ground ground = self.world.CreateStaticBody( shapes=[ b2EdgeShape(vertices=[(-50, 0), (50, 0)]), b2EdgeShape(vertices=[(-50, 0), (-50, 10)]), b2EdgeShape(vertices=[(50, 0), (50, 10)]), ] ) box = b2FixtureDef( shape=b2PolygonShape(box=(0.5, 0.5)), density=1, friction=0.3) circle = b2FixtureDef( shape=b2CircleShape(radius=0.25), density=1) # Create the balls on the ground for i in range(ball_count): self.world.CreateDynamicBody( fixtures=circle, position=(-40 + 2.0 * i, 0.5), ) # The chassis chassis_fixture = b2FixtureDef( shape=b2PolygonShape(box=(2.5, 1)), density=1, friction=0.3, groupIndex=-1) self.chassis = self.world.CreateDynamicBody( fixtures=chassis_fixture, position=pivot + self.offset) # Chassis wheel wheel_fixture = b2FixtureDef( shape=b2CircleShape(radius=1.6), density=1, friction=0.3, groupIndex=-1) self.wheel = self.world.CreateDynamicBody( fixtures=wheel_fixture, position=pivot + self.offset) # Add a joint between the chassis wheel and the chassis itself self.motorJoint = self.world.CreateRevoluteJoint( bodyA=self.wheel, bodyB=self.chassis, anchor=pivot + self.offset, collideConnected=False, motorSpeed=self.motorSpeed, maxMotorTorque=400, enableMotor=self.motorOn) wheelAnchor = pivot + (0, -0.8) self.CreateLeg(-1, wheelAnchor) self.CreateLeg(1, wheelAnchor) self.wheel.transform = (self.wheel.position, 120.0 * b2_pi / 180) self.CreateLeg(-1, wheelAnchor) self.CreateLeg(1, wheelAnchor) self.wheel.transform = (self.wheel.position, -120.0 * b2_pi / 180) self.CreateLeg(-1, wheelAnchor) self.CreateLeg(1, wheelAnchor) def CreateLeg(self, s, wheelAnchor): p1, p2 = b2Vec2(5.4 * s, -6.1), b2Vec2(7.2 * s, -1.2) p3, p4 = b2Vec2(4.3 * s, -1.9), b2Vec2(3.1 * s, 0.8) p5, p6 = b2Vec2(6.0 * s, 1.5), b2Vec2(2.5 * s, 3.7) # Use a simple system to create mirrored vertices if s > 0: poly1 = b2PolygonShape(vertices=(p1, p2, p3)) poly2 = b2PolygonShape(vertices=((0, 0), p5 - p4, p6 - p4)) else: poly1 = b2PolygonShape(vertices=(p1, p3, p2)) poly2 = b2PolygonShape(vertices=((0, 0), p6 - p4, p5 - p4)) body1 = self.world.CreateDynamicBody( position=self.offset, angularDamping=10, fixtures=b2FixtureDef( shape=poly1, groupIndex=-1, density=1), ) body2 = self.world.CreateDynamicBody( position=p4 + self.offset, angularDamping=10, fixtures=b2FixtureDef( shape=poly2, groupIndex=-1, density=1), ) # Using a soft distance constraint can reduce some jitter. # It also makes the structure seem a bit more fluid by # acting like a suspension system. # Now, join all of the bodies together with distance joints, # and one single revolute joint on the chassis self.world.CreateDistanceJoint( dampingRatio=0.5, frequencyHz=10, bodyA=body1, bodyB=body2, anchorA=p2 + self.offset, anchorB=p5 + self.offset, ) self.world.CreateDistanceJoint( dampingRatio=0.5, frequencyHz=10, bodyA=body1, bodyB=body2, anchorA=p3 + self.offset, anchorB=p4 + self.offset, ) self.world.CreateDistanceJoint( dampingRatio=0.5, frequencyHz=10, bodyA=body1, bodyB=self.wheel, anchorA=p3 + self.offset, anchorB=wheelAnchor + self.offset, ) self.world.CreateDistanceJoint( dampingRatio=0.5, frequencyHz=10, bodyA=body2, bodyB=self.wheel, anchorA=p6 + self.offset, anchorB=wheelAnchor + self.offset, ) self.world.CreateRevoluteJoint( bodyA=body2, bodyB=self.chassis, anchor=p4 + self.offset, ) def Keyboard(self, key): if key == Keys.K_a: self.motorJoint.motorSpeed = -self.motorSpeed elif key == Keys.K_d: self.motorJoint.motorSpeed = self.motorSpeed elif key == Keys.K_s: self.motorJoint.motorSpeed = 0 elif key == Keys.K_m: self.motorJoint.motorEnabled = not self.motorJoint.motorEnabled if __name__ == "__main__": main(TheoJansen) pybox2d-2.3.2/examples/tiles.py000066400000000000000000000057071276457661000164440ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from math import ceil, log from .framework import (Framework, main) from Box2D import (b2FixtureDef, b2PolygonShape, b2Vec2) class Tiles (Framework): name = "Tiles" description = ('This stress tests the dynamic tree broad-phase. This also' 'shows that tile based collision\nis _not_ smooth due to ' 'Box2D not knowing about adjacency.') def __init__(self): super(Tiles, self).__init__() a = 0.5 def ground_positions(): N = 200 M = 10 position = b2Vec2(0, 0) for i in range(M): position.x = -N * a for j in range(N): yield position position.x += 2.0 * a position.y -= 2.0 * a ground = self.world.CreateStaticBody( position=(0, -a), shapes=[b2PolygonShape(box=(a, a, position, 0)) for position in ground_positions()] ) count = 20 def dynamic_positions(): x = b2Vec2(-7.0, 0.75) deltaX = (0.5625, 1.25) deltaY = (1.125, 0.0) for i in range(count): y = x.copy() for j in range(i, count): yield y y += deltaY x += deltaX for pos in dynamic_positions(): self.world.CreateDynamicBody( position=pos, fixtures=b2FixtureDef( shape=b2PolygonShape(box=(a, a)), density=5) ) def Step(self, settings): super(Tiles, self).Step(settings) cm = self.world.contactManager height = cm.broadPhase.treeHeight leafCount = cm.broadPhase.proxyCount minNodeCount = 2 * leafCount - 1 minHeight = ceil(log(float(minNodeCount)) / log(2)) self.Print('Dynamic tree height=%d, min=%d' % (height, minHeight)) if __name__ == "__main__": main(Tiles) pybox2d-2.3.2/examples/time_of_impact.py000066400000000000000000000117421276457661000202770ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2Color, b2Globals, b2PolygonShape, b2Sweep, b2TimeOfImpact) class TimeOfImpact (Framework): name = "Time of Impact" description = ("See the source code for more information." "No additional controls.") def __init__(self): super(TimeOfImpact, self).__init__() # The two shapes to check for time of impact self.shapeA = b2PolygonShape(box=(0.2, 1, (0.5, 1), 0)) self.shapeB = b2PolygonShape(box=(2, 0.1)) def Step(self, settings): super(TimeOfImpact, self).Step(settings) # b2Sweep describes the motion of a body/shape for TOI computation. # Shapes are defined with respect to the body origin, which may no # coincide with the center of mass. However, to support dynamics we # must interpolate the center of mass position. sweepA = b2Sweep(c0=(0, 0), c=(0, 0), a=0, a0=0, localCenter=(0, 0)) # The parameters of the sweep are defined as follows: # localCenter - local center of mass position # c0, c - center world positions # a0, a - world angles # t0 - time interval = [t0,1], where t0 is in [0,1] sweepB = b2Sweep(c0=(-0.20382018, 2.1368704), a0=-3.1664171, c=(-0.26699525, 2.3552670), a=-3.3926492, localCenter=(0, 0)) type_, time_of_impact = b2TimeOfImpact(shapeA=self.shapeA, shapeB=self.shapeB, sweepA=sweepA, sweepB=sweepB, tMax=1.0) # Alternative pybox2d syntax (no kwargs): # type_, t = b2TimeOfImpact(self.shapeA, self.shapeB, sweepA, sweepB, 1.0) # # And even uglier: # input=b2TOIInput(proxyA=b2DistanceProxy(shape=self.shapeA), proxyB=b2DistanceProxy(shape=self.shapeB), sweepA=sweepA, sweepB=sweepB, tMax=1.0) # type_, t = b2TimeOfImpact(input) self.Print("TOI = %g" % time_of_impact) self.Print("max toi iters = %d, max root iters = %d" % (b2Globals.b2_toiMaxIters, b2Globals.b2_toiMaxRootIters)) # Draw the shapes at their current position (t=0) # shapeA (the vertical polygon) transform = sweepA.GetTransform(0) self.renderer.DrawPolygon([self.renderer.to_screen(transform * v) for v in self.shapeA.vertices], b2Color(0.9, 0.9, 0.9)) # shapeB (the horizontal polygon) transform = sweepB.GetTransform(0) self.renderer.DrawPolygon([self.renderer.to_screen(transform * v) for v in self.shapeB.vertices], b2Color(0.5, 0.9, 0.5)) # localPoint=(2, -0.1) # rB = transform * localPoint - sweepB.c0 # wB = sweepB.a - sweepB.a0 # vB = sweepB.c - sweepB.c0 # v = vB + b2Cross(wB, rB) # Now, draw shapeB in a different color when they would collide (i.e., # at t=time of impact) This shows that the polygon would rotate upon # collision transform = sweepB.GetTransform(time_of_impact) self.renderer.DrawPolygon([self.renderer.to_screen(transform * v) for v in self.shapeB.vertices], b2Color(0.5, 0.7, 0.9)) # And finally, draw shapeB at t=1.0, where it would be if it did not # collide with shapeA In this case, time_of_impact = 1.0, so these # become the same polygon. transform = sweepB.GetTransform(1.0) self.renderer.DrawPolygon([self.renderer.to_screen(transform * v) for v in self.shapeB.vertices], b2Color(0.9, 0.5, 0.5)) if __name__ == "__main__": main(TimeOfImpact) pybox2d-2.3.2/examples/top_down_car.py000066400000000000000000000240571276457661000200010ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ Based on Chris Campbell's tutorial from iforce2d.net: http://www.iforce2d.net/b2dtut/top-down-car """ from .framework import (Framework, Keys, main) import math class TDGroundArea(object): """ An area on the ground that the car can run over """ def __init__(self, friction_modifier): self.friction_modifier = friction_modifier class TDTire(object): def __init__(self, car, max_forward_speed=100.0, max_backward_speed=-20, max_drive_force=150, turn_torque=15, max_lateral_impulse=3, dimensions=(0.5, 1.25), density=1.0, position=(0, 0)): world = car.body.world self.current_traction = 1 self.turn_torque = turn_torque self.max_forward_speed = max_forward_speed self.max_backward_speed = max_backward_speed self.max_drive_force = max_drive_force self.max_lateral_impulse = max_lateral_impulse self.ground_areas = [] self.body = world.CreateDynamicBody(position=position) self.body.CreatePolygonFixture(box=dimensions, density=density) self.body.userData = {'obj': self} @property def forward_velocity(self): body = self.body current_normal = body.GetWorldVector((0, 1)) return current_normal.dot(body.linearVelocity) * current_normal @property def lateral_velocity(self): body = self.body right_normal = body.GetWorldVector((1, 0)) return right_normal.dot(body.linearVelocity) * right_normal def update_friction(self): impulse = -self.lateral_velocity * self.body.mass if impulse.length > self.max_lateral_impulse: impulse *= self.max_lateral_impulse / impulse.length self.body.ApplyLinearImpulse(self.current_traction * impulse, self.body.worldCenter, True) aimp = 0.1 * self.current_traction * \ self.body.inertia * -self.body.angularVelocity self.body.ApplyAngularImpulse(aimp, True) current_forward_normal = self.forward_velocity current_forward_speed = current_forward_normal.Normalize() drag_force_magnitude = -2 * current_forward_speed self.body.ApplyForce(self.current_traction * drag_force_magnitude * current_forward_normal, self.body.worldCenter, True) def update_drive(self, keys): if 'up' in keys: desired_speed = self.max_forward_speed elif 'down' in keys: desired_speed = self.max_backward_speed else: return # find the current speed in the forward direction current_forward_normal = self.body.GetWorldVector((0, 1)) current_speed = self.forward_velocity.dot(current_forward_normal) # apply necessary force force = 0.0 if desired_speed > current_speed: force = self.max_drive_force elif desired_speed < current_speed: force = -self.max_drive_force else: return self.body.ApplyForce(self.current_traction * force * current_forward_normal, self.body.worldCenter, True) def update_turn(self, keys): if 'left' in keys: desired_torque = self.turn_torque elif 'right' in keys: desired_torque = -self.turn_torque else: return self.body.ApplyTorque(desired_torque, True) def add_ground_area(self, ud): if ud not in self.ground_areas: self.ground_areas.append(ud) self.update_traction() def remove_ground_area(self, ud): if ud in self.ground_areas: self.ground_areas.remove(ud) self.update_traction() def update_traction(self): if not self.ground_areas: self.current_traction = 1 else: self.current_traction = 0 mods = [ga.friction_modifier for ga in self.ground_areas] max_mod = max(mods) if max_mod > self.current_traction: self.current_traction = max_mod class TDCar(object): vertices = [(1.5, 0.0), (3.0, 2.5), (2.8, 5.5), (1.0, 10.0), (-1.0, 10.0), (-2.8, 5.5), (-3.0, 2.5), (-1.5, 0.0), ] tire_anchors = [(-3.0, 0.75), (3.0, 0.75), (-3.0, 8.50), (3.0, 8.50), ] def __init__(self, world, vertices=None, tire_anchors=None, density=0.1, position=(0, 0), **tire_kws): if vertices is None: vertices = TDCar.vertices self.body = world.CreateDynamicBody(position=position) self.body.CreatePolygonFixture(vertices=vertices, density=density) self.body.userData = {'obj': self} self.tires = [TDTire(self, **tire_kws) for i in range(4)] if tire_anchors is None: anchors = TDCar.tire_anchors joints = self.joints = [] for tire, anchor in zip(self.tires, anchors): j = world.CreateRevoluteJoint(bodyA=self.body, bodyB=tire.body, localAnchorA=anchor, # center of tire localAnchorB=(0, 0), enableMotor=False, maxMotorTorque=1000, enableLimit=True, lowerAngle=0, upperAngle=0, ) tire.body.position = self.body.worldCenter + anchor joints.append(j) def update(self, keys, hz): for tire in self.tires: tire.update_friction() for tire in self.tires: tire.update_drive(keys) # control steering lock_angle = math.radians(40.) # from lock to lock in 0.5 sec turn_speed_per_sec = math.radians(160.) turn_per_timestep = turn_speed_per_sec / hz desired_angle = 0.0 if 'left' in keys: desired_angle = lock_angle elif 'right' in keys: desired_angle = -lock_angle front_left_joint, front_right_joint = self.joints[2:4] angle_now = front_left_joint.angle angle_to_turn = desired_angle - angle_now # TODO fix b2Clamp for non-b2Vec2 types if angle_to_turn < -turn_per_timestep: angle_to_turn = -turn_per_timestep elif angle_to_turn > turn_per_timestep: angle_to_turn = turn_per_timestep new_angle = angle_now + angle_to_turn # Rotate the tires by locking the limits: front_left_joint.SetLimits(new_angle, new_angle) front_right_joint.SetLimits(new_angle, new_angle) class TopDownCar (Framework): name = "Top Down Car" description = "Keys: accel = w, reverse = s, left = a, right = d" def __init__(self): super(TopDownCar, self).__init__() # Top-down -- no gravity in the screen plane self.world.gravity = (0, 0) self.key_map = {Keys.K_w: 'up', Keys.K_s: 'down', Keys.K_a: 'left', Keys.K_d: 'right', } # Keep track of the pressed keys self.pressed_keys = set() # The walls boundary = self.world.CreateStaticBody(position=(0, 20)) boundary.CreateEdgeChain([(-30, -30), (-30, 30), (30, 30), (30, -30), (-30, -30)] ) # A couple regions of differing traction self.car = TDCar(self.world) gnd1 = self.world.CreateStaticBody(userData={'obj': TDGroundArea(0.5)}) fixture = gnd1.CreatePolygonFixture( box=(9, 7, (-10, 15), math.radians(20))) # Set as sensors so that the car doesn't collide fixture.sensor = True gnd2 = self.world.CreateStaticBody(userData={'obj': TDGroundArea(0.2)}) fixture = gnd2.CreatePolygonFixture( box=(9, 5, (5, 20), math.radians(-40))) fixture.sensor = True def Keyboard(self, key): key_map = self.key_map if key in key_map: self.pressed_keys.add(key_map[key]) else: super(TopDownCar, self).Keyboard(key) def KeyboardUp(self, key): key_map = self.key_map if key in key_map: self.pressed_keys.remove(key_map[key]) else: super(TopDownCar, self).KeyboardUp(key) def handle_contact(self, contact, began): # A contact happened -- see if a wheel hit a # ground area fixture_a = contact.fixtureA fixture_b = contact.fixtureB body_a, body_b = fixture_a.body, fixture_b.body ud_a, ud_b = body_a.userData, body_b.userData if not ud_a or not ud_b: return tire = None ground_area = None for ud in (ud_a, ud_b): obj = ud['obj'] if isinstance(obj, TDTire): tire = obj elif isinstance(obj, TDGroundArea): ground_area = obj if ground_area is not None and tire is not None: if began: tire.add_ground_area(ground_area) else: tire.remove_ground_area(ground_area) def BeginContact(self, contact): self.handle_contact(contact, True) def EndContact(self, contact): self.handle_contact(contact, False) def Step(self, settings): self.car.update(self.pressed_keys, settings.hz) super(TopDownCar, self).Step(settings) tractions = [tire.current_traction for tire in self.car.tires] self.Print('Current tractions: %s' % tractions) if __name__ == "__main__": main(TopDownCar) pybox2d-2.3.2/examples/tumbler.py000066400000000000000000000047031276457661000167710ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, main) from Box2D import (b2FixtureDef, b2PolygonShape, b2_pi) class Tumbler (Framework): name = "Tumbler" description = '' count = 800 def __init__(self): Framework.__init__(self) ground = self.world.CreateBody() body = self.world.CreateDynamicBody( position=(0, 10), allowSleep=False, shapeFixture=b2FixtureDef(density=5.0), shapes=[ b2PolygonShape(box=(0.5, 10, (10, 0), 0)), b2PolygonShape(box=(0.5, 10, (-10, 0), 0)), b2PolygonShape(box=(10, 0.5, (0, 10), 0)), b2PolygonShape(box=(10, 0.5, (0, -10), 0)), ] ) self.joint = self.world.CreateRevoluteJoint(bodyA=ground, bodyB=body, localAnchorA=(0, 10), localAnchorB=(0, 0), referenceAngle=0, motorSpeed=0.05 * b2_pi, enableMotor=True, maxMotorTorque=1.0e8) def Step(self, settings): Framework.Step(self, settings) self.count -= 1 if self.count == 0: return self.world.CreateDynamicBody( position=(0, 10), allowSleep=False, fixtures=b2FixtureDef( density=1.0, shape=b2PolygonShape(box=(0.125, 0.125))), ) if __name__ == "__main__": main(Tumbler) pybox2d-2.3.2/examples/vertical_stack.py000066400000000000000000000060751276457661000203210ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape) class VerticalStack (Framework): name = "Vertical Stack" description = ("Tests the stability of stacking circles and boxes\n" "Press B to launch a horizontal bullet") bullet = None def __init__(self): super(VerticalStack, self).__init__() columns = 5 rows = 16 ground = self.world.CreateStaticBody( shapes=[ b2EdgeShape(vertices=[(-40, 0), (40, 0)]), b2EdgeShape(vertices=[(20, 0), (20, 20)]), ] ) box = b2FixtureDef( shape=b2PolygonShape(box=(0.5, 0.5)), density=1, friction=0.3) circle = b2FixtureDef( shape=b2CircleShape(radius=0.5), density=1, friction=0.3) box_start = -10 box_space = 2.5 circle_start = 8 circle_space = 2.5 for j in range(columns): for i in range(rows): self.world.CreateDynamicBody( fixtures=box, position=(box_start + box_space * j, 0.752 + 1.54 * i) ) self.world.CreateDynamicBody( fixtures=circle, position=(circle_start + circle_space * j, 0.752 + 1.54 * i) ) def Step(self, settings): super(VerticalStack, self).Step(settings) def Keyboard(self, key): if key == Keys.K_b: if self.bullet: self.world.DestroyBody(self.bullet) self.bullet = None circle = b2FixtureDef( shape=b2CircleShape(radius=0.25), density=20, restitution=0.05) self.bullet = self.world.CreateDynamicBody( position=(-31, 5), bullet=True, fixtures=circle, linearVelocity=(400, 0), ) if __name__ == "__main__": main(VerticalStack) pybox2d-2.3.2/examples/web.py000066400000000000000000000101201276457661000160620ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version Copyright (c) 2010 kne / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from .framework import (Framework, Keys, main) from Box2D import (b2DistanceJointDef, b2EdgeShape, b2FixtureDef, b2PolygonShape) class Web(Framework): name = "Web" description = "This demonstrates a soft distance joint. Press: (b) to delete a body, (j) to delete a joint" bodies = [] joints = [] def __init__(self): super(Web, self).__init__() # The ground ground = self.world.CreateBody( shapes=b2EdgeShape(vertices=[(-40, 0), (40, 0)]) ) fixture = b2FixtureDef(shape=b2PolygonShape(box=(0.5, 0.5)), density=5, friction=0.2) self.bodies = [self.world.CreateDynamicBody( position=pos, fixtures=fixture ) for pos in ((-5, 5), (5, 5), (5, 15), (-5, 15))] bodies = self.bodies # Create the joints between each of the bodies and also the ground # bodyA bodyB localAnchorA localAnchorB sets = [(ground, bodies[0], (-10, 0), (-0.5, -0.5)), (ground, bodies[1], (10, 0), (0.5, -0.5)), (ground, bodies[2], (10, 20), (0.5, 0.5)), (ground, bodies[3], (-10, 20), (-0.5, 0.5)), (bodies[0], bodies[1], (0.5, 0), (-0.5, 0)), (bodies[1], bodies[2], (0, 0.5), (0, -0.5)), (bodies[2], bodies[3], (-0.5, 0), (0.5, 0)), (bodies[3], bodies[0], (0, -0.5), (0, 0.5)), ] # We will define the positions in the local body coordinates, the length # will automatically be set by the __init__ of the b2DistanceJointDef self.joints = [] for bodyA, bodyB, localAnchorA, localAnchorB in sets: dfn = b2DistanceJointDef( frequencyHz=4.0, dampingRatio=0.5, bodyA=bodyA, bodyB=bodyB, localAnchorA=localAnchorA, localAnchorB=localAnchorB, ) self.joints.append(self.world.CreateJoint(dfn)) def Keyboard(self, key): if key == Keys.K_b: for body in self.bodies: # Gets both FixtureDestroyed and JointDestroyed callbacks. self.world.DestroyBody(body) break elif key == Keys.K_j: for joint in self.joints: # Does not get a JointDestroyed callback! self.world.DestroyJoint(joint) self.joints.remove(joint) break def FixtureDestroyed(self, fixture): super(Web, self).FixtureDestroyed(fixture) body = fixture.body if body in self.bodies: print(body) self.bodies.remove(body) print("Fixture destroyed, removing its body from the list. Bodies left: %d" % len(self.bodies)) def JointDestroyed(self, joint): if joint in self.joints: self.joints.remove(joint) print("Joint destroyed and removed from the list. Joints left: %d" % len(self.joints)) if __name__ == "__main__": main(Web) pybox2d-2.3.2/library/000077500000000000000000000000001276457661000145675ustar00rootroot00000000000000pybox2d-2.3.2/library/Box2D/000077500000000000000000000000001276457661000155055ustar00rootroot00000000000000pybox2d-2.3.2/library/Box2D/Box2D.py000066400000000000000000012263231276457661000170060ustar00rootroot00000000000000# This file was automatically generated by SWIG (http://www.swig.org). # Version 3.0.7 # # Do not make changes to this file unless you know what you are doing--modify # the SWIG interface file instead. from sys import version_info if version_info >= (3, 0, 0): new_instancemethod = lambda func, inst, cls: _Box2D.SWIG_PyInstanceMethod_New(func) else: from new import instancemethod as new_instancemethod if version_info >= (2, 6, 0): def swig_import_helper(): from os.path import dirname import imp fp = None try: fp, pathname, description = imp.find_module('_Box2D', [dirname(__file__)]) except ImportError: import _Box2D return _Box2D if fp is not None: try: _mod = imp.load_module('_Box2D', fp, pathname, description) finally: fp.close() return _mod _Box2D = swig_import_helper() del swig_import_helper else: import _Box2D del version_info try: _swig_property = property except NameError: pass # Python < 2.2 doesn't have 'property'. def _swig_setattr_nondynamic(self, class_type, name, value, static=1): if (name == "thisown"): return self.this.own(value) if (name == "this"): if type(value).__name__ == 'SwigPyObject': self.__dict__[name] = value return method = class_type.__swig_setmethods__.get(name, None) if method: return method(self, value) if (not static): object.__setattr__(self, name, value) else: raise AttributeError("You cannot add attributes to %s" % self) def _swig_setattr(self, class_type, name, value): return _swig_setattr_nondynamic(self, class_type, name, value, 0) def _swig_getattr_nondynamic(self, class_type, name, static=1): if (name == "thisown"): return self.this.own() method = class_type.__swig_getmethods__.get(name, None) if method: return method(self) if (not static): return object.__getattr__(self, name) else: raise AttributeError(name) def _swig_getattr(self, class_type, name): return _swig_getattr_nondynamic(self, class_type, name, 0) def _swig_repr(self): try: strthis = "proxy of " + self.this.__repr__() except: strthis = "" return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) try: _object = object _newclass = 1 except AttributeError: class _object: pass _newclass = 0 def _swig_setattr_nondynamic_method(set): def set_attr(self, name, value): if (name == "thisown"): return self.this.own(value) if hasattr(self, name) or (name == "this"): set(self, name, value) else: raise AttributeError("You cannot add attributes to %s" % self) return set_attr try: import weakref weakref_proxy = weakref.proxy except: weakref_proxy = lambda x: x def _dir_filter(self): """ Using introspection, mimic dir() by adding up all of the __dicts__ for the current class and all base classes (type(self).__mro__ returns all of the classes that make it up) Basically filters by: __x__ OK __x bad _classname bad """ def check(s): if s.startswith('__'): if s.endswith('__'): return True else: return False else: for typename in typenames: if typename in s: return False return True keys = sum([list(c.__dict__.keys()) for c in type(self).__mro__],[]) keys += list(self.__dict__.keys()) typenames = ["_%s" % c.__name__ for c in type(self).__mro__] ret = [s for s in list(set(keys)) if check(s)] ret.sort() return ret def _init_kwargs(self, **kwargs): cls = self.__class__ for key, value in kwargs.items(): try: getattr(cls, key) except AttributeError: raise AttributeError('Invalid keyword argument "%s" for %s' % (key, cls)) try: setattr(self, key, value) except Exception as ex: raise ex.__class__('Failed on kwargs for %s.%s: %s' \ % (self.__class__.__name__, key, ex)) def _init_jointdef_kwargs(self, bodyA=None, bodyB=None, **kwargs): if bodyA is not None or bodyB is not None: # Make sure that bodyA and bodyB are defined before the rest _init_kwargs(self, bodyA=bodyA, bodyB=bodyB) _init_kwargs(self, **kwargs) _repr_attrs = {'b2AABB': ['center', 'extents', 'lowerBound', 'perimeter', 'upperBound', 'valid', ], 'b2Body': ['active', 'angle', 'angularDamping', 'angularVelocity', 'awake', 'bullet', 'contacts', 'fixedRotation', 'fixtures', 'inertia', 'joints', 'linearDamping', 'linearVelocity', 'localCenter', 'mass', 'massData', 'position', 'sleepingAllowed', 'transform', 'type', 'userData', 'worldCenter', ], 'b2BodyDef': ['active', 'allowSleep', 'angle', 'angularDamping', 'angularVelocity', 'awake', 'bullet', 'fixedRotation', 'fixtures', 'inertiaScale', 'linearDamping', 'linearVelocity', 'position', 'shapeFixture', 'shapes', 'type', 'userData', ], 'b2BroadPhase': ['proxyCount', ], 'b2CircleShape': ['childCount', 'pos', 'radius', 'type', ], 'b2ClipVertex': ['id', 'v', ], 'b2Color': ['b', 'bytes', 'g', 'list', 'r', ], 'b2Contact': ['childIndexA', 'childIndexB', 'enabled', 'fixtureA', 'fixtureB', 'manifold', 'touching', 'worldManifold', ], 'b2ContactEdge': ['contact', 'other', ], 'b2ContactFeature': ['indexA', 'indexB', 'typeA', 'typeB', ], 'b2ContactID': ['cf', 'key', ], 'b2ContactImpulse': ['normalImpulses', 'tangentImpulses', ], 'b2ContactManager': ['allocator', 'broadPhase', 'contactCount', 'contactFilter', 'contactList', 'contactListener', ], 'b2ContactPoint': ['fixtureA', 'fixtureB', 'normal', 'position', 'state', ], 'b2DistanceInput': ['proxyA', 'proxyB', 'transformA', 'transformB', 'useRadii', ], 'b2DistanceJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'dampingRatio', 'frequency', 'length', 'type', 'userData', ], 'b2DistanceJointDef': ['anchorA', 'anchorB', 'bodyA', 'bodyB', 'collideConnected', 'dampingRatio', 'frequencyHz', 'length', 'localAnchorA', 'localAnchorB', 'type', 'userData', ], 'b2DistanceOutput': ['distance', 'iterations', 'pointA', 'pointB', ], 'b2DistanceProxy': ['m_buffer', 'shape', 'vertices', ], 'b2Draw': ['flags', ], 'b2DrawExtended': ['center', 'convertVertices', 'flags', 'flipX', 'flipY', 'offset', 'screenSize', 'zoom', ], 'b2EdgeShape': ['all_vertices', 'childCount', 'hasVertex0', 'hasVertex3', 'radius', 'type', 'vertex0', 'vertex1', 'vertex2', 'vertex3', 'vertexCount', 'vertices', ], 'b2Filter': ['categoryBits', 'groupIndex', 'maskBits', ], 'b2Fixture': ['body', 'density', 'filterData', 'friction', 'massData', 'restitution', 'sensor', 'shape', 'type', 'userData', ], 'b2FixtureDef': ['categoryBits', 'density', 'filter', 'friction', 'groupIndex', 'isSensor', 'maskBits', 'restitution', 'shape', 'userData', ], 'b2FixtureProxy': ['aabb', 'childIndex', 'fixture', 'proxyId', ], 'b2FrictionJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'maxForce', 'maxTorque', 'type', 'userData', ], 'b2FrictionJointDef': ['anchor', 'bodyA', 'bodyB', 'collideConnected', 'localAnchorA', 'localAnchorB', 'maxForce', 'maxTorque', 'type', 'userData', ], 'b2GearJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'ratio', 'type', 'userData', ], 'b2GearJointDef': ['bodyA', 'bodyB', 'collideConnected', 'joint1', 'joint2', 'ratio', 'type', 'userData', ], 'b2Jacobian': ['angularA', 'angularB', 'linearA', 'linearB', ], 'b2Joint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'type', 'userData', ], 'b2JointDef': ['bodyA', 'bodyB', 'collideConnected', 'type', 'userData', ], 'b2JointEdge': ['joint', 'other', ], 'b2WheelJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'maxMotorTorque', 'motorEnabled', 'motorSpeed', 'speed', 'springDampingRatio', 'springFrequencyHz', 'translation', 'type', 'userData', ], 'b2WheelJointDef': ['anchor', 'axis', 'bodyA', 'bodyB', 'collideConnected', 'dampingRatio', 'enableMotor', 'frequencyHz', 'localAnchorA', 'localAnchorB', 'localAxisA', 'maxMotorTorque', 'motorSpeed', 'type', 'userData', ], 'b2ChainShape': ['childCount', 'edges', 'radius', 'type', 'vertexCount', 'vertices', ], 'b2Manifold': ['localNormal', 'localPoint', 'pointCount', 'points', 'type_', ], 'b2ManifoldPoint': ['id', 'isNew', 'localPoint', 'normalImpulse', 'tangentImpulse', ], 'b2MassData': ['I', 'center', 'mass', ], 'b2Mat22': ['angle', 'col1', 'col2', 'inverse', ], 'b2Mat33': ['col1', 'col2', 'col3', ], 'b2MouseJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'dampingRatio', 'frequency', 'maxForce', 'target', 'type', 'userData', ], 'b2MouseJointDef': ['bodyA', 'bodyB', 'collideConnected', 'dampingRatio', 'frequencyHz', 'maxForce', 'target', 'type', 'userData', ], 'b2Pair': ['proxyIdA', 'proxyIdB', ], 'b2PolygonShape': ['box', 'centroid', 'childCount', 'normals', 'radius', 'type', 'valid', 'vertexCount', 'vertices', ], 'b2PrismaticJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'limitEnabled', 'limits', 'lowerLimit', 'maxMotorForce', 'motorEnabled', 'motorSpeed', 'speed', 'translation', 'type', 'upperLimit', 'userData', ], 'b2PrismaticJointDef': ['anchor', 'axis', 'bodyA', 'bodyB', 'collideConnected', 'enableLimit', 'enableMotor', 'localAnchorA', 'localAnchorB', 'localAxis1', 'lowerTranslation', 'maxMotorForce', 'motorSpeed', 'referenceAngle', 'type', 'upperTranslation', 'userData', ], 'b2PulleyJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'groundAnchorA', 'groundAnchorB', 'length1', 'length2', 'ratio', 'type', 'userData', ], 'b2PulleyJointDef': ['anchorA', 'anchorB', 'bodyA', 'bodyB', 'collideConnected', 'groundAnchorA', 'groundAnchorB', 'lengthA', 'lengthB', 'localAnchorA', 'localAnchorB', 'maxLengthA', 'maxLengthB', 'ratio', 'type', 'userData', ], 'b2RayCastInput': ['maxFraction', 'p1', 'p2', ], 'b2RayCastOutput': ['fraction', 'normal', ], 'b2RevoluteJoint': ['active', 'anchorA', 'anchorB', 'angle', 'bodyA', 'bodyB', 'limitEnabled', 'limits', 'lowerLimit', 'maxMotorTorque', 'motorEnabled', 'motorSpeed', 'speed', 'type', 'upperLimit', 'userData', ], 'b2RevoluteJointDef': ['anchor', 'bodyA', 'bodyB', 'collideConnected', 'enableLimit', 'enableMotor', 'localAnchorA', 'localAnchorB', 'lowerAngle', 'maxMotorTorque', 'motorSpeed', 'referenceAngle', 'type', 'upperAngle', 'userData', ], 'b2RopeJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'limitState', 'maxLength', 'type', 'userData', ], 'b2RopeJointDef': ['anchorA', 'anchorB', 'bodyA', 'bodyB', 'collideConnected', 'localAnchorA', 'localAnchorB', 'maxLength', 'type', 'userData', ], 'b2Shape': ['childCount', 'radius', 'type', ], 'b2Sweep': ['a', 'a0', 'alpha0', 'c', 'c0', 'localCenter', ], 'b2TOIInput': ['proxyA', 'proxyB', 'sweepA', 'sweepB', 'tMax', ], 'b2TOIOutput': ['state', 't', ], 'b2Transform': ['R', 'angle', 'position', ], 'b2Vec2': ['length', 'lengthSquared', 'skew', 'tuple', 'valid', 'x', 'y', ], 'b2Vec3': ['length', 'lengthSquared', 'tuple', 'valid', 'x', 'y', 'z', ], 'b2Version': ['major', 'minor', 'revision', ], 'b2WeldJoint': ['active', 'anchorA', 'anchorB', 'bodyA', 'bodyB', 'type', 'userData', ], 'b2WeldJointDef': ['anchor', 'bodyA', 'bodyB', 'collideConnected', 'localAnchorA', 'localAnchorB', 'referenceAngle', 'type', 'userData', ], 'b2World': ['autoClearForces', 'bodies', 'bodyCount', 'contactCount', 'contactFilter', 'contactListener', 'contactManager', 'contacts', 'continuousPhysics', 'destructionListener', 'gravity', 'jointCount', 'joints', 'locked', 'proxyCount', 'renderer', 'subStepping', 'warmStarting', ], 'b2WorldManifold': ['normal', 'points', ], } MAX_REPR_DEPTH = 4 MAX_REPR_STR_LEN = 250 MAX_REPR_SUB_LINES = 10 REPR_INDENT = 4 _repr_state = {} def _format_repr(obj): """ Dynamically creates the object representation string for `obj`. Attributes found in _repr_attrs[class_name] will be included. """ global _repr_state if 'spaces' not in _repr_state: _repr_state['spaces'] = 0 if 'depth' not in _repr_state: _repr_state['depth'] = 1 else: _repr_state['depth'] += 1 if _repr_state['depth'] > MAX_REPR_DEPTH: _repr_state['depth'] -= 1 return '%s(max recursion depth hit)' % (' ' * _repr_state['spaces']) class_line = '%s(' % (obj.__class__.__name__, ) orig_spaces = _repr_state['spaces'] ret = [] props = _repr_attrs.get(obj.__class__.__name__, []) try: prop_spacing = _repr_state['spaces'] + len(class_line.lstrip()) separator = '\n' + ' ' * prop_spacing for prop in props: _repr_state['spaces'] = len(prop) + 1 try: s = repr(getattr(obj, prop)) except Exception as ex: s = '(repr: %s)' % ex lines = s.split('\n') if len(lines) > MAX_REPR_SUB_LINES: length_ = 0 for i, line_ in enumerate(lines[:MAX_REPR_SUB_LINES]): length_ += len(line_) if length_ > MAX_REPR_STR_LEN: ending_delim = [] for j in s[::-1]: if j in ')]}': ending_delim.insert(0, j) else: break ret[-1] = '%s... %s' % (ret[-1], ''.join(ending_delim)) break if i == 0: ret.append('%s=%s' % (prop, line_)) else: ret.append(line_) else: ret.append('%s=%s' % (prop, lines[0].lstrip())) if len(lines) > 1: ret.extend(lines[1:]) ret[-1] += ',' finally: _repr_state['depth'] -= 1 _repr_state['spaces'] = orig_spaces if 1<= len(ret) <= 3: # Closing parenthesis on same line ret[-1] += ')' return ''.join(ret) else: # Closing parenthesis on next line ret.append(')') return '%s%s' % (class_line, separator.join(ret)) def __jointeq(a, b): """__jointeq(b2Joint a, b2Joint b) -> bool""" return _Box2D.__jointeq(a, b) def __bodyeq(a, b): """__bodyeq(b2Body a, b2Body b) -> bool""" return _Box2D.__bodyeq(a, b) def __shapeeq(a, b): """__shapeeq(b2Shape a, b2Shape b) -> bool""" return _Box2D.__shapeeq(a, b) def __fixtureeq(a, b): """__fixtureeq(b2Fixture a, b2Fixture b) -> bool""" return _Box2D.__fixtureeq(a, b) def __b2ComputeCentroid(vs, count): """__b2ComputeCentroid(b2Vec2 vs, int32 count) -> b2Vec2""" return _Box2D.__b2ComputeCentroid(vs, count) def b2CheckVertices(vertices, count, additional_checks=True): """b2CheckVertices(b2Vec2 vertices, int32 count, bool additional_checks=True) -> bool""" return _Box2D.b2CheckVertices(vertices, count, additional_checks) def b2CheckPolygon(shape, additional_checks=True): """b2CheckPolygon(b2PolygonShape shape, bool additional_checks=True) -> bool""" return _Box2D.b2CheckPolygon(shape, additional_checks) _Box2D.RAND_LIMIT_swigconstant(_Box2D) RAND_LIMIT = _Box2D.RAND_LIMIT def b2Random(*args): """ b2Random() -> float32 b2Random(float32 lo, float32 hi) -> float32 """ return _Box2D.b2Random(*args) b2_epsilon = 1.192092896e-07 class _indexable_generator(list): def __init__(self, iter): list.__init__(self) self.iter=iter self.__full=False def __len__(self): self.__fill_list__() return super(_indexable_generator, self).__len__() def __iter__(self): for item in self.iter: self.append(item) yield item self.__full=True def __fill_list__(self): for item in self.iter: self.append(item) self.__full=True def __getitem__(self, i): """Support indexing positive/negative elements of the generator, but no slices. If you want those, use list(generator)""" if not self.__full: if i < 0: self.__fill_list__() elif i >= list.__len__(self): diff=i-list.__len__(self)+1 for j in range(diff): value = next(self.iter) self.append(value) return super(_indexable_generator, self).__getitem__(i) def _generator_from_linked_list(first): if first: one = first while one: yield one one = one.next def _list_from_linked_list(first): if not first: return [] one = first lst = [] while one: lst.append(one) one = one.next # linked lists are stored in reverse order from creation order lst.reverse() return lst # Support using == on bodies, joints, and shapes def b2ShapeCompare(a, b): if not isinstance(a, b2Shape) or not isinstance(b, b2Shape): return False return __shapeeq(a, b) def b2BodyCompare(a, b): if not isinstance(a, b2Body) or not isinstance(b, b2Body): return False return __bodyeq(a, b) def b2JointCompare(a, b): if not isinstance(a, b2Joint) or not isinstance(b, b2Joint): return False return __jointeq(a, b) def b2FixtureCompare(a, b): if not isinstance(a, b2Fixture) or not isinstance(b, b2Fixture): return False return __fixtureeq(a, b) def _b2Distance(*args): """ _b2Distance(b2Shape shapeA, int idxA, b2Shape shapeB, int idxB, b2Transform transformA, b2Transform transformB, bool useRadii=True) -> b2DistanceOutput _b2Distance(b2DistanceInput input) -> b2DistanceOutput """ return _Box2D._b2Distance(*args) import collections b2DistanceResult = collections.namedtuple('b2DistanceResult', 'pointA pointB distance iterations') def b2Distance(shapeA=None, idxA=0, shapeB=None, idxB=0, transformA=None, transformB=None, useRadii=True): """ Compute the closest points between two shapes. Can be called one of two ways: + b2Distance(b2DistanceInput) This uses the b2DistanceInput structure, where you define your own distance proxies Or more conveniently using kwargs: + b2Distance(shapeA=.., idxA=0, shapeB=.., idxB=0, transformA=.., transformB=.., useRadii=True) Returns a namedtuple in the form: b2DistanceResult(pointA=(ax, ay), pointB=(bx, by), distance, iterations) """ if isinstance(shapeA, b2DistanceInput): out = _b2Distance(shapeA) else: out = _b2Distance(shapeA, idxA, shapeB, idxB, transformA, transformB, useRadii) return b2DistanceResult(pointA=tuple(out.pointA), pointB=tuple(out.pointB), distance=out.distance, iterations=out.iterations) def b2GetPointStates(manifold1, manifold2): """ b2GetPointStates(b2Manifold manifold1, b2Manifold manifold2) -> PyObject * Compute the point states given two manifolds. The states pertain to the transition from manifold1 to manifold2. So state1 is either persist or remove while state2 is either add or persist. """ return _Box2D.b2GetPointStates(manifold1, manifold2) class b2ContactPoint(object): """Proxy of C++ b2ContactPoint class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2ContactPoint_swiginit(self,_Box2D.new_b2ContactPoint()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2ContactPoint fixtureA = _swig_property(_Box2D.b2ContactPoint_fixtureA_get, _Box2D.b2ContactPoint_fixtureA_set) fixtureB = _swig_property(_Box2D.b2ContactPoint_fixtureB_get, _Box2D.b2ContactPoint_fixtureB_set) normal = _swig_property(_Box2D.b2ContactPoint_normal_get, _Box2D.b2ContactPoint_normal_set) position = _swig_property(_Box2D.b2ContactPoint_position_get, _Box2D.b2ContactPoint_position_set) state = _swig_property(_Box2D.b2ContactPoint_state_get, _Box2D.b2ContactPoint_state_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ContactPoint self) -> long""" return _Box2D.b2ContactPoint___hash__(self) def __repr__(self): return _format_repr(self) b2ContactPoint.__hash__ = new_instancemethod(_Box2D.b2ContactPoint___hash__, None, b2ContactPoint) b2ContactPoint_swigregister = _Box2D.b2ContactPoint_swigregister b2ContactPoint_swigregister(b2ContactPoint) b2Globals = _Box2D.b2Globals def _b2TimeOfImpact(*args): """ _b2TimeOfImpact(b2Shape shapeA, int idxA, b2Shape shapeB, int idxB, b2Sweep sweepA, b2Sweep sweepB, float32 tMax) -> b2TOIOutput _b2TimeOfImpact(b2TOIInput input) -> b2TOIOutput """ return _Box2D._b2TimeOfImpact(*args) def b2TimeOfImpact(shapeA=None, idxA=0, shapeB=None, idxB=0, sweepA=None, sweepB=None, tMax=0.0): """ Compute the upper bound on time before two shapes penetrate. Time is represented as a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, non-tunneling collision. If you change the time interval, you should call this function again. Note: use b2Distance to compute the contact point and normal at the time of impact. Can be called one of several ways: + b2TimeOfImpact(b2TOIInput) # utilizes the b2TOIInput structure, where you define your own proxies Or utilizing kwargs: + b2TimeOfImpact(shapeA=a, shapeB=b, idxA=0, idxB=0, sweepA=sa, sweepB=sb, tMax=t) Where idxA and idxB are optional and used only if the shapes are loops (they indicate which section to use.) sweep[A,B] are of type b2Sweep. Returns a tuple in the form: (output state, time of impact) Where output state is in b2TOIOutput.[ e_unknown, e_failed, e_overlapped, e_touching, e_separated ] """ if isinstance(shapeA, b2TOIInput): toi_input = shapeA out = _b2TimeOfImpact(toi_input) else: out = _b2TimeOfImpact(shapeA, idxA, shapeB, idxB, sweepA, sweepB, tMax) return (out.state, out.t) class b2AssertException(object): """Proxy of C++ b2AssertException class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr __dir__ = _dir_filter def __hash__(self): """__hash__(b2AssertException self) -> long""" return _Box2D.b2AssertException___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self): """__init__(b2AssertException self) -> b2AssertException""" _Box2D.b2AssertException_swiginit(self, _Box2D.new_b2AssertException()) __swig_destroy__ = _Box2D.delete_b2AssertException b2AssertException.__hash__ = new_instancemethod(_Box2D.b2AssertException___hash__, None, b2AssertException) b2AssertException_swigregister = _Box2D.b2AssertException_swigregister b2AssertException_swigregister(b2AssertException) _Box2D.b2_pi_swigconstant(_Box2D) b2_pi = _Box2D.b2_pi _Box2D.b2_maxManifoldPoints_swigconstant(_Box2D) b2_maxManifoldPoints = _Box2D.b2_maxManifoldPoints _Box2D.b2_maxPolygonVertices_swigconstant(_Box2D) b2_maxPolygonVertices = _Box2D.b2_maxPolygonVertices _Box2D.b2_aabbExtension_swigconstant(_Box2D) b2_aabbExtension = _Box2D.b2_aabbExtension _Box2D.b2_aabbMultiplier_swigconstant(_Box2D) b2_aabbMultiplier = _Box2D.b2_aabbMultiplier _Box2D.b2_linearSlop_swigconstant(_Box2D) b2_linearSlop = _Box2D.b2_linearSlop _Box2D.b2_angularSlop_swigconstant(_Box2D) b2_angularSlop = _Box2D.b2_angularSlop _Box2D.b2_polygonRadius_swigconstant(_Box2D) b2_polygonRadius = _Box2D.b2_polygonRadius _Box2D.b2_maxSubSteps_swigconstant(_Box2D) b2_maxSubSteps = _Box2D.b2_maxSubSteps _Box2D.b2_maxTOIContacts_swigconstant(_Box2D) b2_maxTOIContacts = _Box2D.b2_maxTOIContacts _Box2D.b2_velocityThreshold_swigconstant(_Box2D) b2_velocityThreshold = _Box2D.b2_velocityThreshold _Box2D.b2_maxLinearCorrection_swigconstant(_Box2D) b2_maxLinearCorrection = _Box2D.b2_maxLinearCorrection _Box2D.b2_maxAngularCorrection_swigconstant(_Box2D) b2_maxAngularCorrection = _Box2D.b2_maxAngularCorrection _Box2D.b2_maxTranslation_swigconstant(_Box2D) b2_maxTranslation = _Box2D.b2_maxTranslation _Box2D.b2_maxTranslationSquared_swigconstant(_Box2D) b2_maxTranslationSquared = _Box2D.b2_maxTranslationSquared _Box2D.b2_maxRotation_swigconstant(_Box2D) b2_maxRotation = _Box2D.b2_maxRotation _Box2D.b2_maxRotationSquared_swigconstant(_Box2D) b2_maxRotationSquared = _Box2D.b2_maxRotationSquared _Box2D.b2_baumgarte_swigconstant(_Box2D) b2_baumgarte = _Box2D.b2_baumgarte _Box2D.b2_toiBaugarte_swigconstant(_Box2D) b2_toiBaugarte = _Box2D.b2_toiBaugarte _Box2D.b2_timeToSleep_swigconstant(_Box2D) b2_timeToSleep = _Box2D.b2_timeToSleep _Box2D.b2_linearSleepTolerance_swigconstant(_Box2D) b2_linearSleepTolerance = _Box2D.b2_linearSleepTolerance _Box2D.b2_angularSleepTolerance_swigconstant(_Box2D) b2_angularSleepTolerance = _Box2D.b2_angularSleepTolerance def b2Alloc(size): """ b2Alloc(int32 size) -> void * Implement this function to use your own memory allocator. """ return _Box2D.b2Alloc(size) def b2Free(mem): """ b2Free(void * mem) If you implement b2Alloc, you should also implement this function. """ return _Box2D.b2Free(mem) def b2Log(string): """b2Log(char const * string)""" return _Box2D.b2Log(string) class b2Version(object): """Version numbering scheme. See http://en.wikipedia.org/wiki/Software_versioning""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr major = _swig_property(_Box2D.b2Version_major_get, _Box2D.b2Version_major_set) minor = _swig_property(_Box2D.b2Version_minor_get, _Box2D.b2Version_minor_set) revision = _swig_property(_Box2D.b2Version_revision_get, _Box2D.b2Version_revision_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Version self) -> long""" return _Box2D.b2Version___hash__(self) def __repr__(self): return _format_repr(self) def __repr__(self): return "b2Version(%s.%s.%s)" % (self.major, self.minor, self.revision) def __init__(self, **kwargs): _Box2D.b2Version_swiginit(self,_Box2D.new_b2Version()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2Version b2Version.__hash__ = new_instancemethod(_Box2D.b2Version___hash__, None, b2Version) b2Version_swigregister = _Box2D.b2Version_swigregister b2Version_swigregister(b2Version) def b2IsValid(x): """ b2IsValid(float32 x) -> bool This function is used to ensure that a floating point number is not a NaN or infinity. """ return _Box2D.b2IsValid(x) def b2InvSqrt(x): """ b2InvSqrt(float32 x) -> float32 This is a approximate yet fast inverse square-root. """ return _Box2D.b2InvSqrt(x) class b2Vec2(object): """A 2D column vector.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def SetZero(self): """ SetZero(b2Vec2 self) Set this vector to all zeros. """ return _Box2D.b2Vec2_SetZero(self) def Set(self, x_, y_): """ Set(b2Vec2 self, float32 x_, float32 y_) Set this vector to some specified coordinates. """ return _Box2D.b2Vec2_Set(self, x_, y_) def __neg__(self): """__neg__(b2Vec2 self) -> b2Vec2""" return _Box2D.b2Vec2___neg__(self) def __call__(self, *args): """ __call__(b2Vec2 self, int32 i) -> float32 __call__(b2Vec2 self, int32 i) -> float32 & """ return _Box2D.b2Vec2___call__(self, *args) def __add_vector(self, v): """__add_vector(b2Vec2 self, b2Vec2 v)""" return _Box2D.b2Vec2___add_vector(self, v) def __sub_vector(self, v): """__sub_vector(b2Vec2 self, b2Vec2 v)""" return _Box2D.b2Vec2___sub_vector(self, v) def __mul_float(self, a): """__mul_float(b2Vec2 self, float32 a)""" return _Box2D.b2Vec2___mul_float(self, a) def __Length(self): """ __Length(b2Vec2 self) -> float32 Get the length of this vector (the norm). """ return _Box2D.b2Vec2___Length(self) def __LengthSquared(self): """ __LengthSquared(b2Vec2 self) -> float32 Get the length squared. For performance, use this instead of b2Vec2::Length(if possible). """ return _Box2D.b2Vec2___LengthSquared(self) def Normalize(self): """ Normalize(b2Vec2 self) -> float32 Convert this vector into a unit vector. Returns the length. """ return _Box2D.b2Vec2_Normalize(self) def __IsValid(self): """ __IsValid(b2Vec2 self) -> bool Does this vector contain finite coordinates? """ return _Box2D.b2Vec2___IsValid(self) def __Skew(self): """ __Skew(b2Vec2 self) -> b2Vec2 Get the skew vector such that dot(skew_vec, other) == cross(vec, other) """ return _Box2D.b2Vec2___Skew(self) x = _swig_property(_Box2D.b2Vec2_x_get, _Box2D.b2Vec2_x_set) y = _swig_property(_Box2D.b2Vec2_y_get, _Box2D.b2Vec2_y_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Vec2 self) -> long""" return _Box2D.b2Vec2___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, *args): """ __init__(b2Vec2 self, float32 x, float32 y) -> b2Vec2 __init__(b2Vec2 self) -> b2Vec2 __init__(b2Vec2 self, b2Vec2 other) -> b2Vec2 Construct using coordinates. """ _Box2D.b2Vec2_swiginit(self, _Box2D.new_b2Vec2(*args)) __iter__ = lambda self: iter( (self.x, self.y) ) __eq__ = lambda self, other: self.__equ(other) __ne__ = lambda self,other: not self.__equ(other) def __repr__(self): return "b2Vec2(%g,%g)" % (self.x, self.y) def __len__(self): return 2 def __neg__(self): return b2Vec2(-self.x, -self.y) def copy(self): """ Return a copy of the vector. Remember that the following: a = b2Vec2() b = a Does not copy the vector itself, but b now refers to a. """ return b2Vec2(self.x, self.y) __copy__ = copy def __iadd__(self, other): self.__add_vector(other) return self def __isub__(self, other): self.__sub_vector(other) return self def __imul__(self, a): self.__mul_float(a) return self def __itruediv__(self, a): self.__div_float(a) return self def __idiv__(self, a): self.__div_float(a) return self def __set(self, x, y): self.x = x self.y = y def __nonzero__(self): return self.x!=0.0 or self.y!=0.0 tuple = property(lambda self: (self.x, self.y), lambda self, value: self.__set(*value)) length = property(__Length, None) lengthSquared = property(__LengthSquared, None) valid = property(__IsValid, None) skew = property(__Skew, None) def cross(self, *args): """ cross(b2Vec2 self, b2Vec2 other) -> float32 cross(b2Vec2 self, float32 s) -> b2Vec2 """ return _Box2D.b2Vec2_cross(self, *args) def __getitem__(self, i): """__getitem__(b2Vec2 self, int i) -> float32""" return _Box2D.b2Vec2___getitem__(self, i) def __setitem__(self, i, value): """__setitem__(b2Vec2 self, int i, float32 value)""" return _Box2D.b2Vec2___setitem__(self, i, value) def __equ(self, other): """__equ(b2Vec2 self, b2Vec2 other) -> bool""" return _Box2D.b2Vec2___equ(self, other) def dot(self, other): """dot(b2Vec2 self, b2Vec2 other) -> float32""" return _Box2D.b2Vec2_dot(self, other) def __truediv__(self, a): """__truediv__(b2Vec2 self, float32 a) -> b2Vec2""" return _Box2D.b2Vec2___truediv__(self, a) def __div__(self, a): """__div__(b2Vec2 self, float32 a) -> b2Vec2""" return _Box2D.b2Vec2___div__(self, a) def __mul__(self, a): """__mul__(b2Vec2 self, float32 a) -> b2Vec2""" return _Box2D.b2Vec2___mul__(self, a) def __add__(self, other): """__add__(b2Vec2 self, b2Vec2 other) -> b2Vec2""" return _Box2D.b2Vec2___add__(self, other) def __sub__(self, other): """__sub__(b2Vec2 self, b2Vec2 other) -> b2Vec2""" return _Box2D.b2Vec2___sub__(self, other) def __rmul__(self, a): """__rmul__(b2Vec2 self, float32 a) -> b2Vec2""" return _Box2D.b2Vec2___rmul__(self, a) def __rdiv__(self, a): """__rdiv__(b2Vec2 self, float32 a) -> b2Vec2""" return _Box2D.b2Vec2___rdiv__(self, a) def __div_float(self, a): """__div_float(b2Vec2 self, float32 a)""" return _Box2D.b2Vec2___div_float(self, a) __swig_destroy__ = _Box2D.delete_b2Vec2 b2Vec2.SetZero = new_instancemethod(_Box2D.b2Vec2_SetZero, None, b2Vec2) b2Vec2.Set = new_instancemethod(_Box2D.b2Vec2_Set, None, b2Vec2) b2Vec2.__neg__ = new_instancemethod(_Box2D.b2Vec2___neg__, None, b2Vec2) b2Vec2.__call__ = new_instancemethod(_Box2D.b2Vec2___call__, None, b2Vec2) b2Vec2.__add_vector = new_instancemethod(_Box2D.b2Vec2___add_vector, None, b2Vec2) b2Vec2.__sub_vector = new_instancemethod(_Box2D.b2Vec2___sub_vector, None, b2Vec2) b2Vec2.__mul_float = new_instancemethod(_Box2D.b2Vec2___mul_float, None, b2Vec2) b2Vec2.__Length = new_instancemethod(_Box2D.b2Vec2___Length, None, b2Vec2) b2Vec2.__LengthSquared = new_instancemethod(_Box2D.b2Vec2___LengthSquared, None, b2Vec2) b2Vec2.Normalize = new_instancemethod(_Box2D.b2Vec2_Normalize, None, b2Vec2) b2Vec2.__IsValid = new_instancemethod(_Box2D.b2Vec2___IsValid, None, b2Vec2) b2Vec2.__Skew = new_instancemethod(_Box2D.b2Vec2___Skew, None, b2Vec2) b2Vec2.__hash__ = new_instancemethod(_Box2D.b2Vec2___hash__, None, b2Vec2) b2Vec2.cross = new_instancemethod(_Box2D.b2Vec2_cross, None, b2Vec2) b2Vec2.__getitem__ = new_instancemethod(_Box2D.b2Vec2___getitem__, None, b2Vec2) b2Vec2.__setitem__ = new_instancemethod(_Box2D.b2Vec2___setitem__, None, b2Vec2) b2Vec2.__equ = new_instancemethod(_Box2D.b2Vec2___equ, None, b2Vec2) b2Vec2.dot = new_instancemethod(_Box2D.b2Vec2_dot, None, b2Vec2) b2Vec2.__truediv__ = new_instancemethod(_Box2D.b2Vec2___truediv__, None, b2Vec2) b2Vec2.__div__ = new_instancemethod(_Box2D.b2Vec2___div__, None, b2Vec2) b2Vec2.__mul__ = new_instancemethod(_Box2D.b2Vec2___mul__, None, b2Vec2) b2Vec2.__add__ = new_instancemethod(_Box2D.b2Vec2___add__, None, b2Vec2) b2Vec2.__sub__ = new_instancemethod(_Box2D.b2Vec2___sub__, None, b2Vec2) b2Vec2.__rmul__ = new_instancemethod(_Box2D.b2Vec2___rmul__, None, b2Vec2) b2Vec2.__rdiv__ = new_instancemethod(_Box2D.b2Vec2___rdiv__, None, b2Vec2) b2Vec2.__div_float = new_instancemethod(_Box2D.b2Vec2___div_float, None, b2Vec2) b2Vec2_swigregister = _Box2D.b2Vec2_swigregister b2Vec2_swigregister(b2Vec2) class b2Vec3(object): """A 2D column vector with 3 elements.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def SetZero(self): """ SetZero(b2Vec3 self) Set this vector to all zeros. """ return _Box2D.b2Vec3_SetZero(self) def Set(self, x_, y_, z_): """ Set(b2Vec3 self, float32 x_, float32 y_, float32 z_) Set this vector to some specified coordinates. """ return _Box2D.b2Vec3_Set(self, x_, y_, z_) def __neg__(self): """__neg__(b2Vec3 self) -> b2Vec3""" return _Box2D.b2Vec3___neg__(self) def __add_vector(self, v): """__add_vector(b2Vec3 self, b2Vec3 v)""" return _Box2D.b2Vec3___add_vector(self, v) def __sub_vector(self, v): """__sub_vector(b2Vec3 self, b2Vec3 v)""" return _Box2D.b2Vec3___sub_vector(self, v) def __mul_float(self, s): """__mul_float(b2Vec3 self, float32 s)""" return _Box2D.b2Vec3___mul_float(self, s) x = _swig_property(_Box2D.b2Vec3_x_get, _Box2D.b2Vec3_x_set) y = _swig_property(_Box2D.b2Vec3_y_get, _Box2D.b2Vec3_y_set) z = _swig_property(_Box2D.b2Vec3_z_get, _Box2D.b2Vec3_z_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Vec3 self) -> long""" return _Box2D.b2Vec3___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, *args): """ __init__(b2Vec3 self, float32 x, float32 y, float32 z) -> b2Vec3 __init__(b2Vec3 self) -> b2Vec3 __init__(b2Vec3 self, b2Vec3 other) -> b2Vec3 __init__(b2Vec3 self, b2Vec2 other) -> b2Vec3 Construct using coordinates. """ _Box2D.b2Vec3_swiginit(self, _Box2D.new_b2Vec3(*args)) __iter__ = lambda self: iter( (self.x, self.y, self.z) ) __eq__ = lambda self, other: (self.x == other.x and self.y == other.y and self.z == other.z) __ne__ = lambda self, other: (self.x != other.x or self.y != other.y or self.z != other.z) def __repr__(self): return "b2Vec3(%g,%g,%g)" % (self.x, self.y, self.z) def __len__(self): return 3 def __neg__(self): return b2Vec3(-self.x, -self.y, -self.z) def copy(self): """ Return a copy of the vector. Remember that the following: a = b2Vec3() b = a Does not copy the vector itself, but b now refers to a. """ return b2Vec3(self.x, self.y, self.z) __copy__ = copy def __iadd__(self, other): self.__add_vector(other) return self def __isub__(self, other): self.__sub_vector(other) return self def __imul__(self, a): self.__mul_float(a) return self def __itruediv__(self, a): self.__div_float(a) return self def __idiv__(self, a): self.__div_float(a) return self def dot(self, v): """ Dot product with v (list/tuple or b2Vec3) """ if isinstance(v, (list, tuple)): return self.x*v[0] + self.y*v[1] + self.z*v[2] else: return self.x*v.x + self.y*v.y + self.z*v.z def __set(self, x, y, z): self.x = x self.y = y self.z = z def __nonzero__(self): return self.x!=0.0 or self.y!=0.0 or self.z!=0.0 tuple = property(lambda self: (self.x, self.y, self.z), lambda self, value: self.__set(*value)) length = property(_Box2D.b2Vec3___Length, None) lengthSquared = property(_Box2D.b2Vec3___LengthSquared, None) valid = property(_Box2D.b2Vec3___IsValid, None) def cross(self, b): """cross(b2Vec3 self, b2Vec3 b) -> b2Vec3""" return _Box2D.b2Vec3_cross(self, b) def __getitem__(self, i): """__getitem__(b2Vec3 self, int i) -> float32""" return _Box2D.b2Vec3___getitem__(self, i) def __setitem__(self, i, value): """__setitem__(b2Vec3 self, int i, float32 value)""" return _Box2D.b2Vec3___setitem__(self, i, value) def __IsValid(self): """__IsValid(b2Vec3 self) -> bool""" return _Box2D.b2Vec3___IsValid(self) def __Length(self): """__Length(b2Vec3 self) -> float32""" return _Box2D.b2Vec3___Length(self) def __LengthSquared(self): """__LengthSquared(b2Vec3 self) -> float32""" return _Box2D.b2Vec3___LengthSquared(self) def __truediv__(self, a): """__truediv__(b2Vec3 self, float32 a) -> b2Vec3""" return _Box2D.b2Vec3___truediv__(self, a) def __div__(self, a): """__div__(b2Vec3 self, float32 a) -> b2Vec3""" return _Box2D.b2Vec3___div__(self, a) def __mul__(self, a): """__mul__(b2Vec3 self, float32 a) -> b2Vec3""" return _Box2D.b2Vec3___mul__(self, a) def __add__(self, other): """__add__(b2Vec3 self, b2Vec3 other) -> b2Vec3""" return _Box2D.b2Vec3___add__(self, other) def __sub__(self, other): """__sub__(b2Vec3 self, b2Vec3 other) -> b2Vec3""" return _Box2D.b2Vec3___sub__(self, other) def __rmul__(self, a): """__rmul__(b2Vec3 self, float32 a) -> b2Vec3""" return _Box2D.b2Vec3___rmul__(self, a) def __rdiv__(self, a): """__rdiv__(b2Vec3 self, float32 a) -> b2Vec3""" return _Box2D.b2Vec3___rdiv__(self, a) def __div_float(self, a): """__div_float(b2Vec3 self, float32 a)""" return _Box2D.b2Vec3___div_float(self, a) __swig_destroy__ = _Box2D.delete_b2Vec3 b2Vec3.SetZero = new_instancemethod(_Box2D.b2Vec3_SetZero, None, b2Vec3) b2Vec3.Set = new_instancemethod(_Box2D.b2Vec3_Set, None, b2Vec3) b2Vec3.__neg__ = new_instancemethod(_Box2D.b2Vec3___neg__, None, b2Vec3) b2Vec3.__add_vector = new_instancemethod(_Box2D.b2Vec3___add_vector, None, b2Vec3) b2Vec3.__sub_vector = new_instancemethod(_Box2D.b2Vec3___sub_vector, None, b2Vec3) b2Vec3.__mul_float = new_instancemethod(_Box2D.b2Vec3___mul_float, None, b2Vec3) b2Vec3.__hash__ = new_instancemethod(_Box2D.b2Vec3___hash__, None, b2Vec3) b2Vec3.cross = new_instancemethod(_Box2D.b2Vec3_cross, None, b2Vec3) b2Vec3.__getitem__ = new_instancemethod(_Box2D.b2Vec3___getitem__, None, b2Vec3) b2Vec3.__setitem__ = new_instancemethod(_Box2D.b2Vec3___setitem__, None, b2Vec3) b2Vec3.__IsValid = new_instancemethod(_Box2D.b2Vec3___IsValid, None, b2Vec3) b2Vec3.__Length = new_instancemethod(_Box2D.b2Vec3___Length, None, b2Vec3) b2Vec3.__LengthSquared = new_instancemethod(_Box2D.b2Vec3___LengthSquared, None, b2Vec3) b2Vec3.__truediv__ = new_instancemethod(_Box2D.b2Vec3___truediv__, None, b2Vec3) b2Vec3.__div__ = new_instancemethod(_Box2D.b2Vec3___div__, None, b2Vec3) b2Vec3.__mul__ = new_instancemethod(_Box2D.b2Vec3___mul__, None, b2Vec3) b2Vec3.__add__ = new_instancemethod(_Box2D.b2Vec3___add__, None, b2Vec3) b2Vec3.__sub__ = new_instancemethod(_Box2D.b2Vec3___sub__, None, b2Vec3) b2Vec3.__rmul__ = new_instancemethod(_Box2D.b2Vec3___rmul__, None, b2Vec3) b2Vec3.__rdiv__ = new_instancemethod(_Box2D.b2Vec3___rdiv__, None, b2Vec3) b2Vec3.__div_float = new_instancemethod(_Box2D.b2Vec3___div_float, None, b2Vec3) b2Vec3_swigregister = _Box2D.b2Vec3_swigregister b2Vec3_swigregister(b2Vec3) class b2Mat22(object): """A 2-by-2 matrix. Stored in column-major order.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def SetIdentity(self): """ SetIdentity(b2Mat22 self) Set this to the identity matrix. """ return _Box2D.b2Mat22_SetIdentity(self) def SetZero(self): """ SetZero(b2Mat22 self) Set this matrix to all zeros. """ return _Box2D.b2Mat22_SetZero(self) def __GetInverse(self): """__GetInverse(b2Mat22 self) -> b2Mat22""" return _Box2D.b2Mat22___GetInverse(self) def Solve(self, b): """ Solve(b2Mat22 self, b2Vec2 b) -> b2Vec2 Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases. """ return _Box2D.b2Mat22_Solve(self, b) col1 = _swig_property(_Box2D.b2Mat22_col1_get, _Box2D.b2Mat22_col1_set) col2 = _swig_property(_Box2D.b2Mat22_col2_get, _Box2D.b2Mat22_col2_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Mat22 self) -> long""" return _Box2D.b2Mat22___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, *args): """ __init__(b2Mat22 self, b2Vec2 c1, b2Vec2 c2) -> b2Mat22 __init__(b2Mat22 self, float32 a11, float32 a12, float32 a21, float32 a22) -> b2Mat22 __init__(b2Mat22 self) -> b2Mat22 Construct this matrix using an angle. This matrix becomes an orthonormal rotation matrix. """ _Box2D.b2Mat22_swiginit(self, _Box2D.new_b2Mat22(*args)) def __GetAngle(self): """__GetAngle(b2Mat22 self) -> float32""" return _Box2D.b2Mat22___GetAngle(self) def __SetAngle(self, *args): """ __SetAngle(b2Mat22 self, b2Vec2 c1, b2Vec2 c2) __SetAngle(b2Mat22 self, float32 angle) """ return _Box2D.b2Mat22___SetAngle(self, *args) # Read-only inverse = property(__GetInverse, None) angle = property(__GetAngle, __SetAngle) ex = property(lambda self: self.col1, lambda self, v: setattr(self, 'col1', v)) ey = property(lambda self: self.col2, lambda self, v: setattr(self, 'col2', v)) set = __SetAngle def __mul__(self, *args): """ __mul__(b2Mat22 self, b2Vec2 v) -> b2Vec2 __mul__(b2Mat22 self, b2Mat22 m) -> b2Mat22 """ return _Box2D.b2Mat22___mul__(self, *args) def __add__(self, m): """__add__(b2Mat22 self, b2Mat22 m) -> b2Mat22""" return _Box2D.b2Mat22___add__(self, m) def __sub__(self, m): """__sub__(b2Mat22 self, b2Mat22 m) -> b2Mat22""" return _Box2D.b2Mat22___sub__(self, m) def __iadd(self, m): """__iadd(b2Mat22 self, b2Mat22 m)""" return _Box2D.b2Mat22___iadd(self, m) def __isub(self, m): """__isub(b2Mat22 self, b2Mat22 m)""" return _Box2D.b2Mat22___isub(self, m) __swig_destroy__ = _Box2D.delete_b2Mat22 b2Mat22.SetIdentity = new_instancemethod(_Box2D.b2Mat22_SetIdentity, None, b2Mat22) b2Mat22.SetZero = new_instancemethod(_Box2D.b2Mat22_SetZero, None, b2Mat22) b2Mat22.__GetInverse = new_instancemethod(_Box2D.b2Mat22___GetInverse, None, b2Mat22) b2Mat22.Solve = new_instancemethod(_Box2D.b2Mat22_Solve, None, b2Mat22) b2Mat22.__hash__ = new_instancemethod(_Box2D.b2Mat22___hash__, None, b2Mat22) b2Mat22.__GetAngle = new_instancemethod(_Box2D.b2Mat22___GetAngle, None, b2Mat22) b2Mat22.__SetAngle = new_instancemethod(_Box2D.b2Mat22___SetAngle, None, b2Mat22) b2Mat22.__mul__ = new_instancemethod(_Box2D.b2Mat22___mul__, None, b2Mat22) b2Mat22.__add__ = new_instancemethod(_Box2D.b2Mat22___add__, None, b2Mat22) b2Mat22.__sub__ = new_instancemethod(_Box2D.b2Mat22___sub__, None, b2Mat22) b2Mat22.__iadd = new_instancemethod(_Box2D.b2Mat22___iadd, None, b2Mat22) b2Mat22.__isub = new_instancemethod(_Box2D.b2Mat22___isub, None, b2Mat22) b2Mat22_swigregister = _Box2D.b2Mat22_swigregister b2Mat22_swigregister(b2Mat22) class b2Mat33(object): """A 3-by-3 matrix. Stored in column-major order.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def SetZero(self): """ SetZero(b2Mat33 self) Set this matrix to all zeros. """ return _Box2D.b2Mat33_SetZero(self) def Solve33(self, b): """ Solve33(b2Mat33 self, b2Vec3 b) -> b2Vec3 Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases. """ return _Box2D.b2Mat33_Solve33(self, b) def Solve22(self, b): """ Solve22(b2Mat33 self, b2Vec2 b) -> b2Vec2 Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases. Solve only the upper 2-by-2 matrix equation. """ return _Box2D.b2Mat33_Solve22(self, b) def GetInverse22(self, M): """GetInverse22(b2Mat33 self, b2Mat33 M)""" return _Box2D.b2Mat33_GetInverse22(self, M) def GetSymInverse33(self, M): """GetSymInverse33(b2Mat33 self, b2Mat33 M)""" return _Box2D.b2Mat33_GetSymInverse33(self, M) col1 = _swig_property(_Box2D.b2Mat33_col1_get, _Box2D.b2Mat33_col1_set) col2 = _swig_property(_Box2D.b2Mat33_col2_get, _Box2D.b2Mat33_col2_set) col3 = _swig_property(_Box2D.b2Mat33_col3_get, _Box2D.b2Mat33_col3_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Mat33 self) -> long""" return _Box2D.b2Mat33___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, *args): """ __init__(b2Mat33 self, b2Vec3 c1, b2Vec3 c2, b2Vec3 c3) -> b2Mat33 __init__(b2Mat33 self) -> b2Mat33 Construct this matrix using columns. """ _Box2D.b2Mat33_swiginit(self, _Box2D.new_b2Mat33(*args)) ex = property(lambda self: self.col1, lambda self, v: setattr(self, 'col1', v)) ey = property(lambda self: self.col2, lambda self, v: setattr(self, 'col2', v)) ez = property(lambda self: self.col3, lambda self, v: setattr(self, 'col3', v)) def __mul__(self, v): """__mul__(b2Mat33 self, b2Vec3 v) -> b2Vec3""" return _Box2D.b2Mat33___mul__(self, v) def __add__(self, other): """__add__(b2Mat33 self, b2Mat33 other) -> b2Mat33""" return _Box2D.b2Mat33___add__(self, other) def __sub__(self, other): """__sub__(b2Mat33 self, b2Mat33 other) -> b2Mat33""" return _Box2D.b2Mat33___sub__(self, other) def __iadd(self, other): """__iadd(b2Mat33 self, b2Mat33 other)""" return _Box2D.b2Mat33___iadd(self, other) def __isub(self, other): """__isub(b2Mat33 self, b2Mat33 other)""" return _Box2D.b2Mat33___isub(self, other) __swig_destroy__ = _Box2D.delete_b2Mat33 b2Mat33.SetZero = new_instancemethod(_Box2D.b2Mat33_SetZero, None, b2Mat33) b2Mat33.Solve33 = new_instancemethod(_Box2D.b2Mat33_Solve33, None, b2Mat33) b2Mat33.Solve22 = new_instancemethod(_Box2D.b2Mat33_Solve22, None, b2Mat33) b2Mat33.GetInverse22 = new_instancemethod(_Box2D.b2Mat33_GetInverse22, None, b2Mat33) b2Mat33.GetSymInverse33 = new_instancemethod(_Box2D.b2Mat33_GetSymInverse33, None, b2Mat33) b2Mat33.__hash__ = new_instancemethod(_Box2D.b2Mat33___hash__, None, b2Mat33) b2Mat33.__mul__ = new_instancemethod(_Box2D.b2Mat33___mul__, None, b2Mat33) b2Mat33.__add__ = new_instancemethod(_Box2D.b2Mat33___add__, None, b2Mat33) b2Mat33.__sub__ = new_instancemethod(_Box2D.b2Mat33___sub__, None, b2Mat33) b2Mat33.__iadd = new_instancemethod(_Box2D.b2Mat33___iadd, None, b2Mat33) b2Mat33.__isub = new_instancemethod(_Box2D.b2Mat33___isub, None, b2Mat33) b2Mat33_swigregister = _Box2D.b2Mat33_swigregister b2Mat33_swigregister(b2Mat33) class b2Rot(object): """Proxy of C++ b2Rot class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, *args): """ __init__(b2Rot self) -> b2Rot __init__(b2Rot self, float32 angle) -> b2Rot """ _Box2D.b2Rot_swiginit(self, _Box2D.new_b2Rot(*args)) def __SetAngle(self, angle): """__SetAngle(b2Rot self, float32 angle)""" return _Box2D.b2Rot___SetAngle(self, angle) def SetIdentity(self): """SetIdentity(b2Rot self)""" return _Box2D.b2Rot_SetIdentity(self) def __GetAngle(self): """__GetAngle(b2Rot self) -> float32""" return _Box2D.b2Rot___GetAngle(self) def GetXAxis(self): """GetXAxis(b2Rot self) -> b2Vec2""" return _Box2D.b2Rot_GetXAxis(self) def GetYAxis(self): """GetYAxis(b2Rot self) -> b2Vec2""" return _Box2D.b2Rot_GetYAxis(self) s = _swig_property(_Box2D.b2Rot_s_get, _Box2D.b2Rot_s_set) c = _swig_property(_Box2D.b2Rot_c_get, _Box2D.b2Rot_c_set) angle = property(__GetAngle, __SetAngle) x_axis = property(GetXAxis, None) y_axis = property(GetYAxis, None) def __mul__(self, v): """__mul__(b2Rot self, b2Vec2 v) -> b2Vec2""" return _Box2D.b2Rot___mul__(self, v) __swig_destroy__ = _Box2D.delete_b2Rot b2Rot.__SetAngle = new_instancemethod(_Box2D.b2Rot___SetAngle, None, b2Rot) b2Rot.SetIdentity = new_instancemethod(_Box2D.b2Rot_SetIdentity, None, b2Rot) b2Rot.__GetAngle = new_instancemethod(_Box2D.b2Rot___GetAngle, None, b2Rot) b2Rot.GetXAxis = new_instancemethod(_Box2D.b2Rot_GetXAxis, None, b2Rot) b2Rot.GetYAxis = new_instancemethod(_Box2D.b2Rot_GetYAxis, None, b2Rot) b2Rot.__mul__ = new_instancemethod(_Box2D.b2Rot___mul__, None, b2Rot) b2Rot_swigregister = _Box2D.b2Rot_swigregister b2Rot_swigregister(b2Rot) class b2Transform(object): """A transform contains translation and rotation. It is used to represent the position and orientation of rigid frames.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, *args): """ __init__(b2Transform self) -> b2Transform __init__(b2Transform self, b2Vec2 position, b2Rot rotation) -> b2Transform Initialize using a position vector and a rotation matrix. """ _Box2D.b2Transform_swiginit(self, _Box2D.new_b2Transform(*args)) def SetIdentity(self): """ SetIdentity(b2Transform self) Set this to the identity transform. """ return _Box2D.b2Transform_SetIdentity(self) def Set(self, position, angle): """ Set(b2Transform self, b2Vec2 position, float32 angle) Set this based on the position and angle. """ return _Box2D.b2Transform_Set(self, position, angle) position = _swig_property(_Box2D.b2Transform_position_get, _Box2D.b2Transform_position_set) q = _swig_property(_Box2D.b2Transform_q_get, _Box2D.b2Transform_q_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Transform self) -> long""" return _Box2D.b2Transform___hash__(self) def __repr__(self): return _format_repr(self) def __get_rotation_matrix(self): """__get_rotation_matrix(b2Transform self) -> b2Rot""" return _Box2D.b2Transform___get_rotation_matrix(self) def __get_angle(self): return self.q.angle def __set_angle(self, angle): self.q.angle = angle def __set_rotation_matrix(self, rot_matrix): self.q.angle = rot_matrix.angle angle = property(__get_angle, __set_angle) R = property(__get_rotation_matrix, __set_rotation_matrix) def __mul__(self, v): """__mul__(b2Transform self, b2Vec2 v) -> b2Vec2""" return _Box2D.b2Transform___mul__(self, v) __swig_destroy__ = _Box2D.delete_b2Transform b2Transform.SetIdentity = new_instancemethod(_Box2D.b2Transform_SetIdentity, None, b2Transform) b2Transform.Set = new_instancemethod(_Box2D.b2Transform_Set, None, b2Transform) b2Transform.__hash__ = new_instancemethod(_Box2D.b2Transform___hash__, None, b2Transform) b2Transform.__get_rotation_matrix = new_instancemethod(_Box2D.b2Transform___get_rotation_matrix, None, b2Transform) b2Transform.__mul__ = new_instancemethod(_Box2D.b2Transform___mul__, None, b2Transform) b2Transform_swigregister = _Box2D.b2Transform_swigregister b2Transform_swigregister(b2Transform) class b2Sweep(object): """This describes the motion of a body/shape for TOI computation. Shapes are defined with respect to the body origin, which may no coincide with the center of mass. However, to support dynamics we must interpolate the center of mass position.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def Advance(self, alpha): """ Advance(b2Sweep self, float32 alpha) Advance the sweep forward, yielding a new initial state. Parameters: ----------- alpha: the new initial time. """ return _Box2D.b2Sweep_Advance(self, alpha) def Normalize(self): """ Normalize(b2Sweep self) Normalize the angles. """ return _Box2D.b2Sweep_Normalize(self) localCenter = _swig_property(_Box2D.b2Sweep_localCenter_get, _Box2D.b2Sweep_localCenter_set) c0 = _swig_property(_Box2D.b2Sweep_c0_get, _Box2D.b2Sweep_c0_set) c = _swig_property(_Box2D.b2Sweep_c_get, _Box2D.b2Sweep_c_set) a0 = _swig_property(_Box2D.b2Sweep_a0_get, _Box2D.b2Sweep_a0_set) a = _swig_property(_Box2D.b2Sweep_a_get, _Box2D.b2Sweep_a_set) alpha0 = _swig_property(_Box2D.b2Sweep_alpha0_get, _Box2D.b2Sweep_alpha0_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Sweep self) -> long""" return _Box2D.b2Sweep___hash__(self) def __repr__(self): return _format_repr(self) def GetTransform(self, *args): """ GetTransform(b2Sweep self, b2Transform xfb, float32 beta) GetTransform(b2Sweep self, float32 alpha) -> b2Transform Get the interpolated transform at a specific time. Parameters: ----------- beta: is a factor in [0,1], where 0 indicates alpha0. """ return _Box2D.b2Sweep_GetTransform(self, *args) def __init__(self, **kwargs): _Box2D.b2Sweep_swiginit(self,_Box2D.new_b2Sweep()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2Sweep b2Sweep.Advance = new_instancemethod(_Box2D.b2Sweep_Advance, None, b2Sweep) b2Sweep.Normalize = new_instancemethod(_Box2D.b2Sweep_Normalize, None, b2Sweep) b2Sweep.__hash__ = new_instancemethod(_Box2D.b2Sweep___hash__, None, b2Sweep) b2Sweep.GetTransform = new_instancemethod(_Box2D.b2Sweep_GetTransform, None, b2Sweep) b2Sweep_swigregister = _Box2D.b2Sweep_swigregister b2Sweep_swigregister(b2Sweep) def b2DistanceSquared(a, b): """b2DistanceSquared(b2Vec2 a, b2Vec2 b) -> float32""" return _Box2D.b2DistanceSquared(a, b) def b2Dot(*args): """ b2Dot(b2Vec2 a, b2Vec2 b) -> float32 b2Dot(b2Vec3 a, b2Vec3 b) -> float32 Perform the dot product on two vectors. """ return _Box2D.b2Dot(*args) def b2Cross(*args): """ b2Cross(b2Vec2 a, b2Vec2 b) -> float32 b2Cross(b2Vec2 a, float32 s) -> b2Vec2 b2Cross(float32 s, b2Vec2 a) -> b2Vec2 b2Cross(b2Vec3 a, b2Vec3 b) -> b2Vec3 Perform the cross product on two vectors. """ return _Box2D.b2Cross(*args) def b2Mul22(A, v): """b2Mul22(b2Mat33 A, b2Vec2 v) -> b2Vec2""" return _Box2D.b2Mul22(A, v) def b2Mul(*args): """ b2Mul(b2Mat22 A, b2Vec2 v) -> b2Vec2 b2Mul(b2Mat22 A, b2Mat22 B) -> b2Mat22 b2Mul(b2Mat33 A, b2Vec3 v) -> b2Vec3 b2Mul(b2Rot q, b2Rot r) -> b2Rot b2Mul(b2Rot q, b2Vec2 v) -> b2Vec2 b2Mul(b2Transform T, b2Vec2 v) -> b2Vec2 b2Mul(b2Transform A, b2Transform B) -> b2Transform Multiply a matrix times a vector. """ return _Box2D.b2Mul(*args) def b2MulT(*args): """ b2MulT(b2Mat22 A, b2Vec2 v) -> b2Vec2 b2MulT(b2Mat22 A, b2Mat22 B) -> b2Mat22 b2MulT(b2Rot q, b2Rot r) -> b2Rot b2MulT(b2Rot q, b2Vec2 v) -> b2Vec2 b2MulT(b2Transform T, b2Vec2 v) -> b2Vec2 b2MulT(b2Transform A, b2Transform B) -> b2Transform Multiply a matrix transpose times a vector. If a rotation matrix is provided, then this transforms the vector from one frame to another (inverse transform). """ return _Box2D.b2MulT(*args) def b2Abs(*args): """ b2Abs(b2Vec2 a) -> b2Vec2 b2Abs(b2Mat22 A) -> b2Mat22 """ return _Box2D.b2Abs(*args) def b2Min(a, b): """b2Min(b2Vec2 a, b2Vec2 b) -> b2Vec2""" return _Box2D.b2Min(a, b) def b2Max(a, b): """b2Max(b2Vec2 a, b2Vec2 b) -> b2Vec2""" return _Box2D.b2Max(a, b) def b2Clamp(a, low, high): """b2Clamp(b2Vec2 a, b2Vec2 low, b2Vec2 high) -> b2Vec2""" return _Box2D.b2Clamp(a, low, high) def b2NextPowerOfTwo(x): """ b2NextPowerOfTwo(uint32 x) -> uint32 "Next Largest Power of 2 Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next largest power of 2. For a 32-bit value:" """ return _Box2D.b2NextPowerOfTwo(x) def b2IsPowerOfTwo(x): """b2IsPowerOfTwo(uint32 x) -> bool""" return _Box2D.b2IsPowerOfTwo(x) class b2ContactFeature(object): """The features that intersect to form the contact point This must be 4 bytes or less.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr e_vertex = _Box2D.b2ContactFeature_e_vertex e_face = _Box2D.b2ContactFeature_e_face indexA = _swig_property(_Box2D.b2ContactFeature_indexA_get, _Box2D.b2ContactFeature_indexA_set) indexB = _swig_property(_Box2D.b2ContactFeature_indexB_get, _Box2D.b2ContactFeature_indexB_set) typeA = _swig_property(_Box2D.b2ContactFeature_typeA_get, _Box2D.b2ContactFeature_typeA_set) typeB = _swig_property(_Box2D.b2ContactFeature_typeB_get, _Box2D.b2ContactFeature_typeB_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ContactFeature self) -> long""" return _Box2D.b2ContactFeature___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self): """ __init__(b2ContactFeature self) -> b2ContactFeature The features that intersect to form the contact point This must be 4 bytes or less. """ _Box2D.b2ContactFeature_swiginit(self, _Box2D.new_b2ContactFeature()) __swig_destroy__ = _Box2D.delete_b2ContactFeature b2ContactFeature.__hash__ = new_instancemethod(_Box2D.b2ContactFeature___hash__, None, b2ContactFeature) b2ContactFeature_swigregister = _Box2D.b2ContactFeature_swigregister b2ContactFeature_swigregister(b2ContactFeature) b2Vec2_zero = b2Globals.b2Vec2_zero b2_nullFeature = b2Globals.b2_nullFeature class b2ContactID(object): """Proxy of C++ b2ContactID class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr cf = _swig_property(_Box2D.b2ContactID_cf_get, _Box2D.b2ContactID_cf_set) key = _swig_property(_Box2D.b2ContactID_key_get, _Box2D.b2ContactID_key_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ContactID self) -> long""" return _Box2D.b2ContactID___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2ContactID_swiginit(self,_Box2D.new_b2ContactID()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2ContactID b2ContactID.__hash__ = new_instancemethod(_Box2D.b2ContactID___hash__, None, b2ContactID) b2ContactID_swigregister = _Box2D.b2ContactID_swigregister b2ContactID_swigregister(b2ContactID) class b2ManifoldPoint(object): """A manifold point is a contact point belonging to a contact manifold. It holds details related to the geometry and dynamics of the contact points. The local point usage depends on the manifold type: -e_circles: the local center of circleB -e_faceA: the local center of cirlceB or the clip point of polygonB -e_faceB: the clip point of polygonA This structure is stored across time steps, so we keep it small. Note: the impulses are used for internal caching and may not provide reliable contact forces, especially for high speed collisions.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr localPoint = _swig_property(_Box2D.b2ManifoldPoint_localPoint_get, _Box2D.b2ManifoldPoint_localPoint_set) normalImpulse = _swig_property(_Box2D.b2ManifoldPoint_normalImpulse_get, _Box2D.b2ManifoldPoint_normalImpulse_set) tangentImpulse = _swig_property(_Box2D.b2ManifoldPoint_tangentImpulse_get, _Box2D.b2ManifoldPoint_tangentImpulse_set) id = _swig_property(_Box2D.b2ManifoldPoint_id_get, _Box2D.b2ManifoldPoint_id_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ManifoldPoint self) -> long""" return _Box2D.b2ManifoldPoint___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2ManifoldPoint_swiginit(self,_Box2D.new_b2ManifoldPoint()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2ManifoldPoint b2ManifoldPoint.__hash__ = new_instancemethod(_Box2D.b2ManifoldPoint___hash__, None, b2ManifoldPoint) b2ManifoldPoint_swigregister = _Box2D.b2ManifoldPoint_swigregister b2ManifoldPoint_swigregister(b2ManifoldPoint) class b2Manifold(object): """ A manifold for two touching convex shapes. Box2D supports multiple types of contact: clip point versus plane with radius point versus point with radius (circles) The local point usage depends on the manifold type: -e_circles: the local center of circleA -e_faceA: the center of faceA -e_faceB: the center of faceB Similarly the local normal usage: -e_circles: not used -e_faceA: the normal on polygonA -e_faceB: the normal on polygonB We store contacts in this way so that position correction can account for movement, which is critical for continuous physics. All contact scenarios must be expressed in one of these types. This structure is stored across time steps, so we keep it small. """ thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr e_circles = _Box2D.b2Manifold_e_circles e_faceA = _Box2D.b2Manifold_e_faceA e_faceB = _Box2D.b2Manifold_e_faceB localNormal = _swig_property(_Box2D.b2Manifold_localNormal_get, _Box2D.b2Manifold_localNormal_set) localPoint = _swig_property(_Box2D.b2Manifold_localPoint_get, _Box2D.b2Manifold_localPoint_set) type_ = _swig_property(_Box2D.b2Manifold_type__get, _Box2D.b2Manifold_type__set) pointCount = _swig_property(_Box2D.b2Manifold_pointCount_get, _Box2D.b2Manifold_pointCount_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Manifold self) -> long""" return _Box2D.b2Manifold___hash__(self) def __repr__(self): return _format_repr(self) def __GetPoints(self): return [self.__GetPoint(i) for i in range(self.pointCount)] points = property(__GetPoints, None) def __GetPoint(self, i): """__GetPoint(b2Manifold self, int i) -> b2ManifoldPoint""" return _Box2D.b2Manifold___GetPoint(self, i) def __init__(self, **kwargs): _Box2D.b2Manifold_swiginit(self,_Box2D.new_b2Manifold()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2Manifold b2Manifold.__hash__ = new_instancemethod(_Box2D.b2Manifold___hash__, None, b2Manifold) b2Manifold.__GetPoint = new_instancemethod(_Box2D.b2Manifold___GetPoint, None, b2Manifold) b2Manifold_swigregister = _Box2D.b2Manifold_swigregister b2Manifold_swigregister(b2Manifold) class b2WorldManifold(object): """This is used to compute the current state of a contact manifold.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def Initialize(self, manifold, xfA, radiusA, xfB, radiusB): """ Initialize(b2WorldManifold self, b2Manifold manifold, b2Transform xfA, float32 radiusA, b2Transform xfB, float32 radiusB) Evaluate the manifold with supplied transforms. This assumes modest motion from the original state. This does not change the point count, impulses, etc. The radii must come from the shapes that generated the manifold. """ return _Box2D.b2WorldManifold_Initialize(self, manifold, xfA, radiusA, xfB, radiusB) normal = _swig_property(_Box2D.b2WorldManifold_normal_get, _Box2D.b2WorldManifold_normal_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2WorldManifold self) -> long""" return _Box2D.b2WorldManifold___hash__(self) def __repr__(self): return _format_repr(self) def __get_points(self): """__get_points(b2WorldManifold self) -> PyObject *""" return _Box2D.b2WorldManifold___get_points(self) points = property(__get_points, None) def __init__(self, **kwargs): _Box2D.b2WorldManifold_swiginit(self,_Box2D.new_b2WorldManifold()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2WorldManifold b2WorldManifold.Initialize = new_instancemethod(_Box2D.b2WorldManifold_Initialize, None, b2WorldManifold) b2WorldManifold.__hash__ = new_instancemethod(_Box2D.b2WorldManifold___hash__, None, b2WorldManifold) b2WorldManifold.__get_points = new_instancemethod(_Box2D.b2WorldManifold___get_points, None, b2WorldManifold) b2WorldManifold_swigregister = _Box2D.b2WorldManifold_swigregister b2WorldManifold_swigregister(b2WorldManifold) _Box2D.b2_nullState_swigconstant(_Box2D) b2_nullState = _Box2D.b2_nullState _Box2D.b2_addState_swigconstant(_Box2D) b2_addState = _Box2D.b2_addState _Box2D.b2_persistState_swigconstant(_Box2D) b2_persistState = _Box2D.b2_persistState _Box2D.b2_removeState_swigconstant(_Box2D) b2_removeState = _Box2D.b2_removeState class b2ClipVertex(object): """Used for computing contact manifolds.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr v = _swig_property(_Box2D.b2ClipVertex_v_get, _Box2D.b2ClipVertex_v_set) id = _swig_property(_Box2D.b2ClipVertex_id_get, _Box2D.b2ClipVertex_id_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ClipVertex self) -> long""" return _Box2D.b2ClipVertex___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2ClipVertex_swiginit(self,_Box2D.new_b2ClipVertex()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2ClipVertex b2ClipVertex.__hash__ = new_instancemethod(_Box2D.b2ClipVertex___hash__, None, b2ClipVertex) b2ClipVertex_swigregister = _Box2D.b2ClipVertex_swigregister b2ClipVertex_swigregister(b2ClipVertex) class b2RayCastInput(object): """Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr p1 = _swig_property(_Box2D.b2RayCastInput_p1_get, _Box2D.b2RayCastInput_p1_set) p2 = _swig_property(_Box2D.b2RayCastInput_p2_get, _Box2D.b2RayCastInput_p2_set) maxFraction = _swig_property(_Box2D.b2RayCastInput_maxFraction_get, _Box2D.b2RayCastInput_maxFraction_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2RayCastInput self) -> long""" return _Box2D.b2RayCastInput___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2RayCastInput_swiginit(self,_Box2D.new_b2RayCastInput()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2RayCastInput b2RayCastInput.__hash__ = new_instancemethod(_Box2D.b2RayCastInput___hash__, None, b2RayCastInput) b2RayCastInput_swigregister = _Box2D.b2RayCastInput_swigregister b2RayCastInput_swigregister(b2RayCastInput) class b2RayCastOutput(object): """Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 come from b2RayCastInput.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr normal = _swig_property(_Box2D.b2RayCastOutput_normal_get, _Box2D.b2RayCastOutput_normal_set) fraction = _swig_property(_Box2D.b2RayCastOutput_fraction_get, _Box2D.b2RayCastOutput_fraction_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2RayCastOutput self) -> long""" return _Box2D.b2RayCastOutput___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2RayCastOutput_swiginit(self,_Box2D.new_b2RayCastOutput()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2RayCastOutput b2RayCastOutput.__hash__ = new_instancemethod(_Box2D.b2RayCastOutput___hash__, None, b2RayCastOutput) b2RayCastOutput_swigregister = _Box2D.b2RayCastOutput_swigregister b2RayCastOutput_swigregister(b2RayCastOutput) class b2AABB(object): """An axis aligned bounding box.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __IsValid(self): """ __IsValid(b2AABB self) -> bool Verify that the bounds are sorted. """ return _Box2D.b2AABB___IsValid(self) def __GetCenter(self): """ __GetCenter(b2AABB self) -> b2Vec2 Get the center of the AABB. """ return _Box2D.b2AABB___GetCenter(self) def __GetExtents(self): """ __GetExtents(b2AABB self) -> b2Vec2 Get the extents of the AABB (half-widths). """ return _Box2D.b2AABB___GetExtents(self) def __GetPerimeter(self): """ __GetPerimeter(b2AABB self) -> float32 Get the perimeter length. """ return _Box2D.b2AABB___GetPerimeter(self) def Combine(self, *args): """ Combine(b2AABB self, b2AABB aabb) Combine(b2AABB self, b2AABB aabb1, b2AABB aabb2) Combine two AABBs into this one. """ return _Box2D.b2AABB_Combine(self, *args) def RayCast(self, output, input): """RayCast(b2AABB self, b2RayCastOutput output, b2RayCastInput input) -> bool""" return _Box2D.b2AABB_RayCast(self, output, input) lowerBound = _swig_property(_Box2D.b2AABB_lowerBound_get, _Box2D.b2AABB_lowerBound_set) upperBound = _swig_property(_Box2D.b2AABB_upperBound_get, _Box2D.b2AABB_upperBound_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2AABB self) -> long""" return _Box2D.b2AABB___hash__(self) def __repr__(self): return _format_repr(self) # Read-only valid = property(__IsValid, None) extents = property(__GetExtents, None) center = property(__GetCenter, None) perimeter = property(__GetPerimeter, None) def __contains__(self, *args): """ __contains__(b2AABB self, b2AABB aabb) -> bool __contains__(b2AABB self, b2Vec2 point) -> bool """ return _Box2D.b2AABB___contains__(self, *args) def overlaps(self, aabb2): """overlaps(b2AABB self, b2AABB aabb2) -> bool""" return _Box2D.b2AABB_overlaps(self, aabb2) def __init__(self, **kwargs): _Box2D.b2AABB_swiginit(self,_Box2D.new_b2AABB()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2AABB b2AABB.__IsValid = new_instancemethod(_Box2D.b2AABB___IsValid, None, b2AABB) b2AABB.__GetCenter = new_instancemethod(_Box2D.b2AABB___GetCenter, None, b2AABB) b2AABB.__GetExtents = new_instancemethod(_Box2D.b2AABB___GetExtents, None, b2AABB) b2AABB.__GetPerimeter = new_instancemethod(_Box2D.b2AABB___GetPerimeter, None, b2AABB) b2AABB.Combine = new_instancemethod(_Box2D.b2AABB_Combine, None, b2AABB) b2AABB.RayCast = new_instancemethod(_Box2D.b2AABB_RayCast, None, b2AABB) b2AABB.__hash__ = new_instancemethod(_Box2D.b2AABB___hash__, None, b2AABB) b2AABB.__contains__ = new_instancemethod(_Box2D.b2AABB___contains__, None, b2AABB) b2AABB.overlaps = new_instancemethod(_Box2D.b2AABB_overlaps, None, b2AABB) b2AABB_swigregister = _Box2D.b2AABB_swigregister b2AABB_swigregister(b2AABB) def b2CollideCircles(manifold, circleA, xfA, circleB, xfB): """ b2CollideCircles(b2Manifold manifold, b2CircleShape circleA, b2Transform xfA, b2CircleShape circleB, b2Transform xfB) Compute the collision manifold between two circles. """ return _Box2D.b2CollideCircles(manifold, circleA, xfA, circleB, xfB) def b2CollidePolygonAndCircle(manifold, polygonA, xfA, circleB, xfB): """ b2CollidePolygonAndCircle(b2Manifold manifold, b2PolygonShape polygonA, b2Transform xfA, b2CircleShape circleB, b2Transform xfB) Compute the collision manifold between a polygon and a circle. """ return _Box2D.b2CollidePolygonAndCircle(manifold, polygonA, xfA, circleB, xfB) def b2CollidePolygons(manifold, polygonA, xfA, polygonB, xfB): """ b2CollidePolygons(b2Manifold manifold, b2PolygonShape polygonA, b2Transform xfA, b2PolygonShape polygonB, b2Transform xfB) Compute the collision manifold between two polygons. """ return _Box2D.b2CollidePolygons(manifold, polygonA, xfA, polygonB, xfB) def b2CollideEdgeAndCircle(manifold, polygonA, xfA, circleB, xfB): """ b2CollideEdgeAndCircle(b2Manifold manifold, b2EdgeShape polygonA, b2Transform xfA, b2CircleShape circleB, b2Transform xfB) Compute the collision manifold between an edge and a circle. """ return _Box2D.b2CollideEdgeAndCircle(manifold, polygonA, xfA, circleB, xfB) def b2CollideEdgeAndPolygon(manifold, edgeA, xfA, circleB, xfB): """ b2CollideEdgeAndPolygon(b2Manifold manifold, b2EdgeShape edgeA, b2Transform xfA, b2PolygonShape circleB, b2Transform xfB) Compute the collision manifold between an edge and a circle. """ return _Box2D.b2CollideEdgeAndPolygon(manifold, edgeA, xfA, circleB, xfB) def b2ClipSegmentToLine(vOut, vIn, normal, offset, vertexIndexA): """ b2ClipSegmentToLine(b2ClipVertex vOut, b2ClipVertex vIn, b2Vec2 normal, float32 offset, int32 vertexIndexA) -> int32 Clipping for contact manifolds. """ return _Box2D.b2ClipSegmentToLine(vOut, vIn, normal, offset, vertexIndexA) def b2TestOverlap(*args): """ b2TestOverlap(b2Shape shapeA, int32 indexA, b2Shape shapeB, int32 indexB, b2Transform xfA, b2Transform xfB) -> bool b2TestOverlap(b2AABB a, b2AABB b) -> bool Determine if two generic shapes overlap. """ return _Box2D.b2TestOverlap(*args) class _b2Vec2Array(object): """Proxy of C++ _b2Vec2Array class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, nelements): """__init__(_b2Vec2Array self, size_t nelements) -> _b2Vec2Array""" _Box2D._b2Vec2Array_swiginit(self, _Box2D.new__b2Vec2Array(nelements)) __swig_destroy__ = _Box2D.delete__b2Vec2Array def __getitem__(self, index): """__getitem__(_b2Vec2Array self, size_t index) -> b2Vec2""" return _Box2D._b2Vec2Array___getitem__(self, index) def __setitem__(self, index, value): """__setitem__(_b2Vec2Array self, size_t index, b2Vec2 value)""" return _Box2D._b2Vec2Array___setitem__(self, index, value) def cast(self): """cast(_b2Vec2Array self) -> b2Vec2""" return _Box2D._b2Vec2Array_cast(self) def frompointer(t): """frompointer(b2Vec2 t) -> _b2Vec2Array""" return _Box2D._b2Vec2Array_frompointer(t) frompointer = staticmethod(frompointer) _b2Vec2Array.__getitem__ = new_instancemethod(_Box2D._b2Vec2Array___getitem__, None, _b2Vec2Array) _b2Vec2Array.__setitem__ = new_instancemethod(_Box2D._b2Vec2Array___setitem__, None, _b2Vec2Array) _b2Vec2Array.cast = new_instancemethod(_Box2D._b2Vec2Array_cast, None, _b2Vec2Array) _b2Vec2Array_swigregister = _Box2D._b2Vec2Array_swigregister _b2Vec2Array_swigregister(_b2Vec2Array) def _b2Vec2Array_frompointer(t): """_b2Vec2Array_frompointer(b2Vec2 t) -> _b2Vec2Array""" return _Box2D._b2Vec2Array_frompointer(t) _Box2D.e_convertVertices_swigconstant(_Box2D) e_convertVertices = _Box2D.e_convertVertices class b2Color(object): """Color for debug drawing. Each value has the range [0,1].""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def Set(self, ri, gi, bi): """Set(b2Color self, float32 ri, float32 gi, float32 bi)""" return _Box2D.b2Color_Set(self, ri, gi, bi) r = _swig_property(_Box2D.b2Color_r_get, _Box2D.b2Color_r_set) g = _swig_property(_Box2D.b2Color_g_get, _Box2D.b2Color_g_set) b = _swig_property(_Box2D.b2Color_b_get, _Box2D.b2Color_b_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Color self) -> long""" return _Box2D.b2Color___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, *args): """ __init__(b2Color self) -> b2Color __init__(b2Color self, float32 r, float32 g, float32 b) -> b2Color __init__(b2Color self, b2Color other) -> b2Color Color for debug drawing. Each value has the range [0,1]. """ _Box2D.b2Color_swiginit(self, _Box2D.new_b2Color(*args)) def __get_bytes(self): """__get_bytes(b2Color self) -> PyObject *""" return _Box2D.b2Color___get_bytes(self) __iter__ = lambda self: iter((self.r, self.g, self.b)) __eq__ = lambda self, other: self.__equ(other) __ne__ = lambda self,other: not self.__equ(other) def __repr__(self): return "b2Color(%g,%g,%g)" % (self.r, self.g, self.b) def __len__(self): return 3 def __copy__(self): return b2Color(self.r, self.g, self.b) def copy(self): return b2Color(self.r, self.g, self.b) def __set_bytes(self, value): if len(value) != 3: raise ValueError('Expected length 3 list') self.r, self.g, self.b = value[0]/255, value[1]/255, value[2]/255 def __set_tuple(self, value): if len(value) != 3: raise ValueError('Expected length 3 list') self.r, self.g, self.b = value[0], value[1], value[2] def __nonzero__(self): return self.r!=0.0 or self.g!=0.0 or self.b!=0.0 list = property(lambda self: list(self), __set_tuple) bytes = property(__get_bytes, __set_bytes) def __getitem__(self, i): """__getitem__(b2Color self, int i) -> float32""" return _Box2D.b2Color___getitem__(self, i) def __setitem__(self, i, value): """__setitem__(b2Color self, int i, float32 value)""" return _Box2D.b2Color___setitem__(self, i, value) def __truediv__(self, a): """__truediv__(b2Color self, float32 a) -> b2Color""" return _Box2D.b2Color___truediv__(self, a) def __add__(self, o): """__add__(b2Color self, b2Color o) -> b2Color""" return _Box2D.b2Color___add__(self, o) def __sub__(self, o): """__sub__(b2Color self, b2Color o) -> b2Color""" return _Box2D.b2Color___sub__(self, o) def __div__(self, a): """__div__(b2Color self, float32 a) -> b2Color""" return _Box2D.b2Color___div__(self, a) def __rmul__(self, a): """__rmul__(b2Color self, float32 a) -> b2Color""" return _Box2D.b2Color___rmul__(self, a) def __mul__(self, a): """__mul__(b2Color self, float32 a) -> b2Color""" return _Box2D.b2Color___mul__(self, a) def __isub(self, o): """__isub(b2Color self, b2Color o)""" return _Box2D.b2Color___isub(self, o) def __itruediv(self, o): """__itruediv(b2Color self, b2Color o)""" return _Box2D.b2Color___itruediv(self, o) def __idiv(self, o): """__idiv(b2Color self, b2Color o)""" return _Box2D.b2Color___idiv(self, o) def __imul(self, o): """__imul(b2Color self, b2Color o)""" return _Box2D.b2Color___imul(self, o) def __iadd(self, o): """__iadd(b2Color self, b2Color o)""" return _Box2D.b2Color___iadd(self, o) def __equ(self, b): """__equ(b2Color self, b2Color b) -> bool""" return _Box2D.b2Color___equ(self, b) __swig_destroy__ = _Box2D.delete_b2Color b2Color.Set = new_instancemethod(_Box2D.b2Color_Set, None, b2Color) b2Color.__hash__ = new_instancemethod(_Box2D.b2Color___hash__, None, b2Color) b2Color.__get_bytes = new_instancemethod(_Box2D.b2Color___get_bytes, None, b2Color) b2Color.__getitem__ = new_instancemethod(_Box2D.b2Color___getitem__, None, b2Color) b2Color.__setitem__ = new_instancemethod(_Box2D.b2Color___setitem__, None, b2Color) b2Color.__truediv__ = new_instancemethod(_Box2D.b2Color___truediv__, None, b2Color) b2Color.__add__ = new_instancemethod(_Box2D.b2Color___add__, None, b2Color) b2Color.__sub__ = new_instancemethod(_Box2D.b2Color___sub__, None, b2Color) b2Color.__div__ = new_instancemethod(_Box2D.b2Color___div__, None, b2Color) b2Color.__rmul__ = new_instancemethod(_Box2D.b2Color___rmul__, None, b2Color) b2Color.__mul__ = new_instancemethod(_Box2D.b2Color___mul__, None, b2Color) b2Color.__isub = new_instancemethod(_Box2D.b2Color___isub, None, b2Color) b2Color.__itruediv = new_instancemethod(_Box2D.b2Color___itruediv, None, b2Color) b2Color.__idiv = new_instancemethod(_Box2D.b2Color___idiv, None, b2Color) b2Color.__imul = new_instancemethod(_Box2D.b2Color___imul, None, b2Color) b2Color.__iadd = new_instancemethod(_Box2D.b2Color___iadd, None, b2Color) b2Color.__equ = new_instancemethod(_Box2D.b2Color___equ, None, b2Color) b2Color_swigregister = _Box2D.b2Color_swigregister b2Color_swigregister(b2Color) class b2Draw(object): """Implement and register this class with a b2Worldto provide debug drawing of physics entities in your game.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): if self.__class__ == b2Draw: _self = None else: _self = self _Box2D.b2Draw_swiginit(self,_Box2D.new_b2Draw(_self, )) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2Draw e_shapeBit = _Box2D.b2Draw_e_shapeBit e_jointBit = _Box2D.b2Draw_e_jointBit e_aabbBit = _Box2D.b2Draw_e_aabbBit e_pairBit = _Box2D.b2Draw_e_pairBit e_centerOfMassBit = _Box2D.b2Draw_e_centerOfMassBit def __SetFlags(self, flags): """ __SetFlags(b2Draw self, uint32 flags) Set the drawing flags. """ return _Box2D.b2Draw___SetFlags(self, flags) def __GetFlags(self): """ __GetFlags(b2Draw self) -> uint32 Get the drawing flags. """ return _Box2D.b2Draw___GetFlags(self) def AppendFlags(self, flags): """ AppendFlags(b2Draw self, uint32 flags) Append flags to the current flags. """ return _Box2D.b2Draw_AppendFlags(self, flags) def ClearFlags(self, flags): """ ClearFlags(b2Draw self, uint32 flags) Clear flags from the current flags. """ return _Box2D.b2Draw_ClearFlags(self, flags) def DrawPolygon(self, vertices, vertexCount, color): """ DrawPolygon(b2Draw self, b2Vec2 vertices, int32 vertexCount, b2Color color) Draw a closed polygon provided in CCW order. """ return _Box2D.b2Draw_DrawPolygon(self, vertices, vertexCount, color) def DrawSolidPolygon(self, vertices, vertexCount, color): """ DrawSolidPolygon(b2Draw self, b2Vec2 vertices, int32 vertexCount, b2Color color) Draw a solid closed polygon provided in CCW order. """ return _Box2D.b2Draw_DrawSolidPolygon(self, vertices, vertexCount, color) def DrawCircle(self, center, radius, color): """ DrawCircle(b2Draw self, b2Vec2 center, float32 radius, b2Color color) Draw a circle. """ return _Box2D.b2Draw_DrawCircle(self, center, radius, color) def DrawSolidCircle(self, center, radius, axis, color): """ DrawSolidCircle(b2Draw self, b2Vec2 center, float32 radius, b2Vec2 axis, b2Color color) Draw a solid circle. """ return _Box2D.b2Draw_DrawSolidCircle(self, center, radius, axis, color) def DrawSegment(self, p1, p2, color): """ DrawSegment(b2Draw self, b2Vec2 p1, b2Vec2 p2, b2Color color) Draw a line segment. """ return _Box2D.b2Draw_DrawSegment(self, p1, p2, color) def DrawTransform(self, xf): """ DrawTransform(b2Draw self, b2Transform xf) Draw a transform. Choose your own length scale. Parameters: ----------- xf: a transform. """ return _Box2D.b2Draw_DrawTransform(self, xf) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Draw self) -> long""" return _Box2D.b2Draw___hash__(self) def __repr__(self): return _format_repr(self) _flag_entries = [ ['drawShapes', e_shapeBit], ['drawJoints', e_jointBit ], ['drawAABBs', e_aabbBit ], ['drawPairs', e_pairBit ], ['drawCOMs', e_centerOfMassBit ], ['convertVertices', e_convertVertices ], ] def _SetFlags(self, value): flags = 0 for name_, mask in self._flag_entries: if name_ in value and value[name_]: flags |= mask self.__SetFlags(flags) def _GetFlags(self): flags = self.__GetFlags() ret={} for name_, mask in self._flag_entries: ret[name_]=((flags & mask)==mask) return ret flags=property(_GetFlags, _SetFlags, doc='Sets whether or not shapes, joints, etc. will be drawn.') def __disown__(self): self.this.disown() _Box2D.disown_b2Draw(self) return weakref_proxy(self) b2Draw.__SetFlags = new_instancemethod(_Box2D.b2Draw___SetFlags, None, b2Draw) b2Draw.__GetFlags = new_instancemethod(_Box2D.b2Draw___GetFlags, None, b2Draw) b2Draw.AppendFlags = new_instancemethod(_Box2D.b2Draw_AppendFlags, None, b2Draw) b2Draw.ClearFlags = new_instancemethod(_Box2D.b2Draw_ClearFlags, None, b2Draw) b2Draw.DrawPolygon = new_instancemethod(_Box2D.b2Draw_DrawPolygon, None, b2Draw) b2Draw.DrawSolidPolygon = new_instancemethod(_Box2D.b2Draw_DrawSolidPolygon, None, b2Draw) b2Draw.DrawCircle = new_instancemethod(_Box2D.b2Draw_DrawCircle, None, b2Draw) b2Draw.DrawSolidCircle = new_instancemethod(_Box2D.b2Draw_DrawSolidCircle, None, b2Draw) b2Draw.DrawSegment = new_instancemethod(_Box2D.b2Draw_DrawSegment, None, b2Draw) b2Draw.DrawTransform = new_instancemethod(_Box2D.b2Draw_DrawTransform, None, b2Draw) b2Draw.__hash__ = new_instancemethod(_Box2D.b2Draw___hash__, None, b2Draw) b2Draw_swigregister = _Box2D.b2Draw_swigregister b2Draw_swigregister(b2Draw) class b2DrawExtended(b2Draw): """Proxy of C++ b2DrawExtended class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr convertVertices = _swig_property(_Box2D.b2DrawExtended_convertVertices_get, _Box2D.b2DrawExtended_convertVertices_set) center = _swig_property(_Box2D.b2DrawExtended_center_get, _Box2D.b2DrawExtended_center_set) offset = _swig_property(_Box2D.b2DrawExtended_offset_get, _Box2D.b2DrawExtended_offset_set) zoom = _swig_property(_Box2D.b2DrawExtended_zoom_get, _Box2D.b2DrawExtended_zoom_set) screenSize = _swig_property(_Box2D.b2DrawExtended_screenSize_get, _Box2D.b2DrawExtended_screenSize_set) flipY = _swig_property(_Box2D.b2DrawExtended_flipY_get, _Box2D.b2DrawExtended_flipY_set) flipX = _swig_property(_Box2D.b2DrawExtended_flipX_get, _Box2D.b2DrawExtended_flipX_set) def __Convert(self, verts, vertexCount): """__Convert(b2DrawExtended self, b2Vec2 verts, int32 vertexCount) -> PyObject *""" return _Box2D.b2DrawExtended___Convert(self, verts, vertexCount) def to_screen(self, point): """to_screen(b2DrawExtended self, b2Vec2 point) -> PyObject *""" return _Box2D.b2DrawExtended_to_screen(self, point) def DrawPolygon(self, conv_vertices, vertexCount, color): """ DrawPolygon(b2DrawExtended self, b2Vec2 conv_vertices, int32 vertexCount, b2Color color) Draw a closed polygon provided in CCW order. """ return _Box2D.b2DrawExtended_DrawPolygon(self, conv_vertices, vertexCount, color) def DrawSolidPolygon(self, conv_vertices, vertexCount, color): """ DrawSolidPolygon(b2DrawExtended self, b2Vec2 conv_vertices, int32 vertexCount, b2Color color) Draw a solid closed polygon provided in CCW order. """ return _Box2D.b2DrawExtended_DrawSolidPolygon(self, conv_vertices, vertexCount, color) def DrawCircle(self, conv_p1, radius, color): """ DrawCircle(b2DrawExtended self, b2Vec2 conv_p1, float32 radius, b2Color color) Draw a circle. """ return _Box2D.b2DrawExtended_DrawCircle(self, conv_p1, radius, color) def DrawSolidCircle(self, conv_p1, radius, axis, color): """ DrawSolidCircle(b2DrawExtended self, b2Vec2 conv_p1, float32 radius, b2Vec2 axis, b2Color color) Draw a solid circle. """ return _Box2D.b2DrawExtended_DrawSolidCircle(self, conv_p1, radius, axis, color) def DrawSegment(self, conv_p1, conv_p2, color): """ DrawSegment(b2DrawExtended self, b2Vec2 conv_p1, b2Vec2 conv_p2, b2Color color) Draw a line segment. """ return _Box2D.b2DrawExtended_DrawSegment(self, conv_p1, conv_p2, color) def DrawTransform(self, xf): """ DrawTransform(b2DrawExtended self, b2Transform xf) Draw a transform. Choose your own length scale. Parameters: ----------- xf: a transform. """ return _Box2D.b2DrawExtended_DrawTransform(self, xf) def __SetFlags(self, flags): """__SetFlags(b2DrawExtended self, uint32 flags)""" return _Box2D.b2DrawExtended___SetFlags(self, flags) __swig_destroy__ = _Box2D.delete_b2DrawExtended def __init__(self, **kwargs): if self.__class__ == b2DrawExtended: _self = None else: _self = self _Box2D.b2DrawExtended_swiginit(self,_Box2D.new_b2DrawExtended(_self, )) _init_kwargs(self, **kwargs) __dir__ = _dir_filter def __hash__(self): """__hash__(b2DrawExtended self) -> long""" return _Box2D.b2DrawExtended___hash__(self) def __repr__(self): return _format_repr(self) def __disown__(self): self.this.disown() _Box2D.disown_b2DrawExtended(self) return weakref_proxy(self) b2DrawExtended.__Convert = new_instancemethod(_Box2D.b2DrawExtended___Convert, None, b2DrawExtended) b2DrawExtended.to_screen = new_instancemethod(_Box2D.b2DrawExtended_to_screen, None, b2DrawExtended) b2DrawExtended.DrawPolygon = new_instancemethod(_Box2D.b2DrawExtended_DrawPolygon, None, b2DrawExtended) b2DrawExtended.DrawSolidPolygon = new_instancemethod(_Box2D.b2DrawExtended_DrawSolidPolygon, None, b2DrawExtended) b2DrawExtended.DrawCircle = new_instancemethod(_Box2D.b2DrawExtended_DrawCircle, None, b2DrawExtended) b2DrawExtended.DrawSolidCircle = new_instancemethod(_Box2D.b2DrawExtended_DrawSolidCircle, None, b2DrawExtended) b2DrawExtended.DrawSegment = new_instancemethod(_Box2D.b2DrawExtended_DrawSegment, None, b2DrawExtended) b2DrawExtended.DrawTransform = new_instancemethod(_Box2D.b2DrawExtended_DrawTransform, None, b2DrawExtended) b2DrawExtended.__SetFlags = new_instancemethod(_Box2D.b2DrawExtended___SetFlags, None, b2DrawExtended) b2DrawExtended.__hash__ = new_instancemethod(_Box2D.b2DrawExtended___hash__, None, b2DrawExtended) b2DrawExtended_swigregister = _Box2D.b2DrawExtended_swigregister b2DrawExtended_swigregister(b2DrawExtended) class b2MassData(object): """This holds the mass data computed for a shape.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr mass = _swig_property(_Box2D.b2MassData_mass_get, _Box2D.b2MassData_mass_set) center = _swig_property(_Box2D.b2MassData_center_get, _Box2D.b2MassData_center_set) I = _swig_property(_Box2D.b2MassData_I_get, _Box2D.b2MassData_I_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2MassData self) -> long""" return _Box2D.b2MassData___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2MassData_swiginit(self,_Box2D.new_b2MassData()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2MassData b2MassData.__hash__ = new_instancemethod(_Box2D.b2MassData___hash__, None, b2MassData) b2MassData_swigregister = _Box2D.b2MassData_swigregister b2MassData_swigregister(b2MassData) b2_chunkSize = b2Globals.b2_chunkSize b2_maxBlockSize = b2Globals.b2_maxBlockSize b2_blockSizes = b2Globals.b2_blockSizes b2_chunkArrayIncrement = b2Globals.b2_chunkArrayIncrement class b2Shape(object): """A shape is used for collision detection. You can create a shape however you like. Shapes used for simulation in b2Worldare created automatically when a b2Fixtureis created. Shapes may encapsulate a one or more child shapes.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined - class is abstract") __repr__ = _swig_repr e_circle = _Box2D.b2Shape_e_circle e_edge = _Box2D.b2Shape_e_edge e_polygon = _Box2D.b2Shape_e_polygon e_chain = _Box2D.b2Shape_e_chain e_typeCount = _Box2D.b2Shape_e_typeCount __swig_destroy__ = _Box2D.delete_b2Shape def __GetType(self): """ __GetType(b2Shape self) -> b2Shape::Type Get the type of this shape. You can use this to down cast to the concrete shape. the shape type. """ return _Box2D.b2Shape___GetType(self) def __GetChildCount(self): """ __GetChildCount(b2Shape self) -> int32 Get the number of child primitives. """ return _Box2D.b2Shape___GetChildCount(self) def TestPoint(self, xf, p): """ TestPoint(b2Shape self, b2Transform xf, b2Vec2 p) -> bool Test a point for containment in this shape. This only works for convex shapes. Parameters: ----------- xf: the shape world transform. p: a point in world coordinates. """ return _Box2D.b2Shape_TestPoint(self, xf, p) def RayCast(self, output, input, transform, childIndex): """ RayCast(b2Shape self, b2RayCastOutput output, b2RayCastInput input, b2Transform transform, int32 childIndex) -> bool Cast a ray against a child shape. Parameters: ----------- output: the ray-cast results. input: the ray-cast input parameters. transform: the transform to be applied to the shape. childIndex: the child shape index """ return _Box2D.b2Shape_RayCast(self, output, input, transform, childIndex) def __ComputeAABB(self, aabb, xf, childIndex): """ __ComputeAABB(b2Shape self, b2AABB aabb, b2Transform xf, int32 childIndex) Given a transform, compute the associated axis aligned bounding box for a child shape. Parameters: ----------- aabb: returns the axis aligned box. xf: the world transform of the shape. childIndex: the child shape """ return _Box2D.b2Shape___ComputeAABB(self, aabb, xf, childIndex) def __ComputeMass(self, massData, density): """ __ComputeMass(b2Shape self, b2MassData massData, float32 density) Compute the mass properties of this shape using its dimensions and density. The inertia tensor is computed about the local origin. Parameters: ----------- massData: returns the mass data for this shape. density: the density in kilograms per meter squared. """ return _Box2D.b2Shape___ComputeMass(self, massData, density) radius = _swig_property(_Box2D.b2Shape_radius_get, _Box2D.b2Shape_radius_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Shape self) -> long""" return _Box2D.b2Shape___hash__(self) def __repr__(self): return _format_repr(self) __eq__ = b2ShapeCompare __ne__ = lambda self,other: not b2ShapeCompare(self,other) # Read-only type = property(__GetType, None) def getAsType(self): return self @property def childCount(self): """ Get the number of child primitives. """ return self.__GetChildCount() def getAABB(self, transform, childIndex): """ Given a transform, compute the associated axis aligned bounding box for a child shape. """ if childIndex >= self.childCount: raise ValueError('Child index should be at most childCount=%d' % self.childCount) aabb=b2AABB() self.__ComputeAABB(aabb, transform, childIndex) return aabb def getMass(self, density): """ Compute the mass properties of this shape using its dimensions and density. The inertia tensor is computed about the local origin. """ m=b2MassData() self.__ComputeMass(m, density) return m b2Shape.__GetType = new_instancemethod(_Box2D.b2Shape___GetType, None, b2Shape) b2Shape.__GetChildCount = new_instancemethod(_Box2D.b2Shape___GetChildCount, None, b2Shape) b2Shape.TestPoint = new_instancemethod(_Box2D.b2Shape_TestPoint, None, b2Shape) b2Shape.RayCast = new_instancemethod(_Box2D.b2Shape_RayCast, None, b2Shape) b2Shape.__ComputeAABB = new_instancemethod(_Box2D.b2Shape___ComputeAABB, None, b2Shape) b2Shape.__ComputeMass = new_instancemethod(_Box2D.b2Shape___ComputeMass, None, b2Shape) b2Shape.__hash__ = new_instancemethod(_Box2D.b2Shape___hash__, None, b2Shape) b2Shape_swigregister = _Box2D.b2Shape_swigregister b2Shape_swigregister(b2Shape) class b2CircleShape(b2Shape): """A circle shape.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2CircleShape_swiginit(self,_Box2D.new_b2CircleShape()) _init_kwargs(self, **kwargs) pos = _swig_property(_Box2D.b2CircleShape_pos_get, _Box2D.b2CircleShape_pos_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2CircleShape self) -> long""" return _Box2D.b2CircleShape___hash__(self) def __repr__(self): return _format_repr(self) __swig_destroy__ = _Box2D.delete_b2CircleShape b2CircleShape.__hash__ = new_instancemethod(_Box2D.b2CircleShape___hash__, None, b2CircleShape) b2CircleShape_swigregister = _Box2D.b2CircleShape_swigregister b2CircleShape_swigregister(b2CircleShape) class b2EdgeShape(b2Shape): """A line segment (edge) shape. These can be connected in chains or loops to other edge shapes. The connectivity information is used to ensure correct contact normals.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2EdgeShape_swiginit(self,_Box2D.new_b2EdgeShape()) _init_kwargs(self, **kwargs) def __Set(self, v1, v2): """ __Set(b2EdgeShape self, b2Vec2 v1, b2Vec2 v2) Set this as an isolated edge. """ return _Box2D.b2EdgeShape___Set(self, v1, v2) vertex1 = _swig_property(_Box2D.b2EdgeShape_vertex1_get, _Box2D.b2EdgeShape_vertex1_set) vertex2 = _swig_property(_Box2D.b2EdgeShape_vertex2_get, _Box2D.b2EdgeShape_vertex2_set) vertex0 = _swig_property(_Box2D.b2EdgeShape_vertex0_get, _Box2D.b2EdgeShape_vertex0_set) vertex3 = _swig_property(_Box2D.b2EdgeShape_vertex3_get, _Box2D.b2EdgeShape_vertex3_set) hasVertex0 = _swig_property(_Box2D.b2EdgeShape_hasVertex0_get, _Box2D.b2EdgeShape_hasVertex0_set) hasVertex3 = _swig_property(_Box2D.b2EdgeShape_hasVertex3_get, _Box2D.b2EdgeShape_hasVertex3_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2EdgeShape self) -> long""" return _Box2D.b2EdgeShape___hash__(self) def __repr__(self): return _format_repr(self) def __repr__(self): return "b2EdgeShape(vertices: %s)" % (self.vertices) @property def all_vertices(self): """Returns all of the vertices as a list of tuples [ (x0,y0), (x1,y1), (x2,y2) (x3,y3) ] Note that the validity of vertices 0 and 4 depend on whether or not hasVertex0 and hasVertex3 are set. """ return [tuple(self.vertex0), tuple(self.vertex1), tuple(self.vertex2), tuple(self.vertex3)] def __get_vertices(self): """Returns the basic vertices as a list of tuples [ (x1,y1), (x2,y2) ] To include the supporting vertices, see 'all_vertices' If you want to set vertex3 but not vertex0, pass in None for vertex0. """ return [tuple(self.vertex1), tuple(self.vertex2)] def __set_vertices(self, vertices): if len(vertices)==2: self.vertex1, self.vertex2=vertices self.hasVertex0=False self.hasVertex3=False elif len(vertices)==3: self.vertex0, self.vertex1, self.vertex2=vertices self.hasVertex0=(vertices[0] != None) self.hasVertex3=False elif len(vertices)==4: self.vertex0, self.vertex1, self.vertex2, self.vertex3=vertices self.hasVertex0=(vertices[0] != None) self.hasVertex3=True else: raise ValueError('Expected from 2 to 4 vertices.') @property def vertexCount(self): """ Returns the number of valid vertices (as in, it counts whether or not hasVertex0 or hasVertex3 are set) """ if self.hasVertex0 and self.hasVertex3: return 4 elif self.hasVertex0 or self.hasVertex3: return 3 else: return 2 def __iter__(self): """ Iterates over the vertices in the Edge """ for v in self.vertices: yield v vertices=property(__get_vertices, __set_vertices) __swig_destroy__ = _Box2D.delete_b2EdgeShape b2EdgeShape.__Set = new_instancemethod(_Box2D.b2EdgeShape___Set, None, b2EdgeShape) b2EdgeShape.__hash__ = new_instancemethod(_Box2D.b2EdgeShape___hash__, None, b2EdgeShape) b2EdgeShape_swigregister = _Box2D.b2EdgeShape_swigregister b2EdgeShape_swigregister(b2EdgeShape) class b2ChainShape(b2Shape): """A loop shape is a free form sequence of line segments that form a circular list. The loop may cross upon itself, but this is not recommended for smooth collision. The loop has double sided collision, so you can use inside and outside collision. Therefore, you may use any winding order. Since there may be many vertices, they are allocated using b2Alloc.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2ChainShape_swiginit(self,_Box2D.new_b2ChainShape()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2ChainShape def CreateLoop(self, vertices, count): """CreateLoop(b2ChainShape self, b2Vec2 vertices, int32 count)""" return _Box2D.b2ChainShape_CreateLoop(self, vertices, count) def CreateChain(self, vertices, count): """CreateChain(b2ChainShape self, b2Vec2 vertices, int32 count)""" return _Box2D.b2ChainShape_CreateChain(self, vertices, count) def SetPrevVertex(self, prevVertex): """SetPrevVertex(b2ChainShape self, b2Vec2 prevVertex)""" return _Box2D.b2ChainShape_SetPrevVertex(self, prevVertex) def SetNextVertex(self, nextVertex): """SetNextVertex(b2ChainShape self, b2Vec2 nextVertex)""" return _Box2D.b2ChainShape_SetNextVertex(self, nextVertex) def __GetChildEdge(self, edge, index): """ __GetChildEdge(b2ChainShape self, b2EdgeShape edge, int32 index) Get a child edge. """ return _Box2D.b2ChainShape___GetChildEdge(self, edge, index) m_prevVertex = _swig_property(_Box2D.b2ChainShape_m_prevVertex_get, _Box2D.b2ChainShape_m_prevVertex_set) m_nextVertex = _swig_property(_Box2D.b2ChainShape_m_nextVertex_get, _Box2D.b2ChainShape_m_nextVertex_set) m_hasPrevVertex = _swig_property(_Box2D.b2ChainShape_m_hasPrevVertex_get, _Box2D.b2ChainShape_m_hasPrevVertex_set) m_hasNextVertex = _swig_property(_Box2D.b2ChainShape_m_hasNextVertex_get, _Box2D.b2ChainShape_m_hasNextVertex_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ChainShape self) -> long""" return _Box2D.b2ChainShape___hash__(self) def __repr__(self): return _format_repr(self) def __get_vertices(self): """__get_vertices(b2ChainShape self) -> PyObject *""" return _Box2D.b2ChainShape___get_vertices(self) def __repr__(self): return "b2ChainShape(vertices: %s)" % (self.vertices) def getChildEdge(self, index): if childIndex >= self.childCount: raise ValueError('Child index should be at most childCount=%d' % self.childCount) edge=b2EdgeShape() self.__GetChildEdge(edge, index) return edge @property def edges(self): return [self.getChildEdge(i) for i in range(self.childCount)] @property def vertexCount(self): return self.__get_count() def __get_vertices(self): """Returns all of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" return [ (self.__get_vertex(i).x, self.__get_vertex(i).y ) for i in range(0, self.vertexCount)] def __iter__(self): """ Iterates over the vertices in the Chain """ for v in self.vertices: yield v def __set_vertices(self, values, loop=True): if not values or not isinstance(values, (list, tuple)) or (len(values) < 2): raise ValueError('Expected tuple or list of length >= 2.') for i,value in enumerate(values): if isinstance(value, (tuple, list)): if len(value) != 2: raise ValueError('Expected tuple or list of length 2, got length %d' % len(value)) for j in value: if not isinstance(j, (int, float)): raise ValueError('Expected int or float values, got %s' % (type(j))) elif isinstance(value, b2Vec2): pass else: raise ValueError('Expected tuple, list, or b2Vec2, got %s' % type(value)) vecs=_b2Vec2Array(len(values)) for i, value in enumerate(values): if isinstance(value, b2Vec2): vecs[i]=value else: vecs[i]=b2Vec2(value) self.__create(vecs, len(values), loop) vertices = property(__get_vertices, __set_vertices) vertices_chain = property(__get_vertices, lambda self, v : self.__set_vertices(v, loop=False)) vertices_loop = vertices def __create(self, v, c, loop): """__create(b2ChainShape self, _b2Vec2Array v, int c, bool loop)""" return _Box2D.b2ChainShape___create(self, v, c, loop) def __get_vertex(self, vnum): """__get_vertex(b2ChainShape self, uint16 vnum) -> b2Vec2""" return _Box2D.b2ChainShape___get_vertex(self, vnum) def __get_count(self): """__get_count(b2ChainShape self) -> int32""" return _Box2D.b2ChainShape___get_count(self) b2ChainShape.CreateLoop = new_instancemethod(_Box2D.b2ChainShape_CreateLoop, None, b2ChainShape) b2ChainShape.CreateChain = new_instancemethod(_Box2D.b2ChainShape_CreateChain, None, b2ChainShape) b2ChainShape.SetPrevVertex = new_instancemethod(_Box2D.b2ChainShape_SetPrevVertex, None, b2ChainShape) b2ChainShape.SetNextVertex = new_instancemethod(_Box2D.b2ChainShape_SetNextVertex, None, b2ChainShape) b2ChainShape.__GetChildEdge = new_instancemethod(_Box2D.b2ChainShape___GetChildEdge, None, b2ChainShape) b2ChainShape.__hash__ = new_instancemethod(_Box2D.b2ChainShape___hash__, None, b2ChainShape) b2ChainShape.__get_vertices = new_instancemethod(_Box2D.b2ChainShape___get_vertices, None, b2ChainShape) b2ChainShape.__create = new_instancemethod(_Box2D.b2ChainShape___create, None, b2ChainShape) b2ChainShape.__get_vertex = new_instancemethod(_Box2D.b2ChainShape___get_vertex, None, b2ChainShape) b2ChainShape.__get_count = new_instancemethod(_Box2D.b2ChainShape___get_count, None, b2ChainShape) b2ChainShape_swigregister = _Box2D.b2ChainShape_swigregister b2ChainShape_swigregister(b2ChainShape) class b2PolygonShape(b2Shape): """A convex polygon. It is assumed that the interior of the polygon is to the left of each edge. Polygons have a maximum number of vertices equal to b2_maxPolygonVertices. In most cases you should not need many vertices for a convex polygon.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2PolygonShape_swiginit(self,_Box2D.new_b2PolygonShape()) _init_kwargs(self, **kwargs) def SetAsBox(self, *args): """ SetAsBox(b2PolygonShape self, float32 hx, float32 hy) SetAsBox(b2PolygonShape self, float32 hx, float32 hy, b2Vec2 center, float32 angle) Build vertices to represent an oriented box. Parameters: ----------- hx: the half-width. hy: the half-height. center: the center of the box in local coordinates. angle: the rotation of the box in local coordinates. """ return _Box2D.b2PolygonShape_SetAsBox(self, *args) def Validate(self): """Validate(b2PolygonShape self) -> bool""" return _Box2D.b2PolygonShape_Validate(self) centroid = _swig_property(_Box2D.b2PolygonShape_centroid_get, _Box2D.b2PolygonShape_centroid_set) vertexCount = _swig_property(_Box2D.b2PolygonShape_vertexCount_get, _Box2D.b2PolygonShape_vertexCount_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2PolygonShape self) -> long""" return _Box2D.b2PolygonShape___hash__(self) def __repr__(self): return _format_repr(self) def __get_vertices(self): """__get_vertices(b2PolygonShape self) -> PyObject *""" return _Box2D.b2PolygonShape___get_vertices(self) def __get_normals(self): """__get_normals(b2PolygonShape self) -> PyObject *""" return _Box2D.b2PolygonShape___get_normals(self) def __repr__(self): return "b2PolygonShape(vertices: %s)" % (self.vertices) def __clear_vertices(self): self.vertexCount=0 for i in range(0, b2_maxPolygonVertices): self.set_vertex(i, 0, 0) def __set_vertices(self, values): if not values: self.__clear_vertices() else: if len(values) < 2 or len(values) > b2_maxPolygonVertices: raise ValueError('Expected tuple or list of length >= 2 and less than b2_maxPolygonVertices=%d, got length %d.' % (b2_maxPolygonVertices, len(values))) for i,value in enumerate(values): if isinstance(value, (tuple, list, b2Vec2)): if len(value) != 2: raise ValueError('Expected tuple or list of length 2, got length %d' % len(value)) self.set_vertex(i, *value) else: raise ValueError('Expected tuple, list, or b2Vec2, got %s' % type(value)) self.vertexCount=i+1 # follow along in case of an exception to indicate valid number set self.__set_vertices_internal() # calculates normals, centroid, etc. def __iter__(self): """ Iterates over the vertices in the polygon """ for v in self.vertices: yield v def __IsValid(self): return b2CheckPolygon(self) valid = property(__IsValid, None, doc="Checks the polygon to see if it can be properly created. Raises ValueError for invalid shapes.") vertices = property(__get_vertices, __set_vertices, doc="All of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]") normals = property(__get_normals, None, doc="All of the normals as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]") box = property(None, lambda self, value: self.SetAsBox(*value), doc="Property replacement for running SetAsBox (Write-only)") def __get_vertex(self, vnum): """__get_vertex(b2PolygonShape self, uint16 vnum) -> b2Vec2""" return _Box2D.b2PolygonShape___get_vertex(self, vnum) def __get_normal(self, vnum): """__get_normal(b2PolygonShape self, uint16 vnum) -> b2Vec2""" return _Box2D.b2PolygonShape___get_normal(self, vnum) def set_vertex(self, *args): """ set_vertex(b2PolygonShape self, uint16 vnum, b2Vec2 value) set_vertex(b2PolygonShape self, uint16 vnum, float32 x, float32 y) """ return _Box2D.b2PolygonShape_set_vertex(self, *args) def __set_vertices_internal(self, *args): """ __set_vertices_internal(b2PolygonShape self, b2Vec2 points, int32 count) __set_vertices_internal(b2PolygonShape self) """ return _Box2D.b2PolygonShape___set_vertices_internal(self, *args) __swig_destroy__ = _Box2D.delete_b2PolygonShape b2PolygonShape.SetAsBox = new_instancemethod(_Box2D.b2PolygonShape_SetAsBox, None, b2PolygonShape) b2PolygonShape.Validate = new_instancemethod(_Box2D.b2PolygonShape_Validate, None, b2PolygonShape) b2PolygonShape.__hash__ = new_instancemethod(_Box2D.b2PolygonShape___hash__, None, b2PolygonShape) b2PolygonShape.__get_vertices = new_instancemethod(_Box2D.b2PolygonShape___get_vertices, None, b2PolygonShape) b2PolygonShape.__get_normals = new_instancemethod(_Box2D.b2PolygonShape___get_normals, None, b2PolygonShape) b2PolygonShape.__get_vertex = new_instancemethod(_Box2D.b2PolygonShape___get_vertex, None, b2PolygonShape) b2PolygonShape.__get_normal = new_instancemethod(_Box2D.b2PolygonShape___get_normal, None, b2PolygonShape) b2PolygonShape.set_vertex = new_instancemethod(_Box2D.b2PolygonShape_set_vertex, None, b2PolygonShape) b2PolygonShape.__set_vertices_internal = new_instancemethod(_Box2D.b2PolygonShape___set_vertices_internal, None, b2PolygonShape) b2PolygonShape_swigregister = _Box2D.b2PolygonShape_swigregister b2PolygonShape_swigregister(b2PolygonShape) _Box2D.b2_nullNode_swigconstant(_Box2D) b2_nullNode = _Box2D.b2_nullNode class b2TreeNode(object): """Proxy of C++ b2TreeNode class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def IsLeaf(self): """IsLeaf(b2TreeNode self) -> bool""" return _Box2D.b2TreeNode_IsLeaf(self) aabb = _swig_property(_Box2D.b2TreeNode_aabb_get, _Box2D.b2TreeNode_aabb_set) child1 = _swig_property(_Box2D.b2TreeNode_child1_get, _Box2D.b2TreeNode_child1_set) child2 = _swig_property(_Box2D.b2TreeNode_child2_get, _Box2D.b2TreeNode_child2_set) height = _swig_property(_Box2D.b2TreeNode_height_get, _Box2D.b2TreeNode_height_set) def __init__(self): """__init__(b2TreeNode self) -> b2TreeNode""" _Box2D.b2TreeNode_swiginit(self, _Box2D.new_b2TreeNode()) __swig_destroy__ = _Box2D.delete_b2TreeNode b2TreeNode.IsLeaf = new_instancemethod(_Box2D.b2TreeNode_IsLeaf, None, b2TreeNode) b2TreeNode_swigregister = _Box2D.b2TreeNode_swigregister b2TreeNode_swigregister(b2TreeNode) class b2Pair(object): """Proxy of C++ b2Pair class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr proxyIdA = _swig_property(_Box2D.b2Pair_proxyIdA_get, _Box2D.b2Pair_proxyIdA_set) proxyIdB = _swig_property(_Box2D.b2Pair_proxyIdB_get, _Box2D.b2Pair_proxyIdB_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Pair self) -> long""" return _Box2D.b2Pair___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2Pair_swiginit(self,_Box2D.new_b2Pair()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2Pair b2Pair.__hash__ = new_instancemethod(_Box2D.b2Pair___hash__, None, b2Pair) b2Pair_swigregister = _Box2D.b2Pair_swigregister b2Pair_swigregister(b2Pair) class b2BroadPhase(object): """The broad-phase is used for computing pairs and performing volume queries and ray casts. This broad-phase does not persist pairs. Instead, this reports potentially new pairs. It is up to the client to consume the new pairs and to track subsequent overlap.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr e_nullProxy = _Box2D.b2BroadPhase_e_nullProxy def __init__(self): """ __init__(b2BroadPhase self) -> b2BroadPhase The broad-phase is used for computing pairs and performing volume queries and ray casts. This broad-phase does not persist pairs. Instead, this reports potentially new pairs. It is up to the client to consume the new pairs and to track subsequent overlap. """ _Box2D.b2BroadPhase_swiginit(self, _Box2D.new_b2BroadPhase()) __swig_destroy__ = _Box2D.delete_b2BroadPhase def MoveProxy(self, proxyId, aabb, displacement): """ MoveProxy(b2BroadPhase self, int32 proxyId, b2AABB aabb, b2Vec2 displacement) Call MoveProxy as many times as you like, then when you are done call UpdatePairs to finalized the proxy pairs (for your time step). """ return _Box2D.b2BroadPhase_MoveProxy(self, proxyId, aabb, displacement) def TouchProxy(self, proxyId): """ TouchProxy(b2BroadPhase self, int32 proxyId) Call to trigger a re-processing of it's pairs on the next call to UpdatePairs. """ return _Box2D.b2BroadPhase_TouchProxy(self, proxyId) def GetFatAABB(self, proxyId): """ GetFatAABB(b2BroadPhase self, int32 proxyId) -> b2AABB Get the fat AABB for a proxy. """ return _Box2D.b2BroadPhase_GetFatAABB(self, proxyId) def TestOverlap(self, proxyIdA, proxyIdB): """ TestOverlap(b2BroadPhase self, int32 proxyIdA, int32 proxyIdB) -> bool Test overlap of fat AABBs. """ return _Box2D.b2BroadPhase_TestOverlap(self, proxyIdA, proxyIdB) def __GetProxyCount(self): """ __GetProxyCount(b2BroadPhase self) -> int32 Get the number of proxies. """ return _Box2D.b2BroadPhase___GetProxyCount(self) def __GetTreeHeight(self): """__GetTreeHeight(b2BroadPhase self) -> int32""" return _Box2D.b2BroadPhase___GetTreeHeight(self) def __GetTreeBalance(self): """__GetTreeBalance(b2BroadPhase self) -> int32""" return _Box2D.b2BroadPhase___GetTreeBalance(self) def __GetTreeQuality(self): """__GetTreeQuality(b2BroadPhase self) -> float32""" return _Box2D.b2BroadPhase___GetTreeQuality(self) def ShiftOrigin(self, newOrigin): """ShiftOrigin(b2BroadPhase self, b2Vec2 newOrigin)""" return _Box2D.b2BroadPhase_ShiftOrigin(self, newOrigin) __dir__ = _dir_filter def __hash__(self): """__hash__(b2BroadPhase self) -> long""" return _Box2D.b2BroadPhase___hash__(self) def __repr__(self): return _format_repr(self) proxyCount=property(__GetProxyCount, None) treeHeight=property(__GetTreeHeight, None) treeBalance=property(__GetTreeBalance, None) treeQuality=property(__GetTreeQuality, None) b2BroadPhase.MoveProxy = new_instancemethod(_Box2D.b2BroadPhase_MoveProxy, None, b2BroadPhase) b2BroadPhase.TouchProxy = new_instancemethod(_Box2D.b2BroadPhase_TouchProxy, None, b2BroadPhase) b2BroadPhase.GetFatAABB = new_instancemethod(_Box2D.b2BroadPhase_GetFatAABB, None, b2BroadPhase) b2BroadPhase.TestOverlap = new_instancemethod(_Box2D.b2BroadPhase_TestOverlap, None, b2BroadPhase) b2BroadPhase.__GetProxyCount = new_instancemethod(_Box2D.b2BroadPhase___GetProxyCount, None, b2BroadPhase) b2BroadPhase.__GetTreeHeight = new_instancemethod(_Box2D.b2BroadPhase___GetTreeHeight, None, b2BroadPhase) b2BroadPhase.__GetTreeBalance = new_instancemethod(_Box2D.b2BroadPhase___GetTreeBalance, None, b2BroadPhase) b2BroadPhase.__GetTreeQuality = new_instancemethod(_Box2D.b2BroadPhase___GetTreeQuality, None, b2BroadPhase) b2BroadPhase.ShiftOrigin = new_instancemethod(_Box2D.b2BroadPhase_ShiftOrigin, None, b2BroadPhase) b2BroadPhase.__hash__ = new_instancemethod(_Box2D.b2BroadPhase___hash__, None, b2BroadPhase) b2BroadPhase_swigregister = _Box2D.b2BroadPhase_swigregister b2BroadPhase_swigregister(b2BroadPhase) def b2PairLessThan(pair1, pair2): """ b2PairLessThan(b2Pair pair1, b2Pair pair2) -> bool This is used to sort pairs. """ return _Box2D.b2PairLessThan(pair1, pair2) class b2DistanceProxy(object): """A distance proxy is used by the GJK algorithm. It encapsulates any shape.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, shape, index=0): _Box2D.b2DistanceProxy_swiginit(self,_Box2D.new_b2DistanceProxy()) self.Set(shape, index) def Set(self, shape, index): """ Set(b2DistanceProxy self, b2Shape shape, int32 index) Initialize the proxy using the given shape. The shape must remain in scope while the proxy is in use. """ return _Box2D.b2DistanceProxy_Set(self, shape, index) def GetSupport(self, d): """ GetSupport(b2DistanceProxy self, b2Vec2 d) -> int32 Get the supporting vertex index in the given direction. """ return _Box2D.b2DistanceProxy_GetSupport(self, d) def GetSupportVertex(self, d): """ GetSupportVertex(b2DistanceProxy self, b2Vec2 d) -> b2Vec2 Get the supporting vertex in the given direction. """ return _Box2D.b2DistanceProxy_GetSupportVertex(self, d) def __get_vertex_count(self): """ __get_vertex_count(b2DistanceProxy self) -> int32 Get the vertex count. """ return _Box2D.b2DistanceProxy___get_vertex_count(self) def __get_vertex(self, index): """ __get_vertex(b2DistanceProxy self, int32 index) -> b2Vec2 Get a vertex by index. Used by b2Distance. """ return _Box2D.b2DistanceProxy___get_vertex(self, index) m_buffer = _swig_property(_Box2D.b2DistanceProxy_m_buffer_get, _Box2D.b2DistanceProxy_m_buffer_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2DistanceProxy self) -> long""" return _Box2D.b2DistanceProxy___hash__(self) def __repr__(self): return _format_repr(self) def __get_vertices(self): """Returns all of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" return [ (self.__get_vertex(i).x, self.__get_vertex(i).y ) for i in range(0, self.__get_vertex_count())] vertices = property(__get_vertices, None) __swig_destroy__ = _Box2D.delete_b2DistanceProxy b2DistanceProxy.Set = new_instancemethod(_Box2D.b2DistanceProxy_Set, None, b2DistanceProxy) b2DistanceProxy.GetSupport = new_instancemethod(_Box2D.b2DistanceProxy_GetSupport, None, b2DistanceProxy) b2DistanceProxy.GetSupportVertex = new_instancemethod(_Box2D.b2DistanceProxy_GetSupportVertex, None, b2DistanceProxy) b2DistanceProxy.__get_vertex_count = new_instancemethod(_Box2D.b2DistanceProxy___get_vertex_count, None, b2DistanceProxy) b2DistanceProxy.__get_vertex = new_instancemethod(_Box2D.b2DistanceProxy___get_vertex, None, b2DistanceProxy) b2DistanceProxy.__hash__ = new_instancemethod(_Box2D.b2DistanceProxy___hash__, None, b2DistanceProxy) b2DistanceProxy_swigregister = _Box2D.b2DistanceProxy_swigregister b2DistanceProxy_swigregister(b2DistanceProxy) class b2DistanceInput(object): """Input for b2Distance. You have to option to use the shape radii in the computation. Even""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr proxyA = _swig_property(_Box2D.b2DistanceInput_proxyA_get, _Box2D.b2DistanceInput_proxyA_set) proxyB = _swig_property(_Box2D.b2DistanceInput_proxyB_get, _Box2D.b2DistanceInput_proxyB_set) transformA = _swig_property(_Box2D.b2DistanceInput_transformA_get, _Box2D.b2DistanceInput_transformA_set) transformB = _swig_property(_Box2D.b2DistanceInput_transformB_get, _Box2D.b2DistanceInput_transformB_set) useRadii = _swig_property(_Box2D.b2DistanceInput_useRadii_get, _Box2D.b2DistanceInput_useRadii_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2DistanceInput self) -> long""" return _Box2D.b2DistanceInput___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2DistanceInput_swiginit(self,_Box2D.new_b2DistanceInput()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2DistanceInput b2DistanceInput.__hash__ = new_instancemethod(_Box2D.b2DistanceInput___hash__, None, b2DistanceInput) b2DistanceInput_swigregister = _Box2D.b2DistanceInput_swigregister b2DistanceInput_swigregister(b2DistanceInput) class b2DistanceOutput(object): """Output for b2Distance.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr pointA = _swig_property(_Box2D.b2DistanceOutput_pointA_get, _Box2D.b2DistanceOutput_pointA_set) pointB = _swig_property(_Box2D.b2DistanceOutput_pointB_get, _Box2D.b2DistanceOutput_pointB_set) distance = _swig_property(_Box2D.b2DistanceOutput_distance_get, _Box2D.b2DistanceOutput_distance_set) iterations = _swig_property(_Box2D.b2DistanceOutput_iterations_get, _Box2D.b2DistanceOutput_iterations_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2DistanceOutput self) -> long""" return _Box2D.b2DistanceOutput___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2DistanceOutput_swiginit(self,_Box2D.new_b2DistanceOutput()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2DistanceOutput b2DistanceOutput.__hash__ = new_instancemethod(_Box2D.b2DistanceOutput___hash__, None, b2DistanceOutput) b2DistanceOutput_swigregister = _Box2D.b2DistanceOutput_swigregister b2DistanceOutput_swigregister(b2DistanceOutput) class b2TOIInput(object): """Input parameters for b2TimeOfImpact.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr proxyA = _swig_property(_Box2D.b2TOIInput_proxyA_get, _Box2D.b2TOIInput_proxyA_set) proxyB = _swig_property(_Box2D.b2TOIInput_proxyB_get, _Box2D.b2TOIInput_proxyB_set) sweepA = _swig_property(_Box2D.b2TOIInput_sweepA_get, _Box2D.b2TOIInput_sweepA_set) sweepB = _swig_property(_Box2D.b2TOIInput_sweepB_get, _Box2D.b2TOIInput_sweepB_set) tMax = _swig_property(_Box2D.b2TOIInput_tMax_get, _Box2D.b2TOIInput_tMax_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2TOIInput self) -> long""" return _Box2D.b2TOIInput___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2TOIInput_swiginit(self,_Box2D.new_b2TOIInput()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2TOIInput b2TOIInput.__hash__ = new_instancemethod(_Box2D.b2TOIInput___hash__, None, b2TOIInput) b2TOIInput_swigregister = _Box2D.b2TOIInput_swigregister b2TOIInput_swigregister(b2TOIInput) class b2TOIOutput(object): """Proxy of C++ b2TOIOutput class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr e_unknown = _Box2D.b2TOIOutput_e_unknown e_failed = _Box2D.b2TOIOutput_e_failed e_overlapped = _Box2D.b2TOIOutput_e_overlapped e_touching = _Box2D.b2TOIOutput_e_touching e_separated = _Box2D.b2TOIOutput_e_separated state = _swig_property(_Box2D.b2TOIOutput_state_get, _Box2D.b2TOIOutput_state_set) t = _swig_property(_Box2D.b2TOIOutput_t_get, _Box2D.b2TOIOutput_t_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2TOIOutput self) -> long""" return _Box2D.b2TOIOutput___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self): """__init__(b2TOIOutput self) -> b2TOIOutput""" _Box2D.b2TOIOutput_swiginit(self, _Box2D.new_b2TOIOutput()) __swig_destroy__ = _Box2D.delete_b2TOIOutput b2TOIOutput.__hash__ = new_instancemethod(_Box2D.b2TOIOutput___hash__, None, b2TOIOutput) b2TOIOutput_swigregister = _Box2D.b2TOIOutput_swigregister b2TOIOutput_swigregister(b2TOIOutput) _Box2D.b2_staticBody_swigconstant(_Box2D) b2_staticBody = _Box2D.b2_staticBody _Box2D.b2_kinematicBody_swigconstant(_Box2D) b2_kinematicBody = _Box2D.b2_kinematicBody _Box2D.b2_dynamicBody_swigconstant(_Box2D) b2_dynamicBody = _Box2D.b2_dynamicBody class b2BodyDef(object): """A body definition holds all the data needed to construct a rigid body. You can safely re-use body definitions. Shapes are added to a body after construction.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2BodyDef_swiginit(self,_Box2D.new_b2BodyDef()) _init_kwargs(self, **kwargs) type = _swig_property(_Box2D.b2BodyDef_type_get, _Box2D.b2BodyDef_type_set) position = _swig_property(_Box2D.b2BodyDef_position_get, _Box2D.b2BodyDef_position_set) angle = _swig_property(_Box2D.b2BodyDef_angle_get, _Box2D.b2BodyDef_angle_set) linearVelocity = _swig_property(_Box2D.b2BodyDef_linearVelocity_get, _Box2D.b2BodyDef_linearVelocity_set) angularVelocity = _swig_property(_Box2D.b2BodyDef_angularVelocity_get, _Box2D.b2BodyDef_angularVelocity_set) linearDamping = _swig_property(_Box2D.b2BodyDef_linearDamping_get, _Box2D.b2BodyDef_linearDamping_set) angularDamping = _swig_property(_Box2D.b2BodyDef_angularDamping_get, _Box2D.b2BodyDef_angularDamping_set) allowSleep = _swig_property(_Box2D.b2BodyDef_allowSleep_get, _Box2D.b2BodyDef_allowSleep_set) awake = _swig_property(_Box2D.b2BodyDef_awake_get, _Box2D.b2BodyDef_awake_set) fixedRotation = _swig_property(_Box2D.b2BodyDef_fixedRotation_get, _Box2D.b2BodyDef_fixedRotation_set) bullet = _swig_property(_Box2D.b2BodyDef_bullet_get, _Box2D.b2BodyDef_bullet_set) active = _swig_property(_Box2D.b2BodyDef_active_get, _Box2D.b2BodyDef_active_set) gravityScale = _swig_property(_Box2D.b2BodyDef_gravityScale_get, _Box2D.b2BodyDef_gravityScale_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2BodyDef self) -> long""" return _Box2D.b2BodyDef___hash__(self) def __repr__(self): return _format_repr(self) def __GetUserData(self): """__GetUserData(b2BodyDef self) -> PyObject *""" return _Box2D.b2BodyDef___GetUserData(self) def __SetUserData(self, data): """__SetUserData(b2BodyDef self, PyObject * data)""" return _Box2D.b2BodyDef___SetUserData(self, data) def ClearUserData(self): """ClearUserData(b2BodyDef self)""" return _Box2D.b2BodyDef_ClearUserData(self) userData = property(__GetUserData, __SetUserData) def __del__(self): self.ClearUserData() _fixtures = None _shapes = None _shapeFixture = None @property def fixtures(self): return self._fixtures @fixtures.setter def fixtures(self, fixtures): if isinstance(fixtures, b2FixtureDef): self._fixtures = [fixtures] else: self._fixtures = list(fixtures) @property def shapes(self): return self._shapes @shapes.setter def shapes(self, shapes): if isinstance(shapes, b2Shape): self._shapes = [shapes] else: self._shapes = list(shapes) @property def shapeFixture(self): return self._shapeFixture @shapeFixture.setter def shapeFixture(self, fixture): self._shapeFixture = fixture __swig_destroy__ = _Box2D.delete_b2BodyDef b2BodyDef.__hash__ = new_instancemethod(_Box2D.b2BodyDef___hash__, None, b2BodyDef) b2BodyDef.__GetUserData = new_instancemethod(_Box2D.b2BodyDef___GetUserData, None, b2BodyDef) b2BodyDef.__SetUserData = new_instancemethod(_Box2D.b2BodyDef___SetUserData, None, b2BodyDef) b2BodyDef.ClearUserData = new_instancemethod(_Box2D.b2BodyDef_ClearUserData, None, b2BodyDef) b2BodyDef_swigregister = _Box2D.b2BodyDef_swigregister b2BodyDef_swigregister(b2BodyDef) class b2Body(object): """A rigid body. These are created via b2World::CreateBody.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def __SetTransform(self, position, angle): """ __SetTransform(b2Body self, b2Vec2 position, float32 angle) Set the position of the body's origin and rotation. This breaks any contacts and wakes the other bodies. Manipulating a body's transform may cause non-physical behavior. Parameters: ----------- position: the world position of the body's local origin. angle: the world rotation in radians. """ return _Box2D.b2Body___SetTransform(self, position, angle) def __GetTransform(self): """ __GetTransform(b2Body self) -> b2Transform Get the body transform for the body's origin. the world transform of the body's origin. """ return _Box2D.b2Body___GetTransform(self) def __GetPosition(self): """ __GetPosition(b2Body self) -> b2Vec2 Get the world body origin position. the world position of the body's origin. """ return _Box2D.b2Body___GetPosition(self) def __GetAngle(self): """ __GetAngle(b2Body self) -> float32 Get the angle in radians. the current world rotation angle in radians. """ return _Box2D.b2Body___GetAngle(self) def __GetWorldCenter(self): """ __GetWorldCenter(b2Body self) -> b2Vec2 Get the world position of the center of mass. """ return _Box2D.b2Body___GetWorldCenter(self) def __GetLocalCenter(self): """ __GetLocalCenter(b2Body self) -> b2Vec2 Get the local position of the center of mass. """ return _Box2D.b2Body___GetLocalCenter(self) def __SetLinearVelocity(self, v): """ __SetLinearVelocity(b2Body self, b2Vec2 v) Set the linear velocity of the center of mass. Parameters: ----------- v: the new linear velocity of the center of mass. """ return _Box2D.b2Body___SetLinearVelocity(self, v) def __GetLinearVelocity(self): """ __GetLinearVelocity(b2Body self) -> b2Vec2 Get the linear velocity of the center of mass. the linear velocity of the center of mass. """ return _Box2D.b2Body___GetLinearVelocity(self) def __SetAngularVelocity(self, omega): """ __SetAngularVelocity(b2Body self, float32 omega) Set the angular velocity. Parameters: ----------- omega: the new angular velocity in radians/second. """ return _Box2D.b2Body___SetAngularVelocity(self, omega) def __GetAngularVelocity(self): """ __GetAngularVelocity(b2Body self) -> float32 Get the angular velocity. the angular velocity in radians/second. """ return _Box2D.b2Body___GetAngularVelocity(self) def ApplyForce(self, force, point, wake): """ ApplyForce(b2Body self, b2Vec2 force, b2Vec2 point, bool wake) Apply a force at a world point. If the force is not applied at the center of mass, it will generate a torque and affect the angular velocity. This wakes up the body. Parameters: ----------- force: the world force vector, usually in Newtons (N). point: the world position of the point of application. """ return _Box2D.b2Body_ApplyForce(self, force, point, wake) def ApplyForceToCenter(self, force, wake): """ApplyForceToCenter(b2Body self, b2Vec2 force, bool wake)""" return _Box2D.b2Body_ApplyForceToCenter(self, force, wake) def ApplyTorque(self, torque, wake): """ ApplyTorque(b2Body self, float32 torque, bool wake) Apply a torque. This affects the angular velocity without affecting the linear velocity of the center of mass. This wakes up the body. Parameters: ----------- torque: about the z-axis (out of the screen), usually in N-m. """ return _Box2D.b2Body_ApplyTorque(self, torque, wake) def ApplyLinearImpulse(self, impulse, point, wake): """ ApplyLinearImpulse(b2Body self, b2Vec2 impulse, b2Vec2 point, bool wake) Apply an impulse at a point. This immediately modifies the velocity. It also modifies the angular velocity if the point of application is not at the center of mass. This wakes up the body. Parameters: ----------- impulse: the world impulse vector, usually in N-seconds or kg-m/s. point: the world position of the point of application. """ return _Box2D.b2Body_ApplyLinearImpulse(self, impulse, point, wake) def ApplyAngularImpulse(self, impulse, wake): """ ApplyAngularImpulse(b2Body self, float32 impulse, bool wake) Apply an angular impulse. Parameters: ----------- impulse: the angular impulse in units of kg*m*m/s """ return _Box2D.b2Body_ApplyAngularImpulse(self, impulse, wake) def __GetMass(self): """ __GetMass(b2Body self) -> float32 Get the total mass of the body. the mass, usually in kilograms (kg). """ return _Box2D.b2Body___GetMass(self) def __GetInertia(self): """ __GetInertia(b2Body self) -> float32 Get the rotational inertia of the body about the local origin. the rotational inertia, usually in kg-m^2. """ return _Box2D.b2Body___GetInertia(self) def GetMassData(self, data): """ GetMassData(b2Body self, b2MassData data) Get the mass data of the body. a struct containing the mass, inertia and center of the body. """ return _Box2D.b2Body_GetMassData(self, data) def __SetMassData(self, data): """ __SetMassData(b2Body self, b2MassData data) Set the mass properties to override the mass properties of the fixtures. Note that this changes the center of mass position. Note that creating or destroying fixtures can also alter the mass. This function has no effect if the body isn't dynamic. Parameters: ----------- massData: the mass properties. """ return _Box2D.b2Body___SetMassData(self, data) def ResetMassData(self): """ ResetMassData(b2Body self) This resets the mass properties to the sum of the mass properties of the fixtures. This normally does not need to be called unless you called SetMassData to override the mass and you later want to reset the mass. """ return _Box2D.b2Body_ResetMassData(self) def GetWorldPoint(self, localPoint): """ GetWorldPoint(b2Body self, b2Vec2 localPoint) -> b2Vec2 Get the world coordinates of a point given the local coordinates. Parameters: ----------- localPoint: a point on the body measured relative the the body's origin. the same point expressed in world coordinates. """ return _Box2D.b2Body_GetWorldPoint(self, localPoint) def GetWorldVector(self, localVector): """ GetWorldVector(b2Body self, b2Vec2 localVector) -> b2Vec2 Get the world coordinates of a vector given the local coordinates. Parameters: ----------- localVector: a vector fixed in the body. the same vector expressed in world coordinates. """ return _Box2D.b2Body_GetWorldVector(self, localVector) def GetLocalPoint(self, worldPoint): """ GetLocalPoint(b2Body self, b2Vec2 worldPoint) -> b2Vec2 Gets a local point relative to the body's origin given a world point. Parameters: ----------- a: point in world coordinates. the corresponding local point relative to the body's origin. """ return _Box2D.b2Body_GetLocalPoint(self, worldPoint) def GetLocalVector(self, worldVector): """ GetLocalVector(b2Body self, b2Vec2 worldVector) -> b2Vec2 Gets a local vector given a world vector. Parameters: ----------- a: vector in world coordinates. the corresponding local vector. """ return _Box2D.b2Body_GetLocalVector(self, worldVector) def GetLinearVelocityFromWorldPoint(self, worldPoint): """ GetLinearVelocityFromWorldPoint(b2Body self, b2Vec2 worldPoint) -> b2Vec2 Get the world linear velocity of a world point attached to this body. Parameters: ----------- a: point in world coordinates. the world velocity of a point. """ return _Box2D.b2Body_GetLinearVelocityFromWorldPoint(self, worldPoint) def GetLinearVelocityFromLocalPoint(self, localPoint): """ GetLinearVelocityFromLocalPoint(b2Body self, b2Vec2 localPoint) -> b2Vec2 Get the world velocity of a local point. Parameters: ----------- a: point in local coordinates. the world velocity of a point. """ return _Box2D.b2Body_GetLinearVelocityFromLocalPoint(self, localPoint) def __GetLinearDamping(self): """ __GetLinearDamping(b2Body self) -> float32 Get the linear damping of the body. """ return _Box2D.b2Body___GetLinearDamping(self) def __SetLinearDamping(self, linearDamping): """ __SetLinearDamping(b2Body self, float32 linearDamping) Set the linear damping of the body. """ return _Box2D.b2Body___SetLinearDamping(self, linearDamping) def __GetAngularDamping(self): """ __GetAngularDamping(b2Body self) -> float32 Get the angular damping of the body. """ return _Box2D.b2Body___GetAngularDamping(self) def __SetAngularDamping(self, angularDamping): """ __SetAngularDamping(b2Body self, float32 angularDamping) Set the angular damping of the body. """ return _Box2D.b2Body___SetAngularDamping(self, angularDamping) def __GetGravityScale(self): """__GetGravityScale(b2Body self) -> float32""" return _Box2D.b2Body___GetGravityScale(self) def __SetGravityScale(self, scale): """__SetGravityScale(b2Body self, float32 scale)""" return _Box2D.b2Body___SetGravityScale(self, scale) def __SetType(self, type): """ __SetType(b2Body self, b2BodyType type) Set the type of this body. This may alter the mass and velocity. """ return _Box2D.b2Body___SetType(self, type) def __GetType(self): """ __GetType(b2Body self) -> b2BodyType Get the type of this body. """ return _Box2D.b2Body___GetType(self) def __SetBullet(self, flag): """ __SetBullet(b2Body self, bool flag) Should this body be treated like a bullet for continuous collision detection? """ return _Box2D.b2Body___SetBullet(self, flag) def __IsBullet(self): """ __IsBullet(b2Body self) -> bool Is this body treated like a bullet for continuous collision detection? """ return _Box2D.b2Body___IsBullet(self) def __SetSleepingAllowed(self, flag): """ __SetSleepingAllowed(b2Body self, bool flag) You can disable sleeping on this body. If you disable sleeping, the body will be woken. """ return _Box2D.b2Body___SetSleepingAllowed(self, flag) def __IsSleepingAllowed(self): """ __IsSleepingAllowed(b2Body self) -> bool Is this body allowed to sleep. """ return _Box2D.b2Body___IsSleepingAllowed(self) def __SetAwake(self, flag): """ __SetAwake(b2Body self, bool flag) Set the sleep state of the body. A sleeping body has very low CPU cost. Parameters: ----------- flag: set to true to put body to sleep, false to wake it. """ return _Box2D.b2Body___SetAwake(self, flag) def __IsAwake(self): """ __IsAwake(b2Body self) -> bool Get the sleeping state of this body. true if the body is sleeping. """ return _Box2D.b2Body___IsAwake(self) def __SetActive(self, flag): """ __SetActive(b2Body self, bool flag) Set the active state of the body. An inactive body is not simulated and cannot be collided with or woken up. If you pass a flag of true, all fixtures will be added to the broad-phase. If you pass a flag of false, all fixtures will be removed from the broad-phase and all contacts will be destroyed. Fixtures and joints are otherwise unaffected. You may continue to create/destroy fixtures and joints on inactive bodies. Fixtures on an inactive body are implicitly inactive and will not participate in collisions, ray-casts, or queries. Joints connected to an inactive body are implicitly inactive. An inactive body is still owned by a b2Worldobject and remains in the body list. """ return _Box2D.b2Body___SetActive(self, flag) def __IsActive(self): """ __IsActive(b2Body self) -> bool Get the active state of the body. """ return _Box2D.b2Body___IsActive(self) def __SetFixedRotation(self, flag): """ __SetFixedRotation(b2Body self, bool flag) Set this body to have fixed rotation. This causes the mass to be reset. """ return _Box2D.b2Body___SetFixedRotation(self, flag) def __IsFixedRotation(self): """ __IsFixedRotation(b2Body self) -> bool Does this body have fixed rotation? """ return _Box2D.b2Body___IsFixedRotation(self) def __GetFixtureList_internal(self, *args): """ __GetFixtureList_internal(b2Body self) -> b2Fixture __GetFixtureList_internal(b2Body self) -> b2Fixture Get the list of all fixtures attached to this body. """ return _Box2D.b2Body___GetFixtureList_internal(self, *args) def __GetJointList_internal(self, *args): """ __GetJointList_internal(b2Body self) -> b2JointEdge __GetJointList_internal(b2Body self) -> b2JointEdge Get the list of all joints attached to this body. """ return _Box2D.b2Body___GetJointList_internal(self, *args) def __GetContactList_internal(self, *args): """ __GetContactList_internal(b2Body self) -> b2ContactEdge __GetContactList_internal(b2Body self) -> b2ContactEdge Get the list of all contacts attached to this body. WARNING: this list changes during the time step and you may miss some collisions if you don't use b2ContactListener. """ return _Box2D.b2Body___GetContactList_internal(self, *args) def __GetNext(self, *args): """ __GetNext(b2Body self) -> b2Body __GetNext(b2Body self) -> b2Body Get the next body in the world's body list. """ return _Box2D.b2Body___GetNext(self, *args) def __GetWorld(self, *args): """ __GetWorld(b2Body self) -> b2World __GetWorld(b2Body self) -> b2World Get the parent world of this body. """ return _Box2D.b2Body___GetWorld(self, *args) def Dump(self): """Dump(b2Body self)""" return _Box2D.b2Body_Dump(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Body self) -> long""" return _Box2D.b2Body___hash__(self) def __repr__(self): return _format_repr(self) def DestroyFixture(self, fixture): """ DestroyFixture(b2Body self, b2Fixture fixture) Destroy a fixture. This removes the fixture from the broad-phase and destroys all contacts associated with this fixture. This will automatically adjust the mass of the body if the body is dynamic and the fixture has positive density. All fixtures attached to a body are implicitly destroyed when the body is destroyed. Parameters: ----------- fixture: the fixture to be removed. WARNING: This function is locked during callbacks. """ return _Box2D.b2Body_DestroyFixture(self, fixture) def __CreateFixture(self, *args): """ __CreateFixture(b2Body self, b2Shape shape, float32 density) -> b2Fixture __CreateFixture(b2Body self, b2FixtureDef defn) -> b2Fixture """ return _Box2D.b2Body___CreateFixture(self, *args) def __GetUserData(self): """__GetUserData(b2Body self) -> PyObject *""" return _Box2D.b2Body___GetUserData(self) def __SetUserData(self, data): """__SetUserData(b2Body self, PyObject * data)""" return _Box2D.b2Body___SetUserData(self, data) def ClearUserData(self): """ClearUserData(b2Body self)""" return _Box2D.b2Body_ClearUserData(self) userData = property(__GetUserData, __SetUserData) __eq__ = b2BodyCompare __ne__ = lambda self,other: not b2BodyCompare(self,other) def __GetMassData(self): """ Get a b2MassData object that represents this b2Body NOTE: To just get the mass, use body.mass """ ret = b2MassData() ret.center=self.localCenter ret.I = self.inertia ret.mass = self.mass return ret def __SetInertia(self, inertia): """ Set the body's inertia """ md = self.massData md.I = inertia self.massData=md def __SetMass(self, mass): """ Set the body's mass """ md = self.massData md.mass = mass self.massData=md def __SetLocalCenter(self, lcenter): """ Set the body's local center """ md = self.massData md.center = lcenter self.massData=md def __iter__(self): """ Iterates over the fixtures in the body """ for fixture in self.fixtures: yield fixture def __CreateShapeFixture(self, type_, **kwargs): """ Internal function to handle creating circles, polygons, etc. without first creating a fixture. type_ is b2Shape. """ shape=type_() fixture=b2FixtureDef(shape=shape) for key, value in kwargs.items(): # Note that these hasattrs use the types to get around # the fact that some properties are write-only (like 'box' in # polygon shapes), and as such do not show up with 'hasattr'. if hasattr(type_, key): to_set=shape elif hasattr(b2FixtureDef, key): to_set=fixture else: raise AttributeError('Property %s not found in either %s or b2FixtureDef' % (key, type_.__name__)) try: setattr(to_set, key, value) except Exception as ex: raise ex.__class__('Failed on kwargs, class="%s" key="%s": %s' \ % (to_set.__class__.__name__, key, ex)) return self.CreateFixture(fixture) def CreatePolygonFixture(self, **kwargs): """ Create a polygon shape without an explicit fixture definition. Takes kwargs; you can pass in properties for either the polygon or the fixture to this function. For example: CreatePolygonFixture(box=(1, 1), friction=0.2, density=1.0) where 'box' is a property from the polygon shape, and 'friction' and 'density' are from the fixture definition. """ return self.__CreateShapeFixture(b2PolygonShape, **kwargs) def CreateCircleFixture(self, **kwargs): """ Create a circle shape without an explicit fixture definition. Takes kwargs; you can pass in properties for either the circle or the fixture to this function. For example: CreateCircleFixture(radius=0.2, friction=0.2, density=1.0) where 'radius' is a property from the circle shape, and 'friction' and 'density' are from the fixture definition. """ return self.__CreateShapeFixture(b2CircleShape, **kwargs) def CreateEdgeFixture(self, **kwargs): """ Create a edge shape without an explicit fixture definition. Takes kwargs; you can pass in properties for either the edge or the fixture to this function. For example: CreateEdgeFixture(vertices=[(0,0),(1,0)], friction=0.2, density=1.0) where 'vertices' is a property from the edge shape, and 'friction' and 'density' are from the fixture definition. """ return self.__CreateShapeFixture(b2EdgeShape, **kwargs) def CreateLoopFixture(self, **kwargs): """ Create a loop shape without an explicit fixture definition. Takes kwargs; you can pass in properties for either the loop or the fixture to this function. For example: CreateLoopFixture(vertices=[...], friction=0.2, density=1.0) where 'vertices' is a property from the loop shape, and 'friction' and 'density' are from the fixture definition. """ return self.__CreateShapeFixture(b2ChainShape, **kwargs) CreateChainFixture = CreateLoopFixture def CreateFixturesFromShapes(self, shapes=None, shapeFixture=None): """ Create fixture(s) on the body from one or more shapes, and optionally a single fixture definition. Takes kwargs; examples of valid combinations are as follows: CreateFixturesFromShapes(shapes=b2CircleShape(radius=0.2)) CreateFixturesFromShapes(shapes=b2CircleShape(radius=0.2), shapeFixture=b2FixtureDef(friction=0.2)) CreateFixturesFromShapes(shapes=[b2CircleShape(radius=0.2), b2PolygonShape(box=[1,2])]) """ if shapes==None: raise TypeError('At least one shape required') if shapeFixture==None: shapeFixture=b2FixtureDef() oldShape=None else: oldShape = shapeFixture.shape ret=None try: if isinstance(shapes, (list, tuple)): ret = [] for shape in shapes: shapeFixture.shape = shape ret.append(self.__CreateFixture(shapeFixture)) else: shapeFixture.shape=shapes ret = self.__CreateFixture(shapeFixture) finally: shapeFixture.shape=oldShape return ret def CreateFixture(self, defn=None, **kwargs): """ Create a fixtures on the body. Takes kwargs; examples of valid combinations are as follows: CreateFixture(b2FixtureDef(shape=s, restitution=0.2, ...)) CreateFixture(shape=s, restitution=0.2, ...) """ if defn is not None and isinstance(defn, b2FixtureDef): return self.__CreateFixture(defn) else: if 'shape' not in kwargs: raise ValueError('Must specify the shape for the fixture') return self.__CreateFixture(b2FixtureDef(**kwargs)) def CreateEdgeChain(self, edge_list): """ Creates a body a set of connected edge chains. Expects edge_list to be a list of vertices, length >= 2. """ prev=None if len(edge_list) < 2: raise ValueError('Edge list length >= 2') shape=b2EdgeShape(vertices=[list(i) for i in edge_list[0:2]]) self.CreateFixturesFromShapes(shape) prev = edge_list[1] for edge in edge_list[1:]: if len(edge) != 2: raise ValueError('Vertex length != 2, "%s"' % list(edge)) shape.vertices = [list(prev), list(edge)] self.CreateFixturesFromShapes(shape) prev=edge # Read-write properties sleepingAllowed = property(__IsSleepingAllowed, __SetSleepingAllowed) angularVelocity = property(__GetAngularVelocity, __SetAngularVelocity) linearVelocity = property(__GetLinearVelocity, __SetLinearVelocity) awake = property(__IsAwake, __SetAwake) angularDamping = property(__GetAngularDamping, __SetAngularDamping) fixedRotation = property(__IsFixedRotation, __SetFixedRotation) linearDamping = property(__GetLinearDamping, __SetLinearDamping) bullet = property(__IsBullet, __SetBullet) type = property(__GetType, __SetType) active = property(__IsActive, __SetActive) angle = property(__GetAngle, lambda self, angle: self.__SetTransform(self.position, angle)) transform = property(__GetTransform, lambda self, value: self.__SetTransform(*value)) massData = property(__GetMassData, __SetMassData) mass = property(__GetMass, __SetMass) localCenter = property(__GetLocalCenter, __SetLocalCenter) inertia = property(__GetInertia, __SetInertia) position = property(__GetPosition, lambda self, pos: self.__SetTransform(pos, self.angle)) gravityScale = property(__GetGravityScale, __SetGravityScale) # Read-only joints = property(lambda self: _list_from_linked_list(self.__GetJointList_internal()), None, doc="""All joints connected to the body as a list. NOTE: This re-creates the list on every call. See also joints_gen.""") contacts = property(lambda self: _list_from_linked_list(self.__GetContactList_internal()), None, doc="""All contacts related to the body as a list. NOTE: This re-creates the list on every call. See also contacts_gen.""") fixtures = property(lambda self: _list_from_linked_list(self.__GetFixtureList_internal()), None, doc="""All fixtures contained in this body as a list. NOTE: This re-creates the list on every call. See also fixtures_gen.""") joints_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetJointList_internal())), None, doc="""Indexable generator of the connected joints to this body. NOTE: When not using the whole list, this may be preferable to using 'joints'.""") contacts_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetContactList_internal())), None, doc="""Indexable generator of the related contacts. NOTE: When not using the whole list, this may be preferable to using 'contacts'.""") fixtures_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetFixtureList_internal())), None, doc="""Indexable generator of the contained fixtures. NOTE: When not using the whole list, this may be preferable to using 'fixtures'.""") next = property(__GetNext, None) worldCenter = property(__GetWorldCenter, None) world = property(__GetWorld, None) b2Body.__SetTransform = new_instancemethod(_Box2D.b2Body___SetTransform, None, b2Body) b2Body.__GetTransform = new_instancemethod(_Box2D.b2Body___GetTransform, None, b2Body) b2Body.__GetPosition = new_instancemethod(_Box2D.b2Body___GetPosition, None, b2Body) b2Body.__GetAngle = new_instancemethod(_Box2D.b2Body___GetAngle, None, b2Body) b2Body.__GetWorldCenter = new_instancemethod(_Box2D.b2Body___GetWorldCenter, None, b2Body) b2Body.__GetLocalCenter = new_instancemethod(_Box2D.b2Body___GetLocalCenter, None, b2Body) b2Body.__SetLinearVelocity = new_instancemethod(_Box2D.b2Body___SetLinearVelocity, None, b2Body) b2Body.__GetLinearVelocity = new_instancemethod(_Box2D.b2Body___GetLinearVelocity, None, b2Body) b2Body.__SetAngularVelocity = new_instancemethod(_Box2D.b2Body___SetAngularVelocity, None, b2Body) b2Body.__GetAngularVelocity = new_instancemethod(_Box2D.b2Body___GetAngularVelocity, None, b2Body) b2Body.ApplyForce = new_instancemethod(_Box2D.b2Body_ApplyForce, None, b2Body) b2Body.ApplyForceToCenter = new_instancemethod(_Box2D.b2Body_ApplyForceToCenter, None, b2Body) b2Body.ApplyTorque = new_instancemethod(_Box2D.b2Body_ApplyTorque, None, b2Body) b2Body.ApplyLinearImpulse = new_instancemethod(_Box2D.b2Body_ApplyLinearImpulse, None, b2Body) b2Body.ApplyAngularImpulse = new_instancemethod(_Box2D.b2Body_ApplyAngularImpulse, None, b2Body) b2Body.__GetMass = new_instancemethod(_Box2D.b2Body___GetMass, None, b2Body) b2Body.__GetInertia = new_instancemethod(_Box2D.b2Body___GetInertia, None, b2Body) b2Body.GetMassData = new_instancemethod(_Box2D.b2Body_GetMassData, None, b2Body) b2Body.__SetMassData = new_instancemethod(_Box2D.b2Body___SetMassData, None, b2Body) b2Body.ResetMassData = new_instancemethod(_Box2D.b2Body_ResetMassData, None, b2Body) b2Body.GetWorldPoint = new_instancemethod(_Box2D.b2Body_GetWorldPoint, None, b2Body) b2Body.GetWorldVector = new_instancemethod(_Box2D.b2Body_GetWorldVector, None, b2Body) b2Body.GetLocalPoint = new_instancemethod(_Box2D.b2Body_GetLocalPoint, None, b2Body) b2Body.GetLocalVector = new_instancemethod(_Box2D.b2Body_GetLocalVector, None, b2Body) b2Body.GetLinearVelocityFromWorldPoint = new_instancemethod(_Box2D.b2Body_GetLinearVelocityFromWorldPoint, None, b2Body) b2Body.GetLinearVelocityFromLocalPoint = new_instancemethod(_Box2D.b2Body_GetLinearVelocityFromLocalPoint, None, b2Body) b2Body.__GetLinearDamping = new_instancemethod(_Box2D.b2Body___GetLinearDamping, None, b2Body) b2Body.__SetLinearDamping = new_instancemethod(_Box2D.b2Body___SetLinearDamping, None, b2Body) b2Body.__GetAngularDamping = new_instancemethod(_Box2D.b2Body___GetAngularDamping, None, b2Body) b2Body.__SetAngularDamping = new_instancemethod(_Box2D.b2Body___SetAngularDamping, None, b2Body) b2Body.__GetGravityScale = new_instancemethod(_Box2D.b2Body___GetGravityScale, None, b2Body) b2Body.__SetGravityScale = new_instancemethod(_Box2D.b2Body___SetGravityScale, None, b2Body) b2Body.__SetType = new_instancemethod(_Box2D.b2Body___SetType, None, b2Body) b2Body.__GetType = new_instancemethod(_Box2D.b2Body___GetType, None, b2Body) b2Body.__SetBullet = new_instancemethod(_Box2D.b2Body___SetBullet, None, b2Body) b2Body.__IsBullet = new_instancemethod(_Box2D.b2Body___IsBullet, None, b2Body) b2Body.__SetSleepingAllowed = new_instancemethod(_Box2D.b2Body___SetSleepingAllowed, None, b2Body) b2Body.__IsSleepingAllowed = new_instancemethod(_Box2D.b2Body___IsSleepingAllowed, None, b2Body) b2Body.__SetAwake = new_instancemethod(_Box2D.b2Body___SetAwake, None, b2Body) b2Body.__IsAwake = new_instancemethod(_Box2D.b2Body___IsAwake, None, b2Body) b2Body.__SetActive = new_instancemethod(_Box2D.b2Body___SetActive, None, b2Body) b2Body.__IsActive = new_instancemethod(_Box2D.b2Body___IsActive, None, b2Body) b2Body.__SetFixedRotation = new_instancemethod(_Box2D.b2Body___SetFixedRotation, None, b2Body) b2Body.__IsFixedRotation = new_instancemethod(_Box2D.b2Body___IsFixedRotation, None, b2Body) b2Body.__GetFixtureList_internal = new_instancemethod(_Box2D.b2Body___GetFixtureList_internal, None, b2Body) b2Body.__GetJointList_internal = new_instancemethod(_Box2D.b2Body___GetJointList_internal, None, b2Body) b2Body.__GetContactList_internal = new_instancemethod(_Box2D.b2Body___GetContactList_internal, None, b2Body) b2Body.__GetNext = new_instancemethod(_Box2D.b2Body___GetNext, None, b2Body) b2Body.__GetWorld = new_instancemethod(_Box2D.b2Body___GetWorld, None, b2Body) b2Body.Dump = new_instancemethod(_Box2D.b2Body_Dump, None, b2Body) b2Body.__hash__ = new_instancemethod(_Box2D.b2Body___hash__, None, b2Body) b2Body.DestroyFixture = new_instancemethod(_Box2D.b2Body_DestroyFixture, None, b2Body) b2Body.__CreateFixture = new_instancemethod(_Box2D.b2Body___CreateFixture, None, b2Body) b2Body.__GetUserData = new_instancemethod(_Box2D.b2Body___GetUserData, None, b2Body) b2Body.__SetUserData = new_instancemethod(_Box2D.b2Body___SetUserData, None, b2Body) b2Body.ClearUserData = new_instancemethod(_Box2D.b2Body_ClearUserData, None, b2Body) b2Body_swigregister = _Box2D.b2Body_swigregister b2Body_swigregister(b2Body) class b2Filter(object): """This holds contact filtering data.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2Filter_swiginit(self,_Box2D.new_b2Filter()) _init_kwargs(self, **kwargs) categoryBits = _swig_property(_Box2D.b2Filter_categoryBits_get, _Box2D.b2Filter_categoryBits_set) maskBits = _swig_property(_Box2D.b2Filter_maskBits_get, _Box2D.b2Filter_maskBits_set) groupIndex = _swig_property(_Box2D.b2Filter_groupIndex_get, _Box2D.b2Filter_groupIndex_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Filter self) -> long""" return _Box2D.b2Filter___hash__(self) def __repr__(self): return _format_repr(self) __swig_destroy__ = _Box2D.delete_b2Filter b2Filter.__hash__ = new_instancemethod(_Box2D.b2Filter___hash__, None, b2Filter) b2Filter_swigregister = _Box2D.b2Filter_swigregister b2Filter_swigregister(b2Filter) class b2FixtureDef(object): """A fixture definition is used to create a fixture. This class defines an abstract fixture definition. You can reuse fixture definitions safely.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2FixtureDef_swiginit(self,_Box2D.new_b2FixtureDef()) _init_kwargs(self, **kwargs) shape = _swig_property(_Box2D.b2FixtureDef_shape_get, _Box2D.b2FixtureDef_shape_set) friction = _swig_property(_Box2D.b2FixtureDef_friction_get, _Box2D.b2FixtureDef_friction_set) restitution = _swig_property(_Box2D.b2FixtureDef_restitution_get, _Box2D.b2FixtureDef_restitution_set) density = _swig_property(_Box2D.b2FixtureDef_density_get, _Box2D.b2FixtureDef_density_set) isSensor = _swig_property(_Box2D.b2FixtureDef_isSensor_get, _Box2D.b2FixtureDef_isSensor_set) filter = _swig_property(_Box2D.b2FixtureDef_filter_get, _Box2D.b2FixtureDef_filter_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2FixtureDef self) -> long""" return _Box2D.b2FixtureDef___hash__(self) def __repr__(self): return _format_repr(self) def __GetUserData(self): """__GetUserData(b2FixtureDef self) -> PyObject *""" return _Box2D.b2FixtureDef___GetUserData(self) def __SetUserData(self, data): """__SetUserData(b2FixtureDef self, PyObject * data)""" return _Box2D.b2FixtureDef___SetUserData(self, data) def ClearUserData(self): """ClearUserData(b2FixtureDef self)""" return _Box2D.b2FixtureDef_ClearUserData(self) userData = property(__GetUserData, __SetUserData) def __del__(self): self.ClearUserData() def __SetCategoryBits(self, value): self.filter.categoryBits=value def __SetGroupIndex(self, value): self.filter.groupIndex=value def __SetMaskBits(self, value): self.filter.maskBits=value categoryBits=property(lambda self: self.filter.categoryBits, __SetCategoryBits) groupIndex=property(lambda self: self.filter.groupIndex, __SetGroupIndex) maskBits=property(lambda self: self.filter.maskBits, __SetMaskBits) __swig_destroy__ = _Box2D.delete_b2FixtureDef b2FixtureDef.__hash__ = new_instancemethod(_Box2D.b2FixtureDef___hash__, None, b2FixtureDef) b2FixtureDef.__GetUserData = new_instancemethod(_Box2D.b2FixtureDef___GetUserData, None, b2FixtureDef) b2FixtureDef.__SetUserData = new_instancemethod(_Box2D.b2FixtureDef___SetUserData, None, b2FixtureDef) b2FixtureDef.ClearUserData = new_instancemethod(_Box2D.b2FixtureDef_ClearUserData, None, b2FixtureDef) b2FixtureDef_swigregister = _Box2D.b2FixtureDef_swigregister b2FixtureDef_swigregister(b2FixtureDef) class b2FixtureProxy(object): """This proxy is used internally to connect fixtures to the broad-phase.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr aabb = _swig_property(_Box2D.b2FixtureProxy_aabb_get, _Box2D.b2FixtureProxy_aabb_set) fixture = _swig_property(_Box2D.b2FixtureProxy_fixture_get, _Box2D.b2FixtureProxy_fixture_set) childIndex = _swig_property(_Box2D.b2FixtureProxy_childIndex_get, _Box2D.b2FixtureProxy_childIndex_set) proxyId = _swig_property(_Box2D.b2FixtureProxy_proxyId_get, _Box2D.b2FixtureProxy_proxyId_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2FixtureProxy self) -> long""" return _Box2D.b2FixtureProxy___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self): """ __init__(b2FixtureProxy self) -> b2FixtureProxy This proxy is used internally to connect fixtures to the broad-phase. """ _Box2D.b2FixtureProxy_swiginit(self, _Box2D.new_b2FixtureProxy()) __swig_destroy__ = _Box2D.delete_b2FixtureProxy b2FixtureProxy.__hash__ = new_instancemethod(_Box2D.b2FixtureProxy___hash__, None, b2FixtureProxy) b2FixtureProxy_swigregister = _Box2D.b2FixtureProxy_swigregister b2FixtureProxy_swigregister(b2FixtureProxy) class b2Fixture(object): """ A fixture is used to attach a shape to a body for collision detection. A fixture inherits its transform from its parent. Fixtures hold additional non-geometric data such as friction, collision filters, etc. Fixtures are created via b2Body::CreateFixture. WARNING: you cannot reuse fixtures. """ thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def __GetType(self): """ __GetType(b2Fixture self) -> b2Shape::Type Get the type of the child shape. You can use this to down cast to the concrete shape. the shape type. """ return _Box2D.b2Fixture___GetType(self) def __GetShape(self, *args): """ __GetShape(b2Fixture self) -> b2Shape __GetShape(b2Fixture self) -> b2Shape Get the child shape. You can modify the child shape, however you should not change the number of vertices because this will crash some collision caching mechanisms. Manipulating the shape may lead to non-physical behavior. """ return _Box2D.b2Fixture___GetShape(self, *args) def __SetSensor(self, sensor): """ __SetSensor(b2Fixture self, bool sensor) Set if this fixture is a sensor. """ return _Box2D.b2Fixture___SetSensor(self, sensor) def __IsSensor(self): """ __IsSensor(b2Fixture self) -> bool Is this fixture a sensor (non-solid)? the true if the shape is a sensor. """ return _Box2D.b2Fixture___IsSensor(self) def __SetFilterData(self, filter): """ __SetFilterData(b2Fixture self, b2Filter filter) Set the contact filtering data. This will not update contacts until the next time step when either parent body is active and awake. This automatically calls Refilter. """ return _Box2D.b2Fixture___SetFilterData(self, filter) def __GetFilterData(self): """ __GetFilterData(b2Fixture self) -> b2Filter Get the contact filtering data. """ return _Box2D.b2Fixture___GetFilterData(self) def Refilter(self): """ Refilter(b2Fixture self) Call this if you want to establish collision that was previously disabled by b2ContactFilter::ShouldCollide. """ return _Box2D.b2Fixture_Refilter(self) def __GetBody(self, *args): """ __GetBody(b2Fixture self) -> b2Body __GetBody(b2Fixture self) -> b2Body Get the parent body of this fixture. This is NULL if the fixture is not attached. the parent body. """ return _Box2D.b2Fixture___GetBody(self, *args) def __GetNext(self, *args): """ __GetNext(b2Fixture self) -> b2Fixture __GetNext(b2Fixture self) -> b2Fixture Get the next fixture in the parent body's fixture list. the next shape. """ return _Box2D.b2Fixture___GetNext(self, *args) def TestPoint(self, p): """ TestPoint(b2Fixture self, b2Vec2 p) -> bool Test a point for containment in this fixture. Parameters: ----------- p: a point in world coordinates. """ return _Box2D.b2Fixture_TestPoint(self, p) def RayCast(self, output, input, childIndex): """ RayCast(b2Fixture self, b2RayCastOutput output, b2RayCastInput input, int32 childIndex) -> bool Cast a ray against this shape. Parameters: ----------- output: the ray-cast results. input: the ray-cast input parameters. """ return _Box2D.b2Fixture_RayCast(self, output, input, childIndex) def __GetMassData(self, massData): """ __GetMassData(b2Fixture self, b2MassData massData) Get the mass data for this fixture. The mass data is based on the density and the shape. The rotational inertia is about the shape's origin. This operation may be expensive. """ return _Box2D.b2Fixture___GetMassData(self, massData) def __SetDensity(self, density): """ __SetDensity(b2Fixture self, float32 density) Set the density of this fixture. This will _not_ automatically adjust the mass of the body. You must call b2Body::ResetMassDatato update the body's mass. """ return _Box2D.b2Fixture___SetDensity(self, density) def __GetDensity(self): """ __GetDensity(b2Fixture self) -> float32 Get the density of this fixture. """ return _Box2D.b2Fixture___GetDensity(self) def __GetFriction(self): """ __GetFriction(b2Fixture self) -> float32 Get the coefficient of friction. """ return _Box2D.b2Fixture___GetFriction(self) def __SetFriction(self, friction): """ __SetFriction(b2Fixture self, float32 friction) Set the coefficient of friction. This will immediately update the mixed friction on all associated contacts. """ return _Box2D.b2Fixture___SetFriction(self, friction) def __GetRestitution(self): """ __GetRestitution(b2Fixture self) -> float32 Get the coefficient of restitution. """ return _Box2D.b2Fixture___GetRestitution(self) def __SetRestitution(self, restitution): """ __SetRestitution(b2Fixture self, float32 restitution) Set the coefficient of restitution. This will immediately update the mixed restitution on all associated contacts. """ return _Box2D.b2Fixture___SetRestitution(self, restitution) def GetAABB(self, childIndex): """ GetAABB(b2Fixture self, int32 childIndex) -> b2AABB Get the fixture's AABB. This AABB may be enlarge and/or stale. If you need a more accurate AABB, compute it using the shape and the body transform. """ return _Box2D.b2Fixture_GetAABB(self, childIndex) def Dump(self, bodyIndex): """Dump(b2Fixture self, int32 bodyIndex)""" return _Box2D.b2Fixture_Dump(self, bodyIndex) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Fixture self) -> long""" return _Box2D.b2Fixture___hash__(self) def __repr__(self): return _format_repr(self) def __GetUserData(self): """__GetUserData(b2Fixture self) -> PyObject *""" return _Box2D.b2Fixture___GetUserData(self) def __SetUserData(self, data): """__SetUserData(b2Fixture self, PyObject * data)""" return _Box2D.b2Fixture___SetUserData(self, data) def ClearUserData(self): """ClearUserData(b2Fixture self)""" return _Box2D.b2Fixture_ClearUserData(self) userData = property(__GetUserData, __SetUserData) __swig_destroy__ = _Box2D.delete_b2Fixture __eq__ = b2FixtureCompare __ne__ = lambda self,other: not b2FixtureCompare(self,other) # Read-write properties friction = property(__GetFriction, __SetFriction) restitution = property(__GetRestitution, __SetRestitution) filterData = property(__GetFilterData, __SetFilterData) sensor = property(__IsSensor, __SetSensor) density = property(__GetDensity, __SetDensity) # Read-only next = property(__GetNext, None) type = property(__GetType, None) shape = property(__GetShape, None) body = property(__GetBody, None) @property def massData(self): md=b2MassData() self.__GetMassData(md) return md b2Fixture.__GetType = new_instancemethod(_Box2D.b2Fixture___GetType, None, b2Fixture) b2Fixture.__GetShape = new_instancemethod(_Box2D.b2Fixture___GetShape, None, b2Fixture) b2Fixture.__SetSensor = new_instancemethod(_Box2D.b2Fixture___SetSensor, None, b2Fixture) b2Fixture.__IsSensor = new_instancemethod(_Box2D.b2Fixture___IsSensor, None, b2Fixture) b2Fixture.__SetFilterData = new_instancemethod(_Box2D.b2Fixture___SetFilterData, None, b2Fixture) b2Fixture.__GetFilterData = new_instancemethod(_Box2D.b2Fixture___GetFilterData, None, b2Fixture) b2Fixture.Refilter = new_instancemethod(_Box2D.b2Fixture_Refilter, None, b2Fixture) b2Fixture.__GetBody = new_instancemethod(_Box2D.b2Fixture___GetBody, None, b2Fixture) b2Fixture.__GetNext = new_instancemethod(_Box2D.b2Fixture___GetNext, None, b2Fixture) b2Fixture.TestPoint = new_instancemethod(_Box2D.b2Fixture_TestPoint, None, b2Fixture) b2Fixture.RayCast = new_instancemethod(_Box2D.b2Fixture_RayCast, None, b2Fixture) b2Fixture.__GetMassData = new_instancemethod(_Box2D.b2Fixture___GetMassData, None, b2Fixture) b2Fixture.__SetDensity = new_instancemethod(_Box2D.b2Fixture___SetDensity, None, b2Fixture) b2Fixture.__GetDensity = new_instancemethod(_Box2D.b2Fixture___GetDensity, None, b2Fixture) b2Fixture.__GetFriction = new_instancemethod(_Box2D.b2Fixture___GetFriction, None, b2Fixture) b2Fixture.__SetFriction = new_instancemethod(_Box2D.b2Fixture___SetFriction, None, b2Fixture) b2Fixture.__GetRestitution = new_instancemethod(_Box2D.b2Fixture___GetRestitution, None, b2Fixture) b2Fixture.__SetRestitution = new_instancemethod(_Box2D.b2Fixture___SetRestitution, None, b2Fixture) b2Fixture.GetAABB = new_instancemethod(_Box2D.b2Fixture_GetAABB, None, b2Fixture) b2Fixture.Dump = new_instancemethod(_Box2D.b2Fixture_Dump, None, b2Fixture) b2Fixture.__hash__ = new_instancemethod(_Box2D.b2Fixture___hash__, None, b2Fixture) b2Fixture.__GetUserData = new_instancemethod(_Box2D.b2Fixture___GetUserData, None, b2Fixture) b2Fixture.__SetUserData = new_instancemethod(_Box2D.b2Fixture___SetUserData, None, b2Fixture) b2Fixture.ClearUserData = new_instancemethod(_Box2D.b2Fixture_ClearUserData, None, b2Fixture) b2Fixture_swigregister = _Box2D.b2Fixture_swigregister b2Fixture_swigregister(b2Fixture) class b2DestructionListener(object): """Joints and fixtures are destroyed when their associated body is destroyed. Implement this listener so that you may nullify references to these joints and shapes.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr __swig_destroy__ = _Box2D.delete_b2DestructionListener def SayGoodbye(self, *args): """ SayGoodbye(b2DestructionListener self, b2Joint joint) SayGoodbye(b2DestructionListener self, b2Fixture fixture) Called when any fixture is about to be destroyed due to the destruction of its parent body. """ return _Box2D.b2DestructionListener_SayGoodbye(self, *args) __dir__ = _dir_filter def __hash__(self): """__hash__(b2DestructionListener self) -> long""" return _Box2D.b2DestructionListener___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): if self.__class__ == b2DestructionListener: _self = None else: _self = self _Box2D.b2DestructionListener_swiginit(self,_Box2D.new_b2DestructionListener(_self, )) _init_kwargs(self, **kwargs) def __disown__(self): self.this.disown() _Box2D.disown_b2DestructionListener(self) return weakref_proxy(self) b2DestructionListener.SayGoodbye = new_instancemethod(_Box2D.b2DestructionListener_SayGoodbye, None, b2DestructionListener) b2DestructionListener.__hash__ = new_instancemethod(_Box2D.b2DestructionListener___hash__, None, b2DestructionListener) b2DestructionListener_swigregister = _Box2D.b2DestructionListener_swigregister b2DestructionListener_swigregister(b2DestructionListener) class b2ContactFilter(object): """Implement this class to provide collision filtering. In other words, you can implement this class if you want finer control over contact creation.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr __swig_destroy__ = _Box2D.delete_b2ContactFilter def ShouldCollide(self, fixtureA, fixtureB): """ ShouldCollide(b2ContactFilter self, b2Fixture fixtureA, b2Fixture fixtureB) -> bool Return true if contact calculations should be performed between these two shapes. WARNING: for performance reasons this is only called when the AABBs begin to overlap. """ return _Box2D.b2ContactFilter_ShouldCollide(self, fixtureA, fixtureB) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ContactFilter self) -> long""" return _Box2D.b2ContactFilter___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): if self.__class__ == b2ContactFilter: _self = None else: _self = self _Box2D.b2ContactFilter_swiginit(self,_Box2D.new_b2ContactFilter(_self, )) _init_kwargs(self, **kwargs) def __disown__(self): self.this.disown() _Box2D.disown_b2ContactFilter(self) return weakref_proxy(self) b2ContactFilter.ShouldCollide = new_instancemethod(_Box2D.b2ContactFilter_ShouldCollide, None, b2ContactFilter) b2ContactFilter.__hash__ = new_instancemethod(_Box2D.b2ContactFilter___hash__, None, b2ContactFilter) b2ContactFilter_swigregister = _Box2D.b2ContactFilter_swigregister b2ContactFilter_swigregister(b2ContactFilter) class b2ContactImpulse(object): """Contact impulses for reporting. Impulses are used instead of forces because sub-step forces may approach infinity for rigid body collisions. These match up one-to-one with the contact points in b2Manifold.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr count = _swig_property(_Box2D.b2ContactImpulse_count_get, _Box2D.b2ContactImpulse_count_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ContactImpulse self) -> long""" return _Box2D.b2ContactImpulse___hash__(self) def __repr__(self): return _format_repr(self) def __get_normal_impulses(self): """__get_normal_impulses(b2ContactImpulse self) -> PyObject *""" return _Box2D.b2ContactImpulse___get_normal_impulses(self) def __get_tangent_impulses(self): """__get_tangent_impulses(b2ContactImpulse self) -> PyObject *""" return _Box2D.b2ContactImpulse___get_tangent_impulses(self) normalImpulses = property(__get_normal_impulses, None) tangentImpulses = property(__get_tangent_impulses, None) def __init__(self, **kwargs): _Box2D.b2ContactImpulse_swiginit(self,_Box2D.new_b2ContactImpulse()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2ContactImpulse b2ContactImpulse.__hash__ = new_instancemethod(_Box2D.b2ContactImpulse___hash__, None, b2ContactImpulse) b2ContactImpulse.__get_normal_impulses = new_instancemethod(_Box2D.b2ContactImpulse___get_normal_impulses, None, b2ContactImpulse) b2ContactImpulse.__get_tangent_impulses = new_instancemethod(_Box2D.b2ContactImpulse___get_tangent_impulses, None, b2ContactImpulse) b2ContactImpulse_swigregister = _Box2D.b2ContactImpulse_swigregister b2ContactImpulse_swigregister(b2ContactImpulse) class b2ContactListener(object): """ Implement this class to get contact information. You can use these results for things like sounds and game logic. You can also get contact results by traversing the contact lists after the time step. However, you might miss some contacts because continuous physics leads to sub-stepping. Additionally you may receive multiple callbacks for the same contact in a single time step. You should strive to make your callbacks efficient because there may be many callbacks per time step. WARNING: You cannot create/destroy Box2D entities inside these callbacks. """ thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr __swig_destroy__ = _Box2D.delete_b2ContactListener def BeginContact(self, contact): """ BeginContact(b2ContactListener self, b2Contact contact) Called when two fixtures begin to touch. """ return _Box2D.b2ContactListener_BeginContact(self, contact) def EndContact(self, contact): """ EndContact(b2ContactListener self, b2Contact contact) Called when two fixtures cease to touch. """ return _Box2D.b2ContactListener_EndContact(self, contact) def PreSolve(self, contact, oldManifold): """ PreSolve(b2ContactListener self, b2Contact contact, b2Manifold oldManifold) This is called after a contact is updated. This allows you to inspect a contact before it goes to the solver. If you are careful, you can modify the contact manifold (e.g. disable contact). A copy of the old manifold is provided so that you can detect changes. Note: this is called only for awake bodies. Note: this is called even when the number of contact points is zero. Note: this is not called for sensors. Note: if you set the number of contact points to zero, you will not get an EndContact callback. However, you may get a BeginContact callback the next step. """ return _Box2D.b2ContactListener_PreSolve(self, contact, oldManifold) def PostSolve(self, contact, impulse): """ PostSolve(b2ContactListener self, b2Contact contact, b2ContactImpulse impulse) This lets you inspect a contact after the solver is finished. This is useful for inspecting impulses. Note: the contact manifold does not include time of impact impulses, which can be arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly in a separate data structure. Note: this is only called for contacts that are touching, solid, and awake. """ return _Box2D.b2ContactListener_PostSolve(self, contact, impulse) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ContactListener self) -> long""" return _Box2D.b2ContactListener___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): if self.__class__ == b2ContactListener: _self = None else: _self = self _Box2D.b2ContactListener_swiginit(self,_Box2D.new_b2ContactListener(_self, )) _init_kwargs(self, **kwargs) def __disown__(self): self.this.disown() _Box2D.disown_b2ContactListener(self) return weakref_proxy(self) b2ContactListener.BeginContact = new_instancemethod(_Box2D.b2ContactListener_BeginContact, None, b2ContactListener) b2ContactListener.EndContact = new_instancemethod(_Box2D.b2ContactListener_EndContact, None, b2ContactListener) b2ContactListener.PreSolve = new_instancemethod(_Box2D.b2ContactListener_PreSolve, None, b2ContactListener) b2ContactListener.PostSolve = new_instancemethod(_Box2D.b2ContactListener_PostSolve, None, b2ContactListener) b2ContactListener.__hash__ = new_instancemethod(_Box2D.b2ContactListener___hash__, None, b2ContactListener) b2ContactListener_swigregister = _Box2D.b2ContactListener_swigregister b2ContactListener_swigregister(b2ContactListener) class b2QueryCallback(object): """Callback class for AABB queries. See b2World::Query""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr __swig_destroy__ = _Box2D.delete_b2QueryCallback def ReportFixture(self, fixture): """ ReportFixture(b2QueryCallback self, b2Fixture fixture) -> bool Called for each fixture found in the query AABB. false to terminate the query. """ return _Box2D.b2QueryCallback_ReportFixture(self, fixture) __dir__ = _dir_filter def __hash__(self): """__hash__(b2QueryCallback self) -> long""" return _Box2D.b2QueryCallback___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): if self.__class__ == b2QueryCallback: _self = None else: _self = self _Box2D.b2QueryCallback_swiginit(self,_Box2D.new_b2QueryCallback(_self, )) _init_kwargs(self, **kwargs) def __disown__(self): self.this.disown() _Box2D.disown_b2QueryCallback(self) return weakref_proxy(self) b2QueryCallback.ReportFixture = new_instancemethod(_Box2D.b2QueryCallback_ReportFixture, None, b2QueryCallback) b2QueryCallback.__hash__ = new_instancemethod(_Box2D.b2QueryCallback___hash__, None, b2QueryCallback) b2QueryCallback_swigregister = _Box2D.b2QueryCallback_swigregister b2QueryCallback_swigregister(b2QueryCallback) class b2RayCastCallback(object): """Callback class for ray casts. See b2World::RayCast""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr __swig_destroy__ = _Box2D.delete_b2RayCastCallback def ReportFixture(self, fixture, point, normal, fraction): """ ReportFixture(b2RayCastCallback self, b2Fixture fixture, b2Vec2 point, b2Vec2 normal, float32 fraction) -> float32 Called for each fixture found in the query. You control how the ray cast proceeds by returning a float: return -1: ignore this fixture and continue return 0: terminate the ray cast return fraction: clip the ray to this point return 1: don't clip the ray and continue Parameters: ----------- fixture: the fixture hit by the ray point: the point of initial intersection normal: the normal vector at the point of intersection -1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue """ return _Box2D.b2RayCastCallback_ReportFixture(self, fixture, point, normal, fraction) __dir__ = _dir_filter def __hash__(self): """__hash__(b2RayCastCallback self) -> long""" return _Box2D.b2RayCastCallback___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self): """ __init__(b2RayCastCallback self) -> b2RayCastCallback Callback class for ray casts. See b2World::RayCast """ if self.__class__ == b2RayCastCallback: _self = None else: _self = self _Box2D.b2RayCastCallback_swiginit(self, _Box2D.new_b2RayCastCallback(_self, )) def __disown__(self): self.this.disown() _Box2D.disown_b2RayCastCallback(self) return weakref_proxy(self) b2RayCastCallback.ReportFixture = new_instancemethod(_Box2D.b2RayCastCallback_ReportFixture, None, b2RayCastCallback) b2RayCastCallback.__hash__ = new_instancemethod(_Box2D.b2RayCastCallback___hash__, None, b2RayCastCallback) b2RayCastCallback_swigregister = _Box2D.b2RayCastCallback_swigregister b2RayCastCallback_swigregister(b2RayCastCallback) class b2Profile(object): """Proxy of C++ b2Profile class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr step = _swig_property(_Box2D.b2Profile_step_get, _Box2D.b2Profile_step_set) collide = _swig_property(_Box2D.b2Profile_collide_get, _Box2D.b2Profile_collide_set) solve = _swig_property(_Box2D.b2Profile_solve_get, _Box2D.b2Profile_solve_set) solveInit = _swig_property(_Box2D.b2Profile_solveInit_get, _Box2D.b2Profile_solveInit_set) solveVelocity = _swig_property(_Box2D.b2Profile_solveVelocity_get, _Box2D.b2Profile_solveVelocity_set) solvePosition = _swig_property(_Box2D.b2Profile_solvePosition_get, _Box2D.b2Profile_solvePosition_set) broadphase = _swig_property(_Box2D.b2Profile_broadphase_get, _Box2D.b2Profile_broadphase_set) solveTOI = _swig_property(_Box2D.b2Profile_solveTOI_get, _Box2D.b2Profile_solveTOI_set) def __init__(self): """__init__(b2Profile self) -> b2Profile""" _Box2D.b2Profile_swiginit(self, _Box2D.new_b2Profile()) __swig_destroy__ = _Box2D.delete_b2Profile b2Profile_swigregister = _Box2D.b2Profile_swigregister b2Profile_swigregister(b2Profile) class b2SolverData(object): """Proxy of C++ b2SolverData class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr step = _swig_property(_Box2D.b2SolverData_step_get, _Box2D.b2SolverData_step_set) positions = _swig_property(_Box2D.b2SolverData_positions_get, _Box2D.b2SolverData_positions_set) velocities = _swig_property(_Box2D.b2SolverData_velocities_get, _Box2D.b2SolverData_velocities_set) def __init__(self): """__init__(b2SolverData self) -> b2SolverData""" _Box2D.b2SolverData_swiginit(self, _Box2D.new_b2SolverData()) __swig_destroy__ = _Box2D.delete_b2SolverData b2SolverData_swigregister = _Box2D.b2SolverData_swigregister b2SolverData_swigregister(b2SolverData) class b2ContactManager(object): """Proxy of C++ b2ContactManager class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self): """__init__(b2ContactManager self) -> b2ContactManager""" _Box2D.b2ContactManager_swiginit(self, _Box2D.new_b2ContactManager()) def AddPair(self, proxyUserDataA, proxyUserDataB): """AddPair(b2ContactManager self, void * proxyUserDataA, void * proxyUserDataB)""" return _Box2D.b2ContactManager_AddPair(self, proxyUserDataA, proxyUserDataB) def FindNewContacts(self): """FindNewContacts(b2ContactManager self)""" return _Box2D.b2ContactManager_FindNewContacts(self) def Destroy(self, c): """Destroy(b2ContactManager self, b2Contact c)""" return _Box2D.b2ContactManager_Destroy(self, c) def Collide(self): """Collide(b2ContactManager self)""" return _Box2D.b2ContactManager_Collide(self) broadPhase = _swig_property(_Box2D.b2ContactManager_broadPhase_get, _Box2D.b2ContactManager_broadPhase_set) contactList = _swig_property(_Box2D.b2ContactManager_contactList_get, _Box2D.b2ContactManager_contactList_set) contactCount = _swig_property(_Box2D.b2ContactManager_contactCount_get, _Box2D.b2ContactManager_contactCount_set) contactFilter = _swig_property(_Box2D.b2ContactManager_contactFilter_get, _Box2D.b2ContactManager_contactFilter_set) contactListener = _swig_property(_Box2D.b2ContactManager_contactListener_get, _Box2D.b2ContactManager_contactListener_set) allocator = _swig_property(_Box2D.b2ContactManager_allocator_get, _Box2D.b2ContactManager_allocator_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ContactManager self) -> long""" return _Box2D.b2ContactManager___hash__(self) def __repr__(self): return _format_repr(self) __swig_destroy__ = _Box2D.delete_b2ContactManager b2ContactManager.AddPair = new_instancemethod(_Box2D.b2ContactManager_AddPair, None, b2ContactManager) b2ContactManager.FindNewContacts = new_instancemethod(_Box2D.b2ContactManager_FindNewContacts, None, b2ContactManager) b2ContactManager.Destroy = new_instancemethod(_Box2D.b2ContactManager_Destroy, None, b2ContactManager) b2ContactManager.Collide = new_instancemethod(_Box2D.b2ContactManager_Collide, None, b2ContactManager) b2ContactManager.__hash__ = new_instancemethod(_Box2D.b2ContactManager___hash__, None, b2ContactManager) b2ContactManager_swigregister = _Box2D.b2ContactManager_swigregister b2ContactManager_swigregister(b2ContactManager) b2_stackSize = b2Globals.b2_stackSize b2_maxStackEntries = b2Globals.b2_maxStackEntries class b2World(object): """The world class manages all physics entities, dynamic simulation, and asynchronous queries. The world also contains efficient memory management facilities.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, gravity=(0, -10), doSleep=True, **kwargs): """__init__(self, gravity=(0, -10), doSleep=True, **kwargs) -> b2World Additional kwargs like contactListener will be passed after the world is created. Examples: b2World(gravity=(0,-10), doSleep=True) b2World(contactListener=myListener) """ _Box2D.b2World_swiginit(self,_Box2D.new_b2World(gravity)) self.allowSleeping = doSleep for key, value in kwargs.items(): try: setattr(self, key, value) except Exception as ex: raise ex.__class__('Failed on kwargs, class="%s" key="%s": %s' \ % (self.__class__.__name__, key, ex)) __swig_destroy__ = _Box2D.delete_b2World def __SetDestructionListener_internal(self, listener): """ __SetDestructionListener_internal(b2World self, b2DestructionListener listener) Register a destruction listener. The listener is owned by you and must remain in scope. """ return _Box2D.b2World___SetDestructionListener_internal(self, listener) def __SetContactFilter_internal(self, filter): """ __SetContactFilter_internal(b2World self, b2ContactFilter filter) Register a contact filter to provide specific control over collision. Otherwise the default filter is used (b2_defaultFilter). The listener is owned by you and must remain in scope. """ return _Box2D.b2World___SetContactFilter_internal(self, filter) def __SetContactListener_internal(self, listener): """ __SetContactListener_internal(b2World self, b2ContactListener listener) Register a contact event listener. The listener is owned by you and must remain in scope. """ return _Box2D.b2World___SetContactListener_internal(self, listener) def __SetDebugDraw_internal(self, debugDraw): """ __SetDebugDraw_internal(b2World self, b2Draw debugDraw) Register a routine for debug drawing. The debug draw functions are called inside with b2World::DrawDebugDatamethod. The debug draw object is owned by you and must remain in scope. """ return _Box2D.b2World___SetDebugDraw_internal(self, debugDraw) def Step(self, timeStep, velocityIterations, positionIterations): """ Step(b2World self, float32 timeStep, int32 velocityIterations, int32 positionIterations) Take a time step. This performs collision detection, integration, and constraint solution. Parameters: ----------- timeStep: the amount of time to simulate, this should not vary. velocityIterations: for the velocity constraint solver. positionIterations: for the position constraint solver. """ return _Box2D.b2World_Step(self, timeStep, velocityIterations, positionIterations) def ClearForces(self): """ ClearForces(b2World self) Manually clear the force buffer on all bodies. By default, forces are cleared automatically after each call to Step. The default behavior is modified by calling SetAutoClearForces. The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain a fixed sized time step under a variable frame-rate. When you perform sub-stepping you will disable auto clearing of forces and instead call ClearForces after all sub-steps are complete in one pass of your game loop. See: SetAutoClearForces """ return _Box2D.b2World_ClearForces(self) def DrawDebugData(self): """ DrawDebugData(b2World self) Call this to draw shapes and other debug draw data. """ return _Box2D.b2World_DrawDebugData(self) def QueryAABB(self, callback, aabb): """ QueryAABB(b2World self, b2QueryCallback callback, b2AABB aabb) Query the world for all fixtures that potentially overlap the provided AABB. Parameters: ----------- callback: a user implemented callback class. aabb: the query box. """ return _Box2D.b2World_QueryAABB(self, callback, aabb) def RayCast(self, callback, point1, point2): """ RayCast(b2World self, b2RayCastCallback callback, b2Vec2 point1, b2Vec2 point2) Ray-cast the world for all fixtures in the path of the ray. Your callback controls whether you get the closest point, any point, or n-points. The ray-cast ignores shapes that contain the starting point. Parameters: ----------- callback: a user implemented callback class. point1: the ray starting point point2: the ray ending point """ return _Box2D.b2World_RayCast(self, callback, point1, point2) def __GetBodyList_internal(self, *args): """ __GetBodyList_internal(b2World self) -> b2Body __GetBodyList_internal(b2World self) -> b2Body Get the world body list. With the returned body, use b2Body::GetNextto get the next body in the world list. A NULL body indicates the end of the list. the head of the world body list. """ return _Box2D.b2World___GetBodyList_internal(self, *args) def __GetJointList_internal(self, *args): """ __GetJointList_internal(b2World self) -> b2Joint __GetJointList_internal(b2World self) -> b2Joint Get the world joint list. With the returned joint, use b2Joint::GetNextto get the next joint in the world list. A NULL joint indicates the end of the list. the head of the world joint list. """ return _Box2D.b2World___GetJointList_internal(self, *args) def __GetContactList_internal(self, *args): """ __GetContactList_internal(b2World self) -> b2Contact __GetContactList_internal(b2World self) -> b2Contact Get the world contact list. With the returned contact, use b2Contact::GetNextto get the next contact in the world list. A NULL contact indicates the end of the list. the head of the world contact list. WARNING: contacts are """ return _Box2D.b2World___GetContactList_internal(self, *args) def SetAllowSleeping(self, flag): """SetAllowSleeping(b2World self, bool flag)""" return _Box2D.b2World_SetAllowSleeping(self, flag) def GetAllowSleeping(self): """GetAllowSleeping(b2World self) -> bool""" return _Box2D.b2World_GetAllowSleeping(self) def __SetWarmStarting(self, flag): """ __SetWarmStarting(b2World self, bool flag) Enable/disable warm starting. For testing. """ return _Box2D.b2World___SetWarmStarting(self, flag) def __GetWarmStarting(self): """__GetWarmStarting(b2World self) -> bool""" return _Box2D.b2World___GetWarmStarting(self) def __SetContinuousPhysics(self, flag): """ __SetContinuousPhysics(b2World self, bool flag) Enable/disable continuous physics. For testing. """ return _Box2D.b2World___SetContinuousPhysics(self, flag) def __GetContinuousPhysics(self): """__GetContinuousPhysics(b2World self) -> bool""" return _Box2D.b2World___GetContinuousPhysics(self) def __SetSubStepping(self, flag): """ __SetSubStepping(b2World self, bool flag) Enable/disable single stepped continuous physics. For testing. """ return _Box2D.b2World___SetSubStepping(self, flag) def __GetSubStepping(self): """__GetSubStepping(b2World self) -> bool""" return _Box2D.b2World___GetSubStepping(self) def __GetProxyCount(self): """ __GetProxyCount(b2World self) -> int32 Get the number of broad-phase proxies. """ return _Box2D.b2World___GetProxyCount(self) def __GetBodyCount(self): """ __GetBodyCount(b2World self) -> int32 Get the number of bodies. """ return _Box2D.b2World___GetBodyCount(self) def __GetJointCount(self): """ __GetJointCount(b2World self) -> int32 Get the number of joints. """ return _Box2D.b2World___GetJointCount(self) def __GetContactCount(self): """ __GetContactCount(b2World self) -> int32 Get the number of contacts (each may have 0 or more contact points). """ return _Box2D.b2World___GetContactCount(self) def GetTreeHeight(self): """GetTreeHeight(b2World self) -> int32""" return _Box2D.b2World_GetTreeHeight(self) def GetTreeBalance(self): """GetTreeBalance(b2World self) -> int32""" return _Box2D.b2World_GetTreeBalance(self) def GetTreeQuality(self): """GetTreeQuality(b2World self) -> float32""" return _Box2D.b2World_GetTreeQuality(self) def __SetGravity(self, gravity): """ __SetGravity(b2World self, b2Vec2 gravity) Change the global gravity vector. """ return _Box2D.b2World___SetGravity(self, gravity) def __GetGravity(self): """ __GetGravity(b2World self) -> b2Vec2 Get the global gravity vector. """ return _Box2D.b2World___GetGravity(self) def __IsLocked(self): """ __IsLocked(b2World self) -> bool Is the world locked (in the middle of a time step). """ return _Box2D.b2World___IsLocked(self) def __SetAutoClearForces(self, flag): """ __SetAutoClearForces(b2World self, bool flag) Set flag to control automatic clearing of forces after each time step. """ return _Box2D.b2World___SetAutoClearForces(self, flag) def __GetAutoClearForces(self): """ __GetAutoClearForces(b2World self) -> bool Get the flag that controls automatic clearing of forces after each time step. """ return _Box2D.b2World___GetAutoClearForces(self) def ShiftOrigin(self, newOrigin): """ShiftOrigin(b2World self, b2Vec2 newOrigin)""" return _Box2D.b2World_ShiftOrigin(self, newOrigin) def __GetContactManager(self): """ __GetContactManager(b2World self) -> b2ContactManager Get the contact manager for testing. """ return _Box2D.b2World___GetContactManager(self) def GetProfile(self): """GetProfile(b2World self) -> b2Profile""" return _Box2D.b2World_GetProfile(self) def Dump(self): """Dump(b2World self)""" return _Box2D.b2World_Dump(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2World self) -> long""" return _Box2D.b2World___hash__(self) def __repr__(self): return _format_repr(self) def __CreateBody(self, defn): """__CreateBody(b2World self, b2BodyDef defn) -> b2Body""" return _Box2D.b2World___CreateBody(self, defn) def __CreateJoint(self, defn): """__CreateJoint(b2World self, b2JointDef defn) -> b2Joint""" return _Box2D.b2World___CreateJoint(self, defn) def DestroyBody(self, body): """ DestroyBody(b2World self, b2Body body) Destroy a rigid body given a definition. No reference to the definition is retained. This function is locked during callbacks. WARNING: This automatically deletes all associated shapes and joints. This function is locked during callbacks. """ return _Box2D.b2World_DestroyBody(self, body) def DestroyJoint(self, joint): """ DestroyJoint(b2World self, b2Joint joint) Destroy a joint. This may cause the connected bodies to begin colliding. WARNING: This function is locked during callbacks. """ return _Box2D.b2World_DestroyJoint(self, joint) def __iter__(self): """ Iterates over the bodies in the world """ for body in self.bodies: yield body def CreateDynamicBody(self, **kwargs): """ Create a single dynamic body in the world. Accepts only kwargs to a b2BodyDef. For more information, see CreateBody and b2BodyDef. """ kwargs['type'] = b2_dynamicBody return self.CreateBody(**kwargs) def CreateKinematicBody(self, **kwargs): """ Create a single kinematic body in the world. Accepts only kwargs to a b2BodyDef. For more information, see CreateBody and b2BodyDef. """ kwargs['type'] = b2_kinematicBody return self.CreateBody(**kwargs) def CreateStaticBody(self, **kwargs): """ Create a single static body in the world. Accepts only kwargs to a b2BodyDef. For more information, see CreateBody and b2BodyDef. """ kwargs['type'] = b2_staticBody return self.CreateBody(**kwargs) def CreateBody(self, defn=None, **kwargs): """ Create a body in the world. Takes a single b2BodyDef argument, or kwargs to pass to a temporary b2BodyDef. world.CreateBody(position=(1,2), angle=1) is short for: world.CreateBody(b2BodyDef(position=(1,2), angle=1)) If the definition (or kwargs) sets 'fixtures', they will be created on the newly created body. A single fixture is also accepted. CreateBody(..., fixtures=[]) This is short for: body = CreateBody(...) for fixture in []: body.CreateFixture(fixture) 'shapes' and 'shapeFixture' are also accepted: CreateBody(..., shapes=[], shapeFixture=b2FixtureDef()) This is short for: body = CreateBody(...) body.CreateFixturesFromShapes(shapes=[], shapeFixture=b2FixtureDef()) """ if defn is not None: if not isinstance(defn, b2BodyDef): raise TypeError('Expected b2BodyDef') else: defn = b2BodyDef(**kwargs) body=self.__CreateBody(defn) if defn.fixtures: if isinstance(defn.fixtures, (list, tuple)): for fixture in defn.fixtures: body.CreateFixture(fixture) else: body.CreateFixture(defn.fixtures) if defn.shapes: body.CreateFixturesFromShapes(shapes=defn.shapes, shapeFixture=defn.shapeFixture) if 'massData' in kwargs: body.massData=kwargs['massData'] if 'localCenter' in kwargs: body.localCenter=kwargs['localCenter'] if 'inertia' in kwargs: body.inertia=kwargs['inertia'] if 'mass' in kwargs: body.mass=kwargs['mass'] return body def CreateDistanceJoint(self, **kwargs): """ Create a single b2DistanceJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2DistanceJointDef(**kwargs)) def CreateRopeJoint(self, **kwargs): """ Create a single b2RopeJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2RopeJointDef(**kwargs)) def CreateFrictionJoint(self, **kwargs): """ Create a single b2FrictionJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2FrictionJointDef(**kwargs)) def CreateGearJoint(self, **kwargs): """ Create a single b2GearJoint. Only accepts kwargs to the joint definition. Raises ValueError if either joint1 or joint2 is left unset. """ if 'joint1' not in kwargs or 'joint2' not in kwargs: raise ValueError('Gear joint requires that both joint1 and joint2 be set') return self.__CreateJoint(b2GearJointDef(**kwargs)) def CreateWheelJoint(self, **kwargs): """ Create a single b2WheelJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2WheelJointDef(**kwargs)) def CreateMouseJoint(self, **kwargs): """ Create a single b2MouseJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2MouseJointDef(**kwargs)) def CreatePrismaticJoint(self, **kwargs): """ Create a single b2PrismaticJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2PrismaticJointDef(**kwargs)) def CreatePulleyJoint(self, **kwargs): """ Create a single b2PulleyJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2PulleyJointDef(**kwargs)) def CreateRevoluteJoint(self, **kwargs): """ Create a single b2RevoluteJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2RevoluteJointDef(**kwargs)) def CreateWeldJoint(self, **kwargs): """ Create a single b2WeldJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2WeldJointDef(**kwargs)) def CreateMotorJoint(self, **kwargs): """ Create a single b2MotorJoint. Only accepts kwargs to the joint definition. Raises ValueError if either bodyA or bodyB is left unset. """ if 'bodyA' not in kwargs or 'bodyB' not in kwargs: raise ValueError('Requires at least bodyA and bodyB be set') return self.__CreateJoint(b2MotorJointDef(**kwargs)) def CreateJoint(self, defn=None, type=None, **kwargs): """ Create a joint in the world. Takes a single b2JointDef argument, or kwargs to pass to a temporary b2JointDef. All of these are exactly equivalent: world.CreateJoint(type=b2RevoluteJoint, bodyA=body, bodyB=body2) world.CreateJoint(type=b2RevoluteJointDef, bodyA=body, bodyB=body2) world.CreateJoint(b2RevoluteJointDef(bodyA=body, bodyB=body2)) """ if defn is not None: if not isinstance(defn, b2JointDef): raise TypeError('Expected b2JointDef') if defn.bodyA is None or defn.bodyB is None: raise ValueError('bodyA and bodyB must be set') else: if type is not None: if issubclass(type, b2JointDef): class_type = type elif issubclass(type, b2Joint): # a b2Joint passed in, so get the b2JointDef class_type = globals()[type.__name__ + 'Def'] else: raise TypeError('Expected "type" to be a b2Joint or b2JointDef') else: raise TypeError('Expected "type" to be a b2Joint or b2JointDef') defn = class_type(**kwargs) if isinstance(defn, b2GearJointDef): if not defn.joint1 or not defn.joint2: raise ValueError('Gear joint requires that both joint1 and joint2 be set') else: if not defn.bodyA or not defn.bodyB: raise ValueError('Body or bodies not set (bodyA, bodyB)') return self.__CreateJoint(defn) # The logic behind these functions is that they increase the refcount # of the listeners as you set them, so it is no longer necessary to keep # a copy on your own. Upon destruction of the object, it should be cleared # also clearing the refcount of the function. # Now using it also to buffer previously write-only values in the shadowed # class to make them read-write. def __GetData(self, name): if name in list(self.__data.keys()): return self.__data[name] else: return None def __SetData(self, name, value, fcn): self.__data[name] = value fcn(value) # Read-write properties gravity = property(__GetGravity, __SetGravity) autoClearForces = property(__GetAutoClearForces, __SetAutoClearForces) __data = {} # holds the listeners so they can be properly destroyed, and buffer other data destructionListener = property(lambda self: self.__GetData('destruction'), lambda self, fcn: self.__SetData('destruction', fcn, self.__SetDestructionListener_internal)) contactListener= property(lambda self: self.__GetData('contact'), lambda self, fcn: self.__SetData('contact', fcn, self.__SetContactListener_internal)) contactFilter= property(lambda self: self.__GetData('contactfilter'), lambda self, fcn: self.__SetData('contactfilter', fcn, self.__SetContactFilter_internal)) renderer= property(lambda self: self.__GetData('renderer'), lambda self, fcn: self.__SetData('renderer', fcn, self.__SetDebugDraw_internal)) continuousPhysics = property(__GetContinuousPhysics, __SetContinuousPhysics) warmStarting = property(__GetWarmStarting, __SetWarmStarting) subStepping = property(__GetSubStepping, __SetSubStepping) # Read-only contactManager= property(__GetContactManager, None) contactCount = property(__GetContactCount, None) bodyCount = property(__GetBodyCount, None) jointCount = property(__GetJointCount, None) proxyCount = property(__GetProxyCount, None) joints = property(lambda self: _list_from_linked_list(self.__GetJointList_internal()), None, doc="""All joints in the world. NOTE: This re-creates the list on every call. See also joints_gen.""") bodies = property(lambda self: _list_from_linked_list(self.__GetBodyList_internal()), None, doc="""All bodies in the world. NOTE: This re-creates the list on every call. See also bodies_gen.""") contacts= property(lambda self: _list_from_linked_list(self.__GetContactList_internal()), None, doc="""All contacts in the world. NOTE: This re-creates the list on every call. See also contacts_gen.""") joints_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetJointList_internal())), None, doc="""Indexable generator of the connected joints to this body. NOTE: When not using the whole list, this may be preferable to using 'joints'.""") bodies_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetBodyList_internal())), None, doc="""Indexable generator of all bodies. NOTE: When not using the whole list, this may be preferable to using 'bodies'.""") contacts_gen = property(lambda self: _indexable_generator(_generator_from_linked_list(self.__GetContactList_internal())), None, doc="""Indexable generator of all contacts. NOTE: When not using the whole list, this may be preferable to using 'contacts'.""") locked = property(__IsLocked, None) b2World.__SetDestructionListener_internal = new_instancemethod(_Box2D.b2World___SetDestructionListener_internal, None, b2World) b2World.__SetContactFilter_internal = new_instancemethod(_Box2D.b2World___SetContactFilter_internal, None, b2World) b2World.__SetContactListener_internal = new_instancemethod(_Box2D.b2World___SetContactListener_internal, None, b2World) b2World.__SetDebugDraw_internal = new_instancemethod(_Box2D.b2World___SetDebugDraw_internal, None, b2World) b2World.Step = new_instancemethod(_Box2D.b2World_Step, None, b2World) b2World.ClearForces = new_instancemethod(_Box2D.b2World_ClearForces, None, b2World) b2World.DrawDebugData = new_instancemethod(_Box2D.b2World_DrawDebugData, None, b2World) b2World.QueryAABB = new_instancemethod(_Box2D.b2World_QueryAABB, None, b2World) b2World.RayCast = new_instancemethod(_Box2D.b2World_RayCast, None, b2World) b2World.__GetBodyList_internal = new_instancemethod(_Box2D.b2World___GetBodyList_internal, None, b2World) b2World.__GetJointList_internal = new_instancemethod(_Box2D.b2World___GetJointList_internal, None, b2World) b2World.__GetContactList_internal = new_instancemethod(_Box2D.b2World___GetContactList_internal, None, b2World) b2World.SetAllowSleeping = new_instancemethod(_Box2D.b2World_SetAllowSleeping, None, b2World) b2World.GetAllowSleeping = new_instancemethod(_Box2D.b2World_GetAllowSleeping, None, b2World) b2World.__SetWarmStarting = new_instancemethod(_Box2D.b2World___SetWarmStarting, None, b2World) b2World.__GetWarmStarting = new_instancemethod(_Box2D.b2World___GetWarmStarting, None, b2World) b2World.__SetContinuousPhysics = new_instancemethod(_Box2D.b2World___SetContinuousPhysics, None, b2World) b2World.__GetContinuousPhysics = new_instancemethod(_Box2D.b2World___GetContinuousPhysics, None, b2World) b2World.__SetSubStepping = new_instancemethod(_Box2D.b2World___SetSubStepping, None, b2World) b2World.__GetSubStepping = new_instancemethod(_Box2D.b2World___GetSubStepping, None, b2World) b2World.__GetProxyCount = new_instancemethod(_Box2D.b2World___GetProxyCount, None, b2World) b2World.__GetBodyCount = new_instancemethod(_Box2D.b2World___GetBodyCount, None, b2World) b2World.__GetJointCount = new_instancemethod(_Box2D.b2World___GetJointCount, None, b2World) b2World.__GetContactCount = new_instancemethod(_Box2D.b2World___GetContactCount, None, b2World) b2World.GetTreeHeight = new_instancemethod(_Box2D.b2World_GetTreeHeight, None, b2World) b2World.GetTreeBalance = new_instancemethod(_Box2D.b2World_GetTreeBalance, None, b2World) b2World.GetTreeQuality = new_instancemethod(_Box2D.b2World_GetTreeQuality, None, b2World) b2World.__SetGravity = new_instancemethod(_Box2D.b2World___SetGravity, None, b2World) b2World.__GetGravity = new_instancemethod(_Box2D.b2World___GetGravity, None, b2World) b2World.__IsLocked = new_instancemethod(_Box2D.b2World___IsLocked, None, b2World) b2World.__SetAutoClearForces = new_instancemethod(_Box2D.b2World___SetAutoClearForces, None, b2World) b2World.__GetAutoClearForces = new_instancemethod(_Box2D.b2World___GetAutoClearForces, None, b2World) b2World.ShiftOrigin = new_instancemethod(_Box2D.b2World_ShiftOrigin, None, b2World) b2World.__GetContactManager = new_instancemethod(_Box2D.b2World___GetContactManager, None, b2World) b2World.GetProfile = new_instancemethod(_Box2D.b2World_GetProfile, None, b2World) b2World.Dump = new_instancemethod(_Box2D.b2World_Dump, None, b2World) b2World.__hash__ = new_instancemethod(_Box2D.b2World___hash__, None, b2World) b2World.__CreateBody = new_instancemethod(_Box2D.b2World___CreateBody, None, b2World) b2World.__CreateJoint = new_instancemethod(_Box2D.b2World___CreateJoint, None, b2World) b2World.DestroyBody = new_instancemethod(_Box2D.b2World_DestroyBody, None, b2World) b2World.DestroyJoint = new_instancemethod(_Box2D.b2World_DestroyJoint, None, b2World) b2World_swigregister = _Box2D.b2World_swigregister b2World_swigregister(b2World) def b2MixFriction(friction1, friction2): """ b2MixFriction(float32 friction1, float32 friction2) -> float32 Friction mixing law. Feel free to customize this. """ return _Box2D.b2MixFriction(friction1, friction2) def b2MixRestitution(restitution1, restitution2): """ b2MixRestitution(float32 restitution1, float32 restitution2) -> float32 Restitution mixing law. Feel free to customize this. """ return _Box2D.b2MixRestitution(restitution1, restitution2) class b2ContactEdge(object): """A contact edge is used to connect bodies and contacts together in a contact graph where each body is a node and each contact is an edge. A contact edge belongs to a doubly linked list maintained in each attached body. Each contact has two contact nodes, one for each attached body.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr other = _swig_property(_Box2D.b2ContactEdge_other_get, _Box2D.b2ContactEdge_other_set) contact = _swig_property(_Box2D.b2ContactEdge_contact_get, _Box2D.b2ContactEdge_contact_set) prev = _swig_property(_Box2D.b2ContactEdge_prev_get, _Box2D.b2ContactEdge_prev_set) next = _swig_property(_Box2D.b2ContactEdge_next_get, _Box2D.b2ContactEdge_next_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2ContactEdge self) -> long""" return _Box2D.b2ContactEdge___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2ContactEdge_swiginit(self,_Box2D.new_b2ContactEdge()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2ContactEdge b2ContactEdge.__hash__ = new_instancemethod(_Box2D.b2ContactEdge___hash__, None, b2ContactEdge) b2ContactEdge_swigregister = _Box2D.b2ContactEdge_swigregister b2ContactEdge_swigregister(b2ContactEdge) class b2Contact(object): """The class manages contact between two shapes. A contact exists for each overlapping AABB in the broad-phase (except if filtered). Therefore a contact object may exist that has no contact points.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined - class is abstract") __repr__ = _swig_repr def __GetManifold(self, *args): """ __GetManifold(b2Contact self) -> b2Manifold __GetManifold(b2Contact self) -> b2Manifold Get the contact manifold. Do not modify the manifold unless you understand the internals of Box2D. """ return _Box2D.b2Contact___GetManifold(self, *args) def __GetWorldManifold_internal(self, worldManifold): """ __GetWorldManifold_internal(b2Contact self, b2WorldManifold worldManifold) Get the world manifold. """ return _Box2D.b2Contact___GetWorldManifold_internal(self, worldManifold) def __IsTouching(self): """ __IsTouching(b2Contact self) -> bool Is this contact touching? """ return _Box2D.b2Contact___IsTouching(self) def __SetEnabled(self, flag): """ __SetEnabled(b2Contact self, bool flag) Enable/disable this contact. This can be used inside the pre-solve contact listener. The contact is only disabled for the current time step (or sub-step in continuous collisions). """ return _Box2D.b2Contact___SetEnabled(self, flag) def __IsEnabled(self): """ __IsEnabled(b2Contact self) -> bool Has this contact been disabled? """ return _Box2D.b2Contact___IsEnabled(self) def __GetNext(self, *args): """ __GetNext(b2Contact self) -> b2Contact __GetNext(b2Contact self) -> b2Contact Get the next contact in the world's contact list. """ return _Box2D.b2Contact___GetNext(self, *args) def __GetFixtureA(self, *args): """ __GetFixtureA(b2Contact self) -> b2Fixture __GetFixtureA(b2Contact self) -> b2Fixture Get fixture A in this contact. """ return _Box2D.b2Contact___GetFixtureA(self, *args) def __GetChildIndexA(self): """ __GetChildIndexA(b2Contact self) -> int32 Get the child primitive index for fixture A. """ return _Box2D.b2Contact___GetChildIndexA(self) def __GetFixtureB(self, *args): """ __GetFixtureB(b2Contact self) -> b2Fixture __GetFixtureB(b2Contact self) -> b2Fixture Get fixture B in this contact. """ return _Box2D.b2Contact___GetFixtureB(self, *args) def __GetChildIndexB(self): """ __GetChildIndexB(b2Contact self) -> int32 Get the child primitive index for fixture B. """ return _Box2D.b2Contact___GetChildIndexB(self) def __SetFriction(self, friction): """ __SetFriction(b2Contact self, float32 friction) Override the default friction mixture. You can call this in b2ContactListener::PreSolve. This value persists until set or reset. """ return _Box2D.b2Contact___SetFriction(self, friction) def __GetFriction(self): """ __GetFriction(b2Contact self) -> float32 Get the friction. """ return _Box2D.b2Contact___GetFriction(self) def ResetFriction(self): """ ResetFriction(b2Contact self) Reset the friction mixture to the default value. """ return _Box2D.b2Contact_ResetFriction(self) def __SetRestitution(self, restitution): """ __SetRestitution(b2Contact self, float32 restitution) Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. The value persists until you set or reset. """ return _Box2D.b2Contact___SetRestitution(self, restitution) def __GetRestitution(self): """ __GetRestitution(b2Contact self) -> float32 Get the restitution. """ return _Box2D.b2Contact___GetRestitution(self) def ResetRestitution(self): """ ResetRestitution(b2Contact self) Reset the restitution to the default value. """ return _Box2D.b2Contact_ResetRestitution(self) def __SetTangentSpeed(self, speed): """__SetTangentSpeed(b2Contact self, float32 speed)""" return _Box2D.b2Contact___SetTangentSpeed(self, speed) def __GetTangentSpeed(self): """__GetTangentSpeed(b2Contact self) -> float32""" return _Box2D.b2Contact___GetTangentSpeed(self) def Evaluate(self, manifold, xfA, xfB): """ Evaluate(b2Contact self, b2Manifold manifold, b2Transform xfA, b2Transform xfB) Evaluate this contact with your own manifold and transforms. """ return _Box2D.b2Contact_Evaluate(self, manifold, xfA, xfB) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Contact self) -> long""" return _Box2D.b2Contact___hash__(self) def __repr__(self): return _format_repr(self) def __GetWorldManifold(self): ret=b2WorldManifold() self.__GetWorldManifold_internal(ret) return ret # Read-write properties enabled = property(__IsEnabled, __SetEnabled) # Read-only next = property(__GetNext, None) fixtureB = property(__GetFixtureB, None) fixtureA = property(__GetFixtureA, None) manifold = property(__GetManifold, None) childIndexA = property(__GetChildIndexA, None) childIndexB = property(__GetChildIndexB, None) worldManifold = property(__GetWorldManifold, None) touching = property(__IsTouching, None) friction = property(__GetFriction, __SetFriction) restitution = property(__GetRestitution, __SetRestitution) tangentSpeed = property(__GetTangentSpeed, __SetTangentSpeed) b2Contact.__GetManifold = new_instancemethod(_Box2D.b2Contact___GetManifold, None, b2Contact) b2Contact.__GetWorldManifold_internal = new_instancemethod(_Box2D.b2Contact___GetWorldManifold_internal, None, b2Contact) b2Contact.__IsTouching = new_instancemethod(_Box2D.b2Contact___IsTouching, None, b2Contact) b2Contact.__SetEnabled = new_instancemethod(_Box2D.b2Contact___SetEnabled, None, b2Contact) b2Contact.__IsEnabled = new_instancemethod(_Box2D.b2Contact___IsEnabled, None, b2Contact) b2Contact.__GetNext = new_instancemethod(_Box2D.b2Contact___GetNext, None, b2Contact) b2Contact.__GetFixtureA = new_instancemethod(_Box2D.b2Contact___GetFixtureA, None, b2Contact) b2Contact.__GetChildIndexA = new_instancemethod(_Box2D.b2Contact___GetChildIndexA, None, b2Contact) b2Contact.__GetFixtureB = new_instancemethod(_Box2D.b2Contact___GetFixtureB, None, b2Contact) b2Contact.__GetChildIndexB = new_instancemethod(_Box2D.b2Contact___GetChildIndexB, None, b2Contact) b2Contact.__SetFriction = new_instancemethod(_Box2D.b2Contact___SetFriction, None, b2Contact) b2Contact.__GetFriction = new_instancemethod(_Box2D.b2Contact___GetFriction, None, b2Contact) b2Contact.ResetFriction = new_instancemethod(_Box2D.b2Contact_ResetFriction, None, b2Contact) b2Contact.__SetRestitution = new_instancemethod(_Box2D.b2Contact___SetRestitution, None, b2Contact) b2Contact.__GetRestitution = new_instancemethod(_Box2D.b2Contact___GetRestitution, None, b2Contact) b2Contact.ResetRestitution = new_instancemethod(_Box2D.b2Contact_ResetRestitution, None, b2Contact) b2Contact.__SetTangentSpeed = new_instancemethod(_Box2D.b2Contact___SetTangentSpeed, None, b2Contact) b2Contact.__GetTangentSpeed = new_instancemethod(_Box2D.b2Contact___GetTangentSpeed, None, b2Contact) b2Contact.Evaluate = new_instancemethod(_Box2D.b2Contact_Evaluate, None, b2Contact) b2Contact.__hash__ = new_instancemethod(_Box2D.b2Contact___hash__, None, b2Contact) b2Contact_swigregister = _Box2D.b2Contact_swigregister b2Contact_swigregister(b2Contact) _Box2D.e_wheelJoint_swigconstant(_Box2D) e_wheelJoint = _Box2D.e_wheelJoint _Box2D.e_ropeJoint_swigconstant(_Box2D) e_ropeJoint = _Box2D.e_ropeJoint class b2Jacobian(object): """Proxy of C++ b2Jacobian class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr linear = _swig_property(_Box2D.b2Jacobian_linear_get, _Box2D.b2Jacobian_linear_set) angularA = _swig_property(_Box2D.b2Jacobian_angularA_get, _Box2D.b2Jacobian_angularA_set) angularB = _swig_property(_Box2D.b2Jacobian_angularB_get, _Box2D.b2Jacobian_angularB_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Jacobian self) -> long""" return _Box2D.b2Jacobian___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2Jacobian_swiginit(self,_Box2D.new_b2Jacobian()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2Jacobian b2Jacobian.__hash__ = new_instancemethod(_Box2D.b2Jacobian___hash__, None, b2Jacobian) b2Jacobian_swigregister = _Box2D.b2Jacobian_swigregister b2Jacobian_swigregister(b2Jacobian) class b2JointEdge(object): """A joint edge is used to connect bodies and joints together in a joint graph where each body is a node and each joint is an edge. A joint edge belongs to a doubly linked list maintained in each attached body. Each joint has two joint nodes, one for each attached body.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr other = _swig_property(_Box2D.b2JointEdge_other_get, _Box2D.b2JointEdge_other_set) joint = _swig_property(_Box2D.b2JointEdge_joint_get, _Box2D.b2JointEdge_joint_set) prev = _swig_property(_Box2D.b2JointEdge_prev_get, _Box2D.b2JointEdge_prev_set) next = _swig_property(_Box2D.b2JointEdge_next_get, _Box2D.b2JointEdge_next_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2JointEdge self) -> long""" return _Box2D.b2JointEdge___hash__(self) def __repr__(self): return _format_repr(self) def __init__(self, **kwargs): _Box2D.b2JointEdge_swiginit(self,_Box2D.new_b2JointEdge()) _init_kwargs(self, **kwargs) __swig_destroy__ = _Box2D.delete_b2JointEdge b2JointEdge.__hash__ = new_instancemethod(_Box2D.b2JointEdge___hash__, None, b2JointEdge) b2JointEdge_swigregister = _Box2D.b2JointEdge_swigregister b2JointEdge_swigregister(b2JointEdge) class b2JointDef(object): """Joint definitions are used to construct joints.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2JointDef_swiginit(self,_Box2D.new_b2JointDef()) _init_kwargs(self, **kwargs) type = _swig_property(_Box2D.b2JointDef_type_get, _Box2D.b2JointDef_type_set) bodyA = _swig_property(_Box2D.b2JointDef_bodyA_get, _Box2D.b2JointDef_bodyA_set) bodyB = _swig_property(_Box2D.b2JointDef_bodyB_get, _Box2D.b2JointDef_bodyB_set) collideConnected = _swig_property(_Box2D.b2JointDef_collideConnected_get, _Box2D.b2JointDef_collideConnected_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2JointDef self) -> long""" return _Box2D.b2JointDef___hash__(self) def __repr__(self): return _format_repr(self) def __GetUserData(self): """__GetUserData(b2JointDef self) -> PyObject *""" return _Box2D.b2JointDef___GetUserData(self) def __SetUserData(self, data): """__SetUserData(b2JointDef self, PyObject * data)""" return _Box2D.b2JointDef___SetUserData(self, data) def ClearUserData(self): """ClearUserData(b2JointDef self)""" return _Box2D.b2JointDef_ClearUserData(self) userData = property(__GetUserData, __SetUserData) def __del__(self): self.ClearUserData() def to_kwargs(self): """ Returns a dictionary representing this joint definition """ def is_prop(attr): try: is_property = isinstance(getattr(cls, attr), property) except AttributeError: return False return is_property and attr not in skip_props skip_props = ['anchor', 'anchorA', 'anchorB', 'axis'] cls = type(self) return {attr: getattr(self, attr) for attr in dir(self) if is_prop(attr) } __swig_destroy__ = _Box2D.delete_b2JointDef b2JointDef.__hash__ = new_instancemethod(_Box2D.b2JointDef___hash__, None, b2JointDef) b2JointDef.__GetUserData = new_instancemethod(_Box2D.b2JointDef___GetUserData, None, b2JointDef) b2JointDef.__SetUserData = new_instancemethod(_Box2D.b2JointDef___SetUserData, None, b2JointDef) b2JointDef.ClearUserData = new_instancemethod(_Box2D.b2JointDef_ClearUserData, None, b2JointDef) b2JointDef_swigregister = _Box2D.b2JointDef_swigregister b2JointDef_swigregister(b2JointDef) class b2Joint(object): """The base joint class. Joints are used to constraint two bodies together in various fashions. Some joints also feature limits and motors.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined - class is abstract") __repr__ = _swig_repr def __GetType(self): """ __GetType(b2Joint self) -> b2JointType Get the type of the concrete joint. """ return _Box2D.b2Joint___GetType(self) def __GetBodyA(self): """ __GetBodyA(b2Joint self) -> b2Body Get the first body attached to this joint. """ return _Box2D.b2Joint___GetBodyA(self) def __GetBodyB(self): """ __GetBodyB(b2Joint self) -> b2Body Get the second body attached to this joint. """ return _Box2D.b2Joint___GetBodyB(self) def __GetAnchorA(self): """ __GetAnchorA(b2Joint self) -> b2Vec2 Get the anchor point on bodyA in world coordinates. """ return _Box2D.b2Joint___GetAnchorA(self) def __GetAnchorB(self): """ __GetAnchorB(b2Joint self) -> b2Vec2 Get the anchor point on bodyB in world coordinates. """ return _Box2D.b2Joint___GetAnchorB(self) def GetReactionForce(self, inv_dt): """ GetReactionForce(b2Joint self, float32 inv_dt) -> b2Vec2 Get the reaction force on body2 at the joint anchor in Newtons. """ return _Box2D.b2Joint_GetReactionForce(self, inv_dt) def GetReactionTorque(self, inv_dt): """ GetReactionTorque(b2Joint self, float32 inv_dt) -> float32 Get the reaction torque on body2 in N*m. """ return _Box2D.b2Joint_GetReactionTorque(self, inv_dt) def __GetNext(self, *args): """ __GetNext(b2Joint self) -> b2Joint __GetNext(b2Joint self) -> b2Joint Get the next joint the world joint list. """ return _Box2D.b2Joint___GetNext(self, *args) def __IsActive(self): """ __IsActive(b2Joint self) -> bool Short-cut function to determine if either body is inactive. """ return _Box2D.b2Joint___IsActive(self) def __GetCollideConnected(self): """__GetCollideConnected(b2Joint self) -> bool""" return _Box2D.b2Joint___GetCollideConnected(self) def Dump(self): """Dump(b2Joint self)""" return _Box2D.b2Joint_Dump(self) def ShiftOrigin(self, newOrigin): """ShiftOrigin(b2Joint self, b2Vec2 newOrigin)""" return _Box2D.b2Joint_ShiftOrigin(self, newOrigin) __dir__ = _dir_filter def __hash__(self): """__hash__(b2Joint self) -> long""" return _Box2D.b2Joint___hash__(self) def __repr__(self): return _format_repr(self) def __GetUserData(self): """__GetUserData(b2Joint self) -> PyObject *""" return _Box2D.b2Joint___GetUserData(self) def __SetUserData(self, data): """__SetUserData(b2Joint self, PyObject * data)""" return _Box2D.b2Joint___SetUserData(self, data) def ClearUserData(self): """ClearUserData(b2Joint self)""" return _Box2D.b2Joint_ClearUserData(self) userData = property(__GetUserData, __SetUserData) __eq__ = b2JointCompare __ne__ = lambda self,other: not b2JointCompare(self,other) # Read-only next = property(__GetNext, None) bodyA = property(__GetBodyA, None) bodyB = property(__GetBodyB, None) type = property(__GetType, None) active = property(__IsActive, None) anchorB = property(__GetAnchorB, None) anchorA = property(__GetAnchorA, None) collideConnected = property(__GetCollideConnected, None) def getAsType(self): """ Backward compatibility """ return self b2Joint.__GetType = new_instancemethod(_Box2D.b2Joint___GetType, None, b2Joint) b2Joint.__GetBodyA = new_instancemethod(_Box2D.b2Joint___GetBodyA, None, b2Joint) b2Joint.__GetBodyB = new_instancemethod(_Box2D.b2Joint___GetBodyB, None, b2Joint) b2Joint.__GetAnchorA = new_instancemethod(_Box2D.b2Joint___GetAnchorA, None, b2Joint) b2Joint.__GetAnchorB = new_instancemethod(_Box2D.b2Joint___GetAnchorB, None, b2Joint) b2Joint.GetReactionForce = new_instancemethod(_Box2D.b2Joint_GetReactionForce, None, b2Joint) b2Joint.GetReactionTorque = new_instancemethod(_Box2D.b2Joint_GetReactionTorque, None, b2Joint) b2Joint.__GetNext = new_instancemethod(_Box2D.b2Joint___GetNext, None, b2Joint) b2Joint.__IsActive = new_instancemethod(_Box2D.b2Joint___IsActive, None, b2Joint) b2Joint.__GetCollideConnected = new_instancemethod(_Box2D.b2Joint___GetCollideConnected, None, b2Joint) b2Joint.Dump = new_instancemethod(_Box2D.b2Joint_Dump, None, b2Joint) b2Joint.ShiftOrigin = new_instancemethod(_Box2D.b2Joint_ShiftOrigin, None, b2Joint) b2Joint.__hash__ = new_instancemethod(_Box2D.b2Joint___hash__, None, b2Joint) b2Joint.__GetUserData = new_instancemethod(_Box2D.b2Joint___GetUserData, None, b2Joint) b2Joint.__SetUserData = new_instancemethod(_Box2D.b2Joint___SetUserData, None, b2Joint) b2Joint.ClearUserData = new_instancemethod(_Box2D.b2Joint_ClearUserData, None, b2Joint) b2Joint_swigregister = _Box2D.b2Joint_swigregister b2Joint_swigregister(b2Joint) class b2DistanceJointDef(b2JointDef): """ Distance joint definition. This requires defining an anchor point on both bodies and the non-zero length of the distance joint. The definition uses local anchor points so that the initial configuration can violate the constraint slightly. This helps when saving and loading a game. WARNING: Do not use a zero or short length. """ thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2DistanceJointDef_swiginit(self,_Box2D.new_b2DistanceJointDef()) _init_jointdef_kwargs(self, **kwargs) if 'localAnchorA' in kwargs and 'localAnchorB' in kwargs and 'length' not in kwargs: self.__update_length() def Initialize(self, bodyA, bodyB, anchorA, anchorB): """ Initialize(b2DistanceJointDef self, b2Body bodyA, b2Body bodyB, b2Vec2 anchorA, b2Vec2 anchorB) Initialize the bodies, anchors, and length using the world anchors. """ return _Box2D.b2DistanceJointDef_Initialize(self, bodyA, bodyB, anchorA, anchorB) localAnchorA = _swig_property(_Box2D.b2DistanceJointDef_localAnchorA_get, _Box2D.b2DistanceJointDef_localAnchorA_set) localAnchorB = _swig_property(_Box2D.b2DistanceJointDef_localAnchorB_get, _Box2D.b2DistanceJointDef_localAnchorB_set) length = _swig_property(_Box2D.b2DistanceJointDef_length_get, _Box2D.b2DistanceJointDef_length_set) frequencyHz = _swig_property(_Box2D.b2DistanceJointDef_frequencyHz_get, _Box2D.b2DistanceJointDef_frequencyHz_set) dampingRatio = _swig_property(_Box2D.b2DistanceJointDef_dampingRatio_get, _Box2D.b2DistanceJointDef_dampingRatio_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2DistanceJointDef self) -> long""" return _Box2D.b2DistanceJointDef___hash__(self) def __repr__(self): return _format_repr(self) def __update_length(self): if self.bodyA and self.bodyB: d = self.anchorB - self.anchorA self.length = d.length def __set_anchorA(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.__update_length() def __set_anchorB(self, value): if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorB=self.bodyB.GetLocalPoint(value) self.__update_length() def __get_anchorA(self): if not self.bodyA: raise ValueError('bodyA not set.') return self.bodyA.GetWorldPoint(self.localAnchorA) def __get_anchorB(self): if not self.bodyB: raise ValueError('bodyB not set.') return self.bodyB.GetWorldPoint(self.localAnchorB) anchorA = property(__get_anchorA, __set_anchorA, doc="""Body A's anchor in world coordinates. Getting the property depends on both bodyA and localAnchorA. Setting the property requires that bodyA be set.""") anchorB = property(__get_anchorB, __set_anchorB, doc="""Body B's anchor in world coordinates. Getting the property depends on both bodyB and localAnchorB. Setting the property requires that bodyB be set.""") __swig_destroy__ = _Box2D.delete_b2DistanceJointDef b2DistanceJointDef.Initialize = new_instancemethod(_Box2D.b2DistanceJointDef_Initialize, None, b2DistanceJointDef) b2DistanceJointDef.__hash__ = new_instancemethod(_Box2D.b2DistanceJointDef___hash__, None, b2DistanceJointDef) b2DistanceJointDef_swigregister = _Box2D.b2DistanceJointDef_swigregister b2DistanceJointDef_swigregister(b2DistanceJointDef) class b2DistanceJoint(b2Joint): """A distance joint constrains two points on two bodies to remain at a fixed distance from each other. You can view this as a massless, rigid rod.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def GetLocalAnchorA(self): """GetLocalAnchorA(b2DistanceJoint self) -> b2Vec2""" return _Box2D.b2DistanceJoint_GetLocalAnchorA(self) def GetLocalAnchorB(self): """GetLocalAnchorB(b2DistanceJoint self) -> b2Vec2""" return _Box2D.b2DistanceJoint_GetLocalAnchorB(self) def __SetLength(self, length): """ __SetLength(b2DistanceJoint self, float32 length) Set/get the natural length. Manipulating the length can lead to non-physical behavior when the frequency is zero. """ return _Box2D.b2DistanceJoint___SetLength(self, length) def __GetLength(self): """__GetLength(b2DistanceJoint self) -> float32""" return _Box2D.b2DistanceJoint___GetLength(self) def __SetFrequency(self, hz): """__SetFrequency(b2DistanceJoint self, float32 hz)""" return _Box2D.b2DistanceJoint___SetFrequency(self, hz) def __GetFrequency(self): """__GetFrequency(b2DistanceJoint self) -> float32""" return _Box2D.b2DistanceJoint___GetFrequency(self) def __SetDampingRatio(self, ratio): """__SetDampingRatio(b2DistanceJoint self, float32 ratio)""" return _Box2D.b2DistanceJoint___SetDampingRatio(self, ratio) def __GetDampingRatio(self): """__GetDampingRatio(b2DistanceJoint self) -> float32""" return _Box2D.b2DistanceJoint___GetDampingRatio(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2DistanceJoint self) -> long""" return _Box2D.b2DistanceJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-write properties length = property(__GetLength, __SetLength) frequency = property(__GetFrequency, __SetFrequency) dampingRatio = property(__GetDampingRatio, __SetDampingRatio) __swig_destroy__ = _Box2D.delete_b2DistanceJoint b2DistanceJoint.GetLocalAnchorA = new_instancemethod(_Box2D.b2DistanceJoint_GetLocalAnchorA, None, b2DistanceJoint) b2DistanceJoint.GetLocalAnchorB = new_instancemethod(_Box2D.b2DistanceJoint_GetLocalAnchorB, None, b2DistanceJoint) b2DistanceJoint.__SetLength = new_instancemethod(_Box2D.b2DistanceJoint___SetLength, None, b2DistanceJoint) b2DistanceJoint.__GetLength = new_instancemethod(_Box2D.b2DistanceJoint___GetLength, None, b2DistanceJoint) b2DistanceJoint.__SetFrequency = new_instancemethod(_Box2D.b2DistanceJoint___SetFrequency, None, b2DistanceJoint) b2DistanceJoint.__GetFrequency = new_instancemethod(_Box2D.b2DistanceJoint___GetFrequency, None, b2DistanceJoint) b2DistanceJoint.__SetDampingRatio = new_instancemethod(_Box2D.b2DistanceJoint___SetDampingRatio, None, b2DistanceJoint) b2DistanceJoint.__GetDampingRatio = new_instancemethod(_Box2D.b2DistanceJoint___GetDampingRatio, None, b2DistanceJoint) b2DistanceJoint.__hash__ = new_instancemethod(_Box2D.b2DistanceJoint___hash__, None, b2DistanceJoint) b2DistanceJoint_swigregister = _Box2D.b2DistanceJoint_swigregister b2DistanceJoint_swigregister(b2DistanceJoint) class b2FrictionJointDef(b2JointDef): """Friction joint definition.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2FrictionJointDef_swiginit(self,_Box2D.new_b2FrictionJointDef()) _init_jointdef_kwargs(self, **kwargs) def Initialize(self, bodyA, bodyB, anchor): """ Initialize(b2FrictionJointDef self, b2Body bodyA, b2Body bodyB, b2Vec2 anchor) Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis. """ return _Box2D.b2FrictionJointDef_Initialize(self, bodyA, bodyB, anchor) localAnchorA = _swig_property(_Box2D.b2FrictionJointDef_localAnchorA_get, _Box2D.b2FrictionJointDef_localAnchorA_set) localAnchorB = _swig_property(_Box2D.b2FrictionJointDef_localAnchorB_get, _Box2D.b2FrictionJointDef_localAnchorB_set) maxForce = _swig_property(_Box2D.b2FrictionJointDef_maxForce_get, _Box2D.b2FrictionJointDef_maxForce_set) maxTorque = _swig_property(_Box2D.b2FrictionJointDef_maxTorque_get, _Box2D.b2FrictionJointDef_maxTorque_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2FrictionJointDef self) -> long""" return _Box2D.b2FrictionJointDef___hash__(self) def __repr__(self): return _format_repr(self) def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") __swig_destroy__ = _Box2D.delete_b2FrictionJointDef b2FrictionJointDef.Initialize = new_instancemethod(_Box2D.b2FrictionJointDef_Initialize, None, b2FrictionJointDef) b2FrictionJointDef.__hash__ = new_instancemethod(_Box2D.b2FrictionJointDef___hash__, None, b2FrictionJointDef) b2FrictionJointDef_swigregister = _Box2D.b2FrictionJointDef_swigregister b2FrictionJointDef_swigregister(b2FrictionJointDef) class b2FrictionJoint(b2Joint): """Friction joint. This is used for top-down friction. It provides 2D translational friction and angular friction.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def GetLocalAnchorA(self): """GetLocalAnchorA(b2FrictionJoint self) -> b2Vec2""" return _Box2D.b2FrictionJoint_GetLocalAnchorA(self) def GetLocalAnchorB(self): """GetLocalAnchorB(b2FrictionJoint self) -> b2Vec2""" return _Box2D.b2FrictionJoint_GetLocalAnchorB(self) def __SetMaxForce(self, force): """ __SetMaxForce(b2FrictionJoint self, float32 force) Set the maximum friction force in N. """ return _Box2D.b2FrictionJoint___SetMaxForce(self, force) def __GetMaxForce(self): """ __GetMaxForce(b2FrictionJoint self) -> float32 Get the maximum friction force in N. """ return _Box2D.b2FrictionJoint___GetMaxForce(self) def __SetMaxTorque(self, torque): """ __SetMaxTorque(b2FrictionJoint self, float32 torque) Set the maximum friction torque in N*m. """ return _Box2D.b2FrictionJoint___SetMaxTorque(self, torque) def __GetMaxTorque(self): """ __GetMaxTorque(b2FrictionJoint self) -> float32 Get the maximum friction torque in N*m. """ return _Box2D.b2FrictionJoint___GetMaxTorque(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2FrictionJoint self) -> long""" return _Box2D.b2FrictionJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-write properties maxForce = property(__GetMaxForce, __SetMaxForce) maxTorque = property(__GetMaxTorque, __SetMaxTorque) __swig_destroy__ = _Box2D.delete_b2FrictionJoint b2FrictionJoint.GetLocalAnchorA = new_instancemethod(_Box2D.b2FrictionJoint_GetLocalAnchorA, None, b2FrictionJoint) b2FrictionJoint.GetLocalAnchorB = new_instancemethod(_Box2D.b2FrictionJoint_GetLocalAnchorB, None, b2FrictionJoint) b2FrictionJoint.__SetMaxForce = new_instancemethod(_Box2D.b2FrictionJoint___SetMaxForce, None, b2FrictionJoint) b2FrictionJoint.__GetMaxForce = new_instancemethod(_Box2D.b2FrictionJoint___GetMaxForce, None, b2FrictionJoint) b2FrictionJoint.__SetMaxTorque = new_instancemethod(_Box2D.b2FrictionJoint___SetMaxTorque, None, b2FrictionJoint) b2FrictionJoint.__GetMaxTorque = new_instancemethod(_Box2D.b2FrictionJoint___GetMaxTorque, None, b2FrictionJoint) b2FrictionJoint.__hash__ = new_instancemethod(_Box2D.b2FrictionJoint___hash__, None, b2FrictionJoint) b2FrictionJoint_swigregister = _Box2D.b2FrictionJoint_swigregister b2FrictionJoint_swigregister(b2FrictionJoint) class b2GearJointDef(b2JointDef): """Gear joint definition. This definition requires two existing revolute or prismatic joints (any combination will work). The provided joints must attach a dynamic body to a static body.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2GearJointDef_swiginit(self,_Box2D.new_b2GearJointDef()) _init_kwargs(self, **kwargs) joint1 = _swig_property(_Box2D.b2GearJointDef_joint1_get, _Box2D.b2GearJointDef_joint1_set) joint2 = _swig_property(_Box2D.b2GearJointDef_joint2_get, _Box2D.b2GearJointDef_joint2_set) ratio = _swig_property(_Box2D.b2GearJointDef_ratio_get, _Box2D.b2GearJointDef_ratio_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2GearJointDef self) -> long""" return _Box2D.b2GearJointDef___hash__(self) def __repr__(self): return _format_repr(self) __swig_destroy__ = _Box2D.delete_b2GearJointDef b2GearJointDef.__hash__ = new_instancemethod(_Box2D.b2GearJointDef___hash__, None, b2GearJointDef) b2GearJointDef_swigregister = _Box2D.b2GearJointDef_swigregister b2GearJointDef_swigregister(b2GearJointDef) class b2GearJoint(b2Joint): """ A gear joint is used to connect two joints together. Either joint can be a revolute or prismatic joint. You specify a gear ratio to bind the motions together: coordinate1 + ratio * coordinate2 = constant The ratio can be negative or positive. If one joint is a revolute joint and the other joint is a prismatic joint, then the ratio will have units of length or units of 1/length. WARNING: The revolute and prismatic joints must be attached to fixed bodies (which must be body1 on those joints). """ thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def GetJoint1(self): """GetJoint1(b2GearJoint self) -> b2Joint""" return _Box2D.b2GearJoint_GetJoint1(self) def GetJoint2(self): """GetJoint2(b2GearJoint self) -> b2Joint""" return _Box2D.b2GearJoint_GetJoint2(self) def __SetRatio(self, ratio): """ __SetRatio(b2GearJoint self, float32 ratio) Set/Get the gear ratio. """ return _Box2D.b2GearJoint___SetRatio(self, ratio) def __GetRatio(self): """__GetRatio(b2GearJoint self) -> float32""" return _Box2D.b2GearJoint___GetRatio(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2GearJoint self) -> long""" return _Box2D.b2GearJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-write properties ratio = property(__GetRatio, __SetRatio) __swig_destroy__ = _Box2D.delete_b2GearJoint b2GearJoint.GetJoint1 = new_instancemethod(_Box2D.b2GearJoint_GetJoint1, None, b2GearJoint) b2GearJoint.GetJoint2 = new_instancemethod(_Box2D.b2GearJoint_GetJoint2, None, b2GearJoint) b2GearJoint.__SetRatio = new_instancemethod(_Box2D.b2GearJoint___SetRatio, None, b2GearJoint) b2GearJoint.__GetRatio = new_instancemethod(_Box2D.b2GearJoint___GetRatio, None, b2GearJoint) b2GearJoint.__hash__ = new_instancemethod(_Box2D.b2GearJoint___hash__, None, b2GearJoint) b2GearJoint_swigregister = _Box2D.b2GearJoint_swigregister b2GearJoint_swigregister(b2GearJoint) class b2MotorJointDef(b2JointDef): """Proxy of C++ b2MotorJointDef class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, bodyA=None, bodyB=None, **kwargs): _Box2D.b2MotorJointDef_swiginit(self,_Box2D.new_b2MotorJointDef()) _init_jointdef_kwargs(self, bodyA=bodyA, bodyB=bodyB, **kwargs) if bodyA is not None and bodyB is not None: if not kwargs: self.Initialize(bodyA, bodyB) def Initialize(self, bodyA, bodyB): """Initialize(b2MotorJointDef self, b2Body bodyA, b2Body bodyB)""" return _Box2D.b2MotorJointDef_Initialize(self, bodyA, bodyB) linearOffset = _swig_property(_Box2D.b2MotorJointDef_linearOffset_get, _Box2D.b2MotorJointDef_linearOffset_set) angularOffset = _swig_property(_Box2D.b2MotorJointDef_angularOffset_get, _Box2D.b2MotorJointDef_angularOffset_set) maxForce = _swig_property(_Box2D.b2MotorJointDef_maxForce_get, _Box2D.b2MotorJointDef_maxForce_set) maxTorque = _swig_property(_Box2D.b2MotorJointDef_maxTorque_get, _Box2D.b2MotorJointDef_maxTorque_set) correctionFactor = _swig_property(_Box2D.b2MotorJointDef_correctionFactor_get, _Box2D.b2MotorJointDef_correctionFactor_set) __swig_destroy__ = _Box2D.delete_b2MotorJointDef b2MotorJointDef.Initialize = new_instancemethod(_Box2D.b2MotorJointDef_Initialize, None, b2MotorJointDef) b2MotorJointDef_swigregister = _Box2D.b2MotorJointDef_swigregister b2MotorJointDef_swigregister(b2MotorJointDef) class b2MotorJoint(b2Joint): """Proxy of C++ b2MotorJoint class""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def __SetLinearOffset(self, linearOffset): """__SetLinearOffset(b2MotorJoint self, b2Vec2 linearOffset)""" return _Box2D.b2MotorJoint___SetLinearOffset(self, linearOffset) def __GetLinearOffset(self): """__GetLinearOffset(b2MotorJoint self) -> b2Vec2""" return _Box2D.b2MotorJoint___GetLinearOffset(self) def __SetAngularOffset(self, angularOffset): """__SetAngularOffset(b2MotorJoint self, float32 angularOffset)""" return _Box2D.b2MotorJoint___SetAngularOffset(self, angularOffset) def __GetAngularOffset(self): """__GetAngularOffset(b2MotorJoint self) -> float32""" return _Box2D.b2MotorJoint___GetAngularOffset(self) def __SetMaxForce(self, force): """__SetMaxForce(b2MotorJoint self, float32 force)""" return _Box2D.b2MotorJoint___SetMaxForce(self, force) def __GetMaxForce(self): """__GetMaxForce(b2MotorJoint self) -> float32""" return _Box2D.b2MotorJoint___GetMaxForce(self) def __SetMaxTorque(self, torque): """__SetMaxTorque(b2MotorJoint self, float32 torque)""" return _Box2D.b2MotorJoint___SetMaxTorque(self, torque) def __GetMaxTorque(self): """__GetMaxTorque(b2MotorJoint self) -> float32""" return _Box2D.b2MotorJoint___GetMaxTorque(self) # Read-write properties maxForce = property(__GetMaxForce, __SetMaxForce) maxTorque = property(__GetMaxTorque, __SetMaxTorque) linearOffset = property(__GetLinearOffset, __SetLinearOffset) angularOffset = property(__GetAngularOffset, __SetAngularOffset) __swig_destroy__ = _Box2D.delete_b2MotorJoint b2MotorJoint.__SetLinearOffset = new_instancemethod(_Box2D.b2MotorJoint___SetLinearOffset, None, b2MotorJoint) b2MotorJoint.__GetLinearOffset = new_instancemethod(_Box2D.b2MotorJoint___GetLinearOffset, None, b2MotorJoint) b2MotorJoint.__SetAngularOffset = new_instancemethod(_Box2D.b2MotorJoint___SetAngularOffset, None, b2MotorJoint) b2MotorJoint.__GetAngularOffset = new_instancemethod(_Box2D.b2MotorJoint___GetAngularOffset, None, b2MotorJoint) b2MotorJoint.__SetMaxForce = new_instancemethod(_Box2D.b2MotorJoint___SetMaxForce, None, b2MotorJoint) b2MotorJoint.__GetMaxForce = new_instancemethod(_Box2D.b2MotorJoint___GetMaxForce, None, b2MotorJoint) b2MotorJoint.__SetMaxTorque = new_instancemethod(_Box2D.b2MotorJoint___SetMaxTorque, None, b2MotorJoint) b2MotorJoint.__GetMaxTorque = new_instancemethod(_Box2D.b2MotorJoint___GetMaxTorque, None, b2MotorJoint) b2MotorJoint_swigregister = _Box2D.b2MotorJoint_swigregister b2MotorJoint_swigregister(b2MotorJoint) class b2MouseJointDef(b2JointDef): """Mouse joint definition. This requires a world target point, tuning parameters, and the time step.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2MouseJointDef_swiginit(self,_Box2D.new_b2MouseJointDef()) _init_kwargs(self, **kwargs) target = _swig_property(_Box2D.b2MouseJointDef_target_get, _Box2D.b2MouseJointDef_target_set) maxForce = _swig_property(_Box2D.b2MouseJointDef_maxForce_get, _Box2D.b2MouseJointDef_maxForce_set) frequencyHz = _swig_property(_Box2D.b2MouseJointDef_frequencyHz_get, _Box2D.b2MouseJointDef_frequencyHz_set) dampingRatio = _swig_property(_Box2D.b2MouseJointDef_dampingRatio_get, _Box2D.b2MouseJointDef_dampingRatio_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2MouseJointDef self) -> long""" return _Box2D.b2MouseJointDef___hash__(self) def __repr__(self): return _format_repr(self) __swig_destroy__ = _Box2D.delete_b2MouseJointDef b2MouseJointDef.__hash__ = new_instancemethod(_Box2D.b2MouseJointDef___hash__, None, b2MouseJointDef) b2MouseJointDef_swigregister = _Box2D.b2MouseJointDef_swigregister b2MouseJointDef_swigregister(b2MouseJointDef) class b2MouseJoint(b2Joint): """A mouse joint is used to make a point on a body track a specified world point. This a soft constraint with a maximum force. This allows the constraint to stretch and without applying huge forces. NOTE: this joint is not documented in the manual because it was developed to be used in the testbed. If you want to learn how to use the mouse joint, look at the testbed.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def __SetTarget(self, target): """ __SetTarget(b2MouseJoint self, b2Vec2 target) Use this to update the target point. """ return _Box2D.b2MouseJoint___SetTarget(self, target) def __GetTarget(self): """__GetTarget(b2MouseJoint self) -> b2Vec2""" return _Box2D.b2MouseJoint___GetTarget(self) def __SetMaxForce(self, force): """ __SetMaxForce(b2MouseJoint self, float32 force) Set/get the maximum force in Newtons. """ return _Box2D.b2MouseJoint___SetMaxForce(self, force) def __GetMaxForce(self): """__GetMaxForce(b2MouseJoint self) -> float32""" return _Box2D.b2MouseJoint___GetMaxForce(self) def __SetFrequency(self, hz): """ __SetFrequency(b2MouseJoint self, float32 hz) Set/get the frequency in Hertz. """ return _Box2D.b2MouseJoint___SetFrequency(self, hz) def __GetFrequency(self): """__GetFrequency(b2MouseJoint self) -> float32""" return _Box2D.b2MouseJoint___GetFrequency(self) def __SetDampingRatio(self, ratio): """ __SetDampingRatio(b2MouseJoint self, float32 ratio) Set/get the damping ratio (dimensionless). """ return _Box2D.b2MouseJoint___SetDampingRatio(self, ratio) def __GetDampingRatio(self): """__GetDampingRatio(b2MouseJoint self) -> float32""" return _Box2D.b2MouseJoint___GetDampingRatio(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2MouseJoint self) -> long""" return _Box2D.b2MouseJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-write properties maxForce = property(__GetMaxForce, __SetMaxForce) frequency = property(__GetFrequency, __SetFrequency) dampingRatio = property(__GetDampingRatio, __SetDampingRatio) target = property(__GetTarget, __SetTarget) __swig_destroy__ = _Box2D.delete_b2MouseJoint b2MouseJoint.__SetTarget = new_instancemethod(_Box2D.b2MouseJoint___SetTarget, None, b2MouseJoint) b2MouseJoint.__GetTarget = new_instancemethod(_Box2D.b2MouseJoint___GetTarget, None, b2MouseJoint) b2MouseJoint.__SetMaxForce = new_instancemethod(_Box2D.b2MouseJoint___SetMaxForce, None, b2MouseJoint) b2MouseJoint.__GetMaxForce = new_instancemethod(_Box2D.b2MouseJoint___GetMaxForce, None, b2MouseJoint) b2MouseJoint.__SetFrequency = new_instancemethod(_Box2D.b2MouseJoint___SetFrequency, None, b2MouseJoint) b2MouseJoint.__GetFrequency = new_instancemethod(_Box2D.b2MouseJoint___GetFrequency, None, b2MouseJoint) b2MouseJoint.__SetDampingRatio = new_instancemethod(_Box2D.b2MouseJoint___SetDampingRatio, None, b2MouseJoint) b2MouseJoint.__GetDampingRatio = new_instancemethod(_Box2D.b2MouseJoint___GetDampingRatio, None, b2MouseJoint) b2MouseJoint.__hash__ = new_instancemethod(_Box2D.b2MouseJoint___hash__, None, b2MouseJoint) b2MouseJoint_swigregister = _Box2D.b2MouseJoint_swigregister b2MouseJoint_swigregister(b2MouseJoint) class b2PrismaticJointDef(b2JointDef): """ Prismatic joint definition. This requires defining a line of motion using an axis and an anchor point. The definition uses local anchor points and a local axis so that the initial configuration can violate the constraint slightly. The joint translation is zero when the local anchor points coincide in world space. Using local anchors and a local axis helps when saving and loading a game. WARNING: at least one body should by dynamic with a non-fixed rotation. """ thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2PrismaticJointDef_swiginit(self,_Box2D.new_b2PrismaticJointDef()) _init_jointdef_kwargs(self, **kwargs) if self.bodyA and self.bodyB and 'referenceAngle' not in kwargs: self.referenceAngle = self.bodyB.angle - self.bodyA.angle def Initialize(self, bodyA, bodyB, anchor, axis): """ Initialize(b2PrismaticJointDef self, b2Body bodyA, b2Body bodyB, b2Vec2 anchor, b2Vec2 axis) Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis. """ return _Box2D.b2PrismaticJointDef_Initialize(self, bodyA, bodyB, anchor, axis) localAnchorA = _swig_property(_Box2D.b2PrismaticJointDef_localAnchorA_get, _Box2D.b2PrismaticJointDef_localAnchorA_set) localAnchorB = _swig_property(_Box2D.b2PrismaticJointDef_localAnchorB_get, _Box2D.b2PrismaticJointDef_localAnchorB_set) localAxisA = _swig_property(_Box2D.b2PrismaticJointDef_localAxisA_get, _Box2D.b2PrismaticJointDef_localAxisA_set) referenceAngle = _swig_property(_Box2D.b2PrismaticJointDef_referenceAngle_get, _Box2D.b2PrismaticJointDef_referenceAngle_set) enableLimit = _swig_property(_Box2D.b2PrismaticJointDef_enableLimit_get, _Box2D.b2PrismaticJointDef_enableLimit_set) lowerTranslation = _swig_property(_Box2D.b2PrismaticJointDef_lowerTranslation_get, _Box2D.b2PrismaticJointDef_lowerTranslation_set) upperTranslation = _swig_property(_Box2D.b2PrismaticJointDef_upperTranslation_get, _Box2D.b2PrismaticJointDef_upperTranslation_set) enableMotor = _swig_property(_Box2D.b2PrismaticJointDef_enableMotor_get, _Box2D.b2PrismaticJointDef_enableMotor_set) maxMotorForce = _swig_property(_Box2D.b2PrismaticJointDef_maxMotorForce_get, _Box2D.b2PrismaticJointDef_maxMotorForce_set) motorSpeed = _swig_property(_Box2D.b2PrismaticJointDef_motorSpeed_get, _Box2D.b2PrismaticJointDef_motorSpeed_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2PrismaticJointDef self) -> long""" return _Box2D.b2PrismaticJointDef___hash__(self) def __repr__(self): return _format_repr(self) def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') def __set_axis(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAxisA=self.bodyA.GetLocalVector(value) def __get_axis(self): if not self.bodyA: raise ValueError('Body A unset; unable to get world vector.') return self.bodyA.GetWorldVector(self.localAxisA) anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") axis = property(__get_axis, __set_axis, doc="""The world translation axis on bodyA. Getting the property depends on bodyA and localAxisA. Setting the property requires that bodyA be set.""") __swig_destroy__ = _Box2D.delete_b2PrismaticJointDef b2PrismaticJointDef.Initialize = new_instancemethod(_Box2D.b2PrismaticJointDef_Initialize, None, b2PrismaticJointDef) b2PrismaticJointDef.__hash__ = new_instancemethod(_Box2D.b2PrismaticJointDef___hash__, None, b2PrismaticJointDef) b2PrismaticJointDef_swigregister = _Box2D.b2PrismaticJointDef_swigregister b2PrismaticJointDef_swigregister(b2PrismaticJointDef) class b2PrismaticJoint(b2Joint): """A prismatic joint. This joint provides one degree of freedom: translation along an axis fixed in body1. Relative rotation is prevented. You can use a joint limit to restrict the range of motion and a joint motor to drive the motion or to model joint friction.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def GetLocalAnchorA(self): """GetLocalAnchorA(b2PrismaticJoint self) -> b2Vec2""" return _Box2D.b2PrismaticJoint_GetLocalAnchorA(self) def GetLocalAnchorB(self): """GetLocalAnchorB(b2PrismaticJoint self) -> b2Vec2""" return _Box2D.b2PrismaticJoint_GetLocalAnchorB(self) def GetLocalAxisA(self): """GetLocalAxisA(b2PrismaticJoint self) -> b2Vec2""" return _Box2D.b2PrismaticJoint_GetLocalAxisA(self) def GetReferenceAngle(self): """GetReferenceAngle(b2PrismaticJoint self) -> float32""" return _Box2D.b2PrismaticJoint_GetReferenceAngle(self) def __GetJointTranslation(self): """ __GetJointTranslation(b2PrismaticJoint self) -> float32 Get the current joint translation, usually in meters. """ return _Box2D.b2PrismaticJoint___GetJointTranslation(self) def __GetJointSpeed(self): """ __GetJointSpeed(b2PrismaticJoint self) -> float32 Get the current joint translation speed, usually in meters per second. """ return _Box2D.b2PrismaticJoint___GetJointSpeed(self) def __IsLimitEnabled(self): """ __IsLimitEnabled(b2PrismaticJoint self) -> bool Is the joint limit enabled? """ return _Box2D.b2PrismaticJoint___IsLimitEnabled(self) def __EnableLimit(self, flag): """ __EnableLimit(b2PrismaticJoint self, bool flag) Enable/disable the joint limit. """ return _Box2D.b2PrismaticJoint___EnableLimit(self, flag) def __GetLowerLimit(self): """ __GetLowerLimit(b2PrismaticJoint self) -> float32 Get the lower joint limit, usually in meters. """ return _Box2D.b2PrismaticJoint___GetLowerLimit(self) def __GetUpperLimit(self): """ __GetUpperLimit(b2PrismaticJoint self) -> float32 Get the upper joint limit, usually in meters. """ return _Box2D.b2PrismaticJoint___GetUpperLimit(self) def SetLimits(self, lower, upper): """ SetLimits(b2PrismaticJoint self, float32 lower, float32 upper) Set the joint limits, usually in meters. """ return _Box2D.b2PrismaticJoint_SetLimits(self, lower, upper) def __IsMotorEnabled(self): """ __IsMotorEnabled(b2PrismaticJoint self) -> bool Is the joint motor enabled? """ return _Box2D.b2PrismaticJoint___IsMotorEnabled(self) def __EnableMotor(self, flag): """ __EnableMotor(b2PrismaticJoint self, bool flag) Enable/disable the joint motor. """ return _Box2D.b2PrismaticJoint___EnableMotor(self, flag) def __SetMotorSpeed(self, speed): """ __SetMotorSpeed(b2PrismaticJoint self, float32 speed) Set the motor speed, usually in meters per second. """ return _Box2D.b2PrismaticJoint___SetMotorSpeed(self, speed) def __GetMotorSpeed(self): """ __GetMotorSpeed(b2PrismaticJoint self) -> float32 Get the motor speed, usually in meters per second. """ return _Box2D.b2PrismaticJoint___GetMotorSpeed(self) def __SetMaxMotorForce(self, force): """ __SetMaxMotorForce(b2PrismaticJoint self, float32 force) Set the maximum motor force, usually in N. """ return _Box2D.b2PrismaticJoint___SetMaxMotorForce(self, force) def __GetMaxMotorForce(self): """__GetMaxMotorForce(b2PrismaticJoint self) -> float32""" return _Box2D.b2PrismaticJoint___GetMaxMotorForce(self) def GetMotorForce(self, inv_dt): """ GetMotorForce(b2PrismaticJoint self, float32 inv_dt) -> float32 Get the current motor force given the inverse time step, usually in N. """ return _Box2D.b2PrismaticJoint_GetMotorForce(self, inv_dt) __dir__ = _dir_filter def __hash__(self): """__hash__(b2PrismaticJoint self) -> long""" return _Box2D.b2PrismaticJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-write properties motorSpeed = property(__GetMotorSpeed, __SetMotorSpeed) motorEnabled = property(__IsMotorEnabled, __EnableMotor) limitEnabled = property(__IsLimitEnabled, __EnableLimit) upperLimit = property(__GetUpperLimit, lambda self, v: self.SetLimits(self.lowerLimit, v)) lowerLimit = property(__GetLowerLimit, lambda self, v: self.SetLimits(v, self.upperLimit)) limits = property(lambda self: (self.lowerLimit, self.upperLimit), lambda self, v: self.SetLimits(*v) ) maxMotorForce = property(__GetMaxMotorForce, __SetMaxMotorForce) # Read-only translation = property(__GetJointTranslation, None) speed = property(__GetJointSpeed, None) __swig_destroy__ = _Box2D.delete_b2PrismaticJoint b2PrismaticJoint.GetLocalAnchorA = new_instancemethod(_Box2D.b2PrismaticJoint_GetLocalAnchorA, None, b2PrismaticJoint) b2PrismaticJoint.GetLocalAnchorB = new_instancemethod(_Box2D.b2PrismaticJoint_GetLocalAnchorB, None, b2PrismaticJoint) b2PrismaticJoint.GetLocalAxisA = new_instancemethod(_Box2D.b2PrismaticJoint_GetLocalAxisA, None, b2PrismaticJoint) b2PrismaticJoint.GetReferenceAngle = new_instancemethod(_Box2D.b2PrismaticJoint_GetReferenceAngle, None, b2PrismaticJoint) b2PrismaticJoint.__GetJointTranslation = new_instancemethod(_Box2D.b2PrismaticJoint___GetJointTranslation, None, b2PrismaticJoint) b2PrismaticJoint.__GetJointSpeed = new_instancemethod(_Box2D.b2PrismaticJoint___GetJointSpeed, None, b2PrismaticJoint) b2PrismaticJoint.__IsLimitEnabled = new_instancemethod(_Box2D.b2PrismaticJoint___IsLimitEnabled, None, b2PrismaticJoint) b2PrismaticJoint.__EnableLimit = new_instancemethod(_Box2D.b2PrismaticJoint___EnableLimit, None, b2PrismaticJoint) b2PrismaticJoint.__GetLowerLimit = new_instancemethod(_Box2D.b2PrismaticJoint___GetLowerLimit, None, b2PrismaticJoint) b2PrismaticJoint.__GetUpperLimit = new_instancemethod(_Box2D.b2PrismaticJoint___GetUpperLimit, None, b2PrismaticJoint) b2PrismaticJoint.SetLimits = new_instancemethod(_Box2D.b2PrismaticJoint_SetLimits, None, b2PrismaticJoint) b2PrismaticJoint.__IsMotorEnabled = new_instancemethod(_Box2D.b2PrismaticJoint___IsMotorEnabled, None, b2PrismaticJoint) b2PrismaticJoint.__EnableMotor = new_instancemethod(_Box2D.b2PrismaticJoint___EnableMotor, None, b2PrismaticJoint) b2PrismaticJoint.__SetMotorSpeed = new_instancemethod(_Box2D.b2PrismaticJoint___SetMotorSpeed, None, b2PrismaticJoint) b2PrismaticJoint.__GetMotorSpeed = new_instancemethod(_Box2D.b2PrismaticJoint___GetMotorSpeed, None, b2PrismaticJoint) b2PrismaticJoint.__SetMaxMotorForce = new_instancemethod(_Box2D.b2PrismaticJoint___SetMaxMotorForce, None, b2PrismaticJoint) b2PrismaticJoint.__GetMaxMotorForce = new_instancemethod(_Box2D.b2PrismaticJoint___GetMaxMotorForce, None, b2PrismaticJoint) b2PrismaticJoint.GetMotorForce = new_instancemethod(_Box2D.b2PrismaticJoint_GetMotorForce, None, b2PrismaticJoint) b2PrismaticJoint.__hash__ = new_instancemethod(_Box2D.b2PrismaticJoint___hash__, None, b2PrismaticJoint) b2PrismaticJoint_swigregister = _Box2D.b2PrismaticJoint_swigregister b2PrismaticJoint_swigregister(b2PrismaticJoint) class b2PulleyJointDef(b2JointDef): """Pulley joint definition. This requires two ground anchors, two dynamic body anchor points, max lengths for each side, and a pulley ratio.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2PulleyJointDef_swiginit(self,_Box2D.new_b2PulleyJointDef()) _init_jointdef_kwargs(self, **kwargs) self.__init_pulley__(**kwargs) def __init_pulley__(self, anchorA=None, anchorB=None, lengthA=None, lengthB=None, groundAnchorA=None, groundAnchorB=None, maxLengthA=None, maxLengthB=None, ratio=None, **kwargs): lengthA_set, lengthB_set = False, False if anchorA is not None or anchorB is not None: # Some undoing -- if the user specified the length, we might # have overwritten it, so reset it. if lengthA is not None: self.lengthA = lengthA lengthA_set = True if lengthB is not None: self.lengthB = lengthB lengthB_set = True if anchorA is not None and groundAnchorA is not None and lengthA is None: d1 = self.anchorA - self.groundAnchorA self.lengthA = d1.length lengthA_set = True if anchorB is not None and groundAnchorB is not None and lengthB is None: d2 = self.anchorB - self.groundAnchorB self.lengthB = d2.length lengthB_set=True if ratio is not None: # Ratio too small? assert(self.ratio > globals()['b2_epsilon']) if lengthA_set and lengthB_set and maxLengthA is None and maxLengthB is None: C = self.lengthA + self.ratio * self.lengthB self.maxLengthA = C - self.ratio * b2_minPulleyLength self.maxLengthB = (C - b2_minPulleyLength) / self.ratio def Initialize(self, bodyA, bodyB, groundAnchorA, groundAnchorB, anchorA, anchorB, ratio): """ Initialize(b2PulleyJointDef self, b2Body bodyA, b2Body bodyB, b2Vec2 groundAnchorA, b2Vec2 groundAnchorB, b2Vec2 anchorA, b2Vec2 anchorB, float32 ratio) Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. """ return _Box2D.b2PulleyJointDef_Initialize(self, bodyA, bodyB, groundAnchorA, groundAnchorB, anchorA, anchorB, ratio) groundAnchorA = _swig_property(_Box2D.b2PulleyJointDef_groundAnchorA_get, _Box2D.b2PulleyJointDef_groundAnchorA_set) groundAnchorB = _swig_property(_Box2D.b2PulleyJointDef_groundAnchorB_get, _Box2D.b2PulleyJointDef_groundAnchorB_set) localAnchorA = _swig_property(_Box2D.b2PulleyJointDef_localAnchorA_get, _Box2D.b2PulleyJointDef_localAnchorA_set) localAnchorB = _swig_property(_Box2D.b2PulleyJointDef_localAnchorB_get, _Box2D.b2PulleyJointDef_localAnchorB_set) lengthA = _swig_property(_Box2D.b2PulleyJointDef_lengthA_get, _Box2D.b2PulleyJointDef_lengthA_set) lengthB = _swig_property(_Box2D.b2PulleyJointDef_lengthB_get, _Box2D.b2PulleyJointDef_lengthB_set) ratio = _swig_property(_Box2D.b2PulleyJointDef_ratio_get, _Box2D.b2PulleyJointDef_ratio_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2PulleyJointDef self) -> long""" return _Box2D.b2PulleyJointDef___hash__(self) def __repr__(self): return _format_repr(self) def __update_length(self): if self.bodyA: d1 = self.anchorA - self.groundAnchorA self.lengthA = d1.length if self.bodyB: d1 = self.anchorB - self.groundAnchorB self.lengthB = d1.length def __set_anchorA(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.__update_length() def __set_anchorB(self, value): if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorB=self.bodyB.GetLocalPoint(value) self.__update_length() def __get_anchorA(self): if not self.bodyA: raise ValueError('bodyA not set.') return self.bodyA.GetWorldPoint(self.localAnchorA) def __get_anchorB(self): if not self.bodyB: raise ValueError('bodyB not set.') return self.bodyB.GetWorldPoint(self.localAnchorB) anchorA = property(__get_anchorA, __set_anchorA, doc="""Body A's anchor in world coordinates. Getting the property depends on both bodyA and localAnchorA. Setting the property requires that bodyA be set.""") anchorB = property(__get_anchorB, __set_anchorB, doc="""Body B's anchor in world coordinates. Getting the property depends on both bodyB and localAnchorB. Setting the property requires that bodyB be set.""") __swig_destroy__ = _Box2D.delete_b2PulleyJointDef b2PulleyJointDef.Initialize = new_instancemethod(_Box2D.b2PulleyJointDef_Initialize, None, b2PulleyJointDef) b2PulleyJointDef.__hash__ = new_instancemethod(_Box2D.b2PulleyJointDef___hash__, None, b2PulleyJointDef) b2PulleyJointDef_swigregister = _Box2D.b2PulleyJointDef_swigregister b2PulleyJointDef_swigregister(b2PulleyJointDef) b2_minPulleyLength = b2Globals.b2_minPulleyLength class b2PulleyJoint(b2Joint): """The pulley joint is connected to two bodies and two fixed ground points. The pulley supports a ratio such that: length1 + ratio * length2 <= constant Yes, the force transmitted is scaled by the ratio. The pulley also enforces a maximum length limit on both sides. This is useful to prevent one side of the pulley hitting the top.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def __GetGroundAnchorA(self): """ __GetGroundAnchorA(b2PulleyJoint self) -> b2Vec2 Get the first ground anchor. """ return _Box2D.b2PulleyJoint___GetGroundAnchorA(self) def __GetGroundAnchorB(self): """ __GetGroundAnchorB(b2PulleyJoint self) -> b2Vec2 Get the second ground anchor. """ return _Box2D.b2PulleyJoint___GetGroundAnchorB(self) def __GetLengthA(self): """__GetLengthA(b2PulleyJoint self) -> float32""" return _Box2D.b2PulleyJoint___GetLengthA(self) def __GetLengthB(self): """__GetLengthB(b2PulleyJoint self) -> float32""" return _Box2D.b2PulleyJoint___GetLengthB(self) def __GetRatio(self): """ __GetRatio(b2PulleyJoint self) -> float32 Get the pulley ratio. """ return _Box2D.b2PulleyJoint___GetRatio(self) def GetCurrentLengthA(self): """GetCurrentLengthA(b2PulleyJoint self) -> float32""" return _Box2D.b2PulleyJoint_GetCurrentLengthA(self) def GetCurrentLengthB(self): """GetCurrentLengthB(b2PulleyJoint self) -> float32""" return _Box2D.b2PulleyJoint_GetCurrentLengthB(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2PulleyJoint self) -> long""" return _Box2D.b2PulleyJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-only groundAnchorB = property(__GetGroundAnchorB, None) groundAnchorA = property(__GetGroundAnchorA, None) ratio = property(__GetRatio, None) lengthB = length2 = property(__GetLengthB, None) lengthA = length1 = property(__GetLengthA, None) __swig_destroy__ = _Box2D.delete_b2PulleyJoint b2PulleyJoint.__GetGroundAnchorA = new_instancemethod(_Box2D.b2PulleyJoint___GetGroundAnchorA, None, b2PulleyJoint) b2PulleyJoint.__GetGroundAnchorB = new_instancemethod(_Box2D.b2PulleyJoint___GetGroundAnchorB, None, b2PulleyJoint) b2PulleyJoint.__GetLengthA = new_instancemethod(_Box2D.b2PulleyJoint___GetLengthA, None, b2PulleyJoint) b2PulleyJoint.__GetLengthB = new_instancemethod(_Box2D.b2PulleyJoint___GetLengthB, None, b2PulleyJoint) b2PulleyJoint.__GetRatio = new_instancemethod(_Box2D.b2PulleyJoint___GetRatio, None, b2PulleyJoint) b2PulleyJoint.GetCurrentLengthA = new_instancemethod(_Box2D.b2PulleyJoint_GetCurrentLengthA, None, b2PulleyJoint) b2PulleyJoint.GetCurrentLengthB = new_instancemethod(_Box2D.b2PulleyJoint_GetCurrentLengthB, None, b2PulleyJoint) b2PulleyJoint.__hash__ = new_instancemethod(_Box2D.b2PulleyJoint___hash__, None, b2PulleyJoint) b2PulleyJoint_swigregister = _Box2D.b2PulleyJoint_swigregister b2PulleyJoint_swigregister(b2PulleyJoint) class b2RevoluteJointDef(b2JointDef): """Revolute joint definition. This requires defining an anchor point where the bodies are joined. The definition uses local anchor points so that the initial configuration can violate the constraint slightly. You also need to specify the initial relative angle for joint limits. This helps when saving and loading a game. The local anchor points are measured from the body's origin rather than the center of mass because: 1. you might not know where the center of mass will be. 2. if you add/remove shapes from a body and recompute the mass, the joints will be broken.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2RevoluteJointDef_swiginit(self,_Box2D.new_b2RevoluteJointDef()) _init_jointdef_kwargs(self, **kwargs) if self.bodyA and self.bodyB and 'referenceAngle' not in kwargs: self.referenceAngle = self.bodyB.angle - self.bodyA.angle def Initialize(self, bodyA, bodyB, anchor): """ Initialize(b2RevoluteJointDef self, b2Body bodyA, b2Body bodyB, b2Vec2 anchor) Initialize the bodies, anchors, and reference angle using a world anchor point. """ return _Box2D.b2RevoluteJointDef_Initialize(self, bodyA, bodyB, anchor) localAnchorA = _swig_property(_Box2D.b2RevoluteJointDef_localAnchorA_get, _Box2D.b2RevoluteJointDef_localAnchorA_set) localAnchorB = _swig_property(_Box2D.b2RevoluteJointDef_localAnchorB_get, _Box2D.b2RevoluteJointDef_localAnchorB_set) referenceAngle = _swig_property(_Box2D.b2RevoluteJointDef_referenceAngle_get, _Box2D.b2RevoluteJointDef_referenceAngle_set) enableLimit = _swig_property(_Box2D.b2RevoluteJointDef_enableLimit_get, _Box2D.b2RevoluteJointDef_enableLimit_set) lowerAngle = _swig_property(_Box2D.b2RevoluteJointDef_lowerAngle_get, _Box2D.b2RevoluteJointDef_lowerAngle_set) upperAngle = _swig_property(_Box2D.b2RevoluteJointDef_upperAngle_get, _Box2D.b2RevoluteJointDef_upperAngle_set) enableMotor = _swig_property(_Box2D.b2RevoluteJointDef_enableMotor_get, _Box2D.b2RevoluteJointDef_enableMotor_set) motorSpeed = _swig_property(_Box2D.b2RevoluteJointDef_motorSpeed_get, _Box2D.b2RevoluteJointDef_motorSpeed_set) maxMotorTorque = _swig_property(_Box2D.b2RevoluteJointDef_maxMotorTorque_get, _Box2D.b2RevoluteJointDef_maxMotorTorque_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2RevoluteJointDef self) -> long""" return _Box2D.b2RevoluteJointDef___hash__(self) def __repr__(self): return _format_repr(self) def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") __swig_destroy__ = _Box2D.delete_b2RevoluteJointDef b2RevoluteJointDef.Initialize = new_instancemethod(_Box2D.b2RevoluteJointDef_Initialize, None, b2RevoluteJointDef) b2RevoluteJointDef.__hash__ = new_instancemethod(_Box2D.b2RevoluteJointDef___hash__, None, b2RevoluteJointDef) b2RevoluteJointDef_swigregister = _Box2D.b2RevoluteJointDef_swigregister b2RevoluteJointDef_swigregister(b2RevoluteJointDef) class b2RevoluteJoint(b2Joint): """A revolute joint constrains two bodies to share a common point while they are free to rotate about the point. The relative rotation about the shared point is the joint angle. You can limit the relative rotation with a joint limit that specifies a lower and upper angle. You can use a motor to drive the relative rotation about the shared point. A maximum motor torque is provided so that infinite forces are not generated.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def GetLocalAnchorA(self): """GetLocalAnchorA(b2RevoluteJoint self) -> b2Vec2""" return _Box2D.b2RevoluteJoint_GetLocalAnchorA(self) def GetLocalAnchorB(self): """GetLocalAnchorB(b2RevoluteJoint self) -> b2Vec2""" return _Box2D.b2RevoluteJoint_GetLocalAnchorB(self) def GetReferenceAngle(self): """GetReferenceAngle(b2RevoluteJoint self) -> float32""" return _Box2D.b2RevoluteJoint_GetReferenceAngle(self) def __GetJointAngle(self): """ __GetJointAngle(b2RevoluteJoint self) -> float32 Get the current joint angle in radians. """ return _Box2D.b2RevoluteJoint___GetJointAngle(self) def __GetJointSpeed(self): """ __GetJointSpeed(b2RevoluteJoint self) -> float32 Get the current joint angle speed in radians per second. """ return _Box2D.b2RevoluteJoint___GetJointSpeed(self) def __IsLimitEnabled(self): """ __IsLimitEnabled(b2RevoluteJoint self) -> bool Is the joint limit enabled? """ return _Box2D.b2RevoluteJoint___IsLimitEnabled(self) def __EnableLimit(self, flag): """ __EnableLimit(b2RevoluteJoint self, bool flag) Enable/disable the joint limit. """ return _Box2D.b2RevoluteJoint___EnableLimit(self, flag) def __GetLowerLimit(self): """ __GetLowerLimit(b2RevoluteJoint self) -> float32 Get the lower joint limit in radians. """ return _Box2D.b2RevoluteJoint___GetLowerLimit(self) def __GetUpperLimit(self): """ __GetUpperLimit(b2RevoluteJoint self) -> float32 Get the upper joint limit in radians. """ return _Box2D.b2RevoluteJoint___GetUpperLimit(self) def SetLimits(self, lower, upper): """ SetLimits(b2RevoluteJoint self, float32 lower, float32 upper) Set the joint limits in radians. """ return _Box2D.b2RevoluteJoint_SetLimits(self, lower, upper) def __IsMotorEnabled(self): """ __IsMotorEnabled(b2RevoluteJoint self) -> bool Is the joint motor enabled? """ return _Box2D.b2RevoluteJoint___IsMotorEnabled(self) def __EnableMotor(self, flag): """ __EnableMotor(b2RevoluteJoint self, bool flag) Enable/disable the joint motor. """ return _Box2D.b2RevoluteJoint___EnableMotor(self, flag) def __SetMotorSpeed(self, speed): """ __SetMotorSpeed(b2RevoluteJoint self, float32 speed) Set the motor speed in radians per second. """ return _Box2D.b2RevoluteJoint___SetMotorSpeed(self, speed) def __GetMotorSpeed(self): """ __GetMotorSpeed(b2RevoluteJoint self) -> float32 Get the motor speed in radians per second. """ return _Box2D.b2RevoluteJoint___GetMotorSpeed(self) def __SetMaxMotorTorque(self, torque): """ __SetMaxMotorTorque(b2RevoluteJoint self, float32 torque) Set the maximum motor torque, usually in N-m. """ return _Box2D.b2RevoluteJoint___SetMaxMotorTorque(self, torque) def GetMaxMotorTorque(self): """GetMaxMotorTorque(b2RevoluteJoint self) -> float32""" return _Box2D.b2RevoluteJoint_GetMaxMotorTorque(self) def GetMotorTorque(self, inv_dt): """ GetMotorTorque(b2RevoluteJoint self, float32 inv_dt) -> float32 Get the current motor torque given the inverse time step. Unit is N*m. """ return _Box2D.b2RevoluteJoint_GetMotorTorque(self, inv_dt) __dir__ = _dir_filter def __hash__(self): """__hash__(b2RevoluteJoint self) -> long""" return _Box2D.b2RevoluteJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-write properties motorSpeed = property(__GetMotorSpeed, __SetMotorSpeed) upperLimit = property(__GetUpperLimit, lambda self, v: self.SetLimits(self.lowerLimit, v)) lowerLimit = property(__GetLowerLimit, lambda self, v: self.SetLimits(v, self.upperLimit)) limits = property(lambda self: (self.lowerLimit, self.upperLimit), lambda self, v: self.SetLimits(*v) ) motorEnabled = property(__IsMotorEnabled, __EnableMotor) limitEnabled = property(__IsLimitEnabled, __EnableLimit) # Read-only angle = property(__GetJointAngle, None) speed = property(__GetJointSpeed, None) # Write-only maxMotorTorque = property(None, __SetMaxMotorTorque) __swig_destroy__ = _Box2D.delete_b2RevoluteJoint b2RevoluteJoint.GetLocalAnchorA = new_instancemethod(_Box2D.b2RevoluteJoint_GetLocalAnchorA, None, b2RevoluteJoint) b2RevoluteJoint.GetLocalAnchorB = new_instancemethod(_Box2D.b2RevoluteJoint_GetLocalAnchorB, None, b2RevoluteJoint) b2RevoluteJoint.GetReferenceAngle = new_instancemethod(_Box2D.b2RevoluteJoint_GetReferenceAngle, None, b2RevoluteJoint) b2RevoluteJoint.__GetJointAngle = new_instancemethod(_Box2D.b2RevoluteJoint___GetJointAngle, None, b2RevoluteJoint) b2RevoluteJoint.__GetJointSpeed = new_instancemethod(_Box2D.b2RevoluteJoint___GetJointSpeed, None, b2RevoluteJoint) b2RevoluteJoint.__IsLimitEnabled = new_instancemethod(_Box2D.b2RevoluteJoint___IsLimitEnabled, None, b2RevoluteJoint) b2RevoluteJoint.__EnableLimit = new_instancemethod(_Box2D.b2RevoluteJoint___EnableLimit, None, b2RevoluteJoint) b2RevoluteJoint.__GetLowerLimit = new_instancemethod(_Box2D.b2RevoluteJoint___GetLowerLimit, None, b2RevoluteJoint) b2RevoluteJoint.__GetUpperLimit = new_instancemethod(_Box2D.b2RevoluteJoint___GetUpperLimit, None, b2RevoluteJoint) b2RevoluteJoint.SetLimits = new_instancemethod(_Box2D.b2RevoluteJoint_SetLimits, None, b2RevoluteJoint) b2RevoluteJoint.__IsMotorEnabled = new_instancemethod(_Box2D.b2RevoluteJoint___IsMotorEnabled, None, b2RevoluteJoint) b2RevoluteJoint.__EnableMotor = new_instancemethod(_Box2D.b2RevoluteJoint___EnableMotor, None, b2RevoluteJoint) b2RevoluteJoint.__SetMotorSpeed = new_instancemethod(_Box2D.b2RevoluteJoint___SetMotorSpeed, None, b2RevoluteJoint) b2RevoluteJoint.__GetMotorSpeed = new_instancemethod(_Box2D.b2RevoluteJoint___GetMotorSpeed, None, b2RevoluteJoint) b2RevoluteJoint.__SetMaxMotorTorque = new_instancemethod(_Box2D.b2RevoluteJoint___SetMaxMotorTorque, None, b2RevoluteJoint) b2RevoluteJoint.GetMaxMotorTorque = new_instancemethod(_Box2D.b2RevoluteJoint_GetMaxMotorTorque, None, b2RevoluteJoint) b2RevoluteJoint.GetMotorTorque = new_instancemethod(_Box2D.b2RevoluteJoint_GetMotorTorque, None, b2RevoluteJoint) b2RevoluteJoint.__hash__ = new_instancemethod(_Box2D.b2RevoluteJoint___hash__, None, b2RevoluteJoint) b2RevoluteJoint_swigregister = _Box2D.b2RevoluteJoint_swigregister b2RevoluteJoint_swigregister(b2RevoluteJoint) class b2RopeJointDef(b2JointDef): """Rope joint definition. This requires two body anchor points and a maximum lengths. Note: by default the connected objects will not collide. see collideConnected in b2JointDef.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2RopeJointDef_swiginit(self,_Box2D.new_b2RopeJointDef()) _init_jointdef_kwargs(self, **kwargs) localAnchorA = _swig_property(_Box2D.b2RopeJointDef_localAnchorA_get, _Box2D.b2RopeJointDef_localAnchorA_set) localAnchorB = _swig_property(_Box2D.b2RopeJointDef_localAnchorB_get, _Box2D.b2RopeJointDef_localAnchorB_set) maxLength = _swig_property(_Box2D.b2RopeJointDef_maxLength_get, _Box2D.b2RopeJointDef_maxLength_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2RopeJointDef self) -> long""" return _Box2D.b2RopeJointDef___hash__(self) def __repr__(self): return _format_repr(self) def __set_anchorA(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) def __set_anchorB(self, value): if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchorA(self): if not self.bodyA: raise ValueError('bodyA not set.') return self.bodyA.GetWorldPoint(self.localAnchorA) def __get_anchorB(self): if not self.bodyB: raise ValueError('bodyB not set.') return self.bodyB.GetWorldPoint(self.localAnchorB) anchorA = property(__get_anchorA, __set_anchorA, doc="""Body A's anchor in world coordinates. Getting the property depends on both bodyA and localAnchorA. Setting the property requires that bodyA be set.""") anchorB = property(__get_anchorB, __set_anchorB, doc="""Body B's anchor in world coordinates. Getting the property depends on both bodyB and localAnchorB. Setting the property requires that bodyB be set.""") __swig_destroy__ = _Box2D.delete_b2RopeJointDef b2RopeJointDef.__hash__ = new_instancemethod(_Box2D.b2RopeJointDef___hash__, None, b2RopeJointDef) b2RopeJointDef_swigregister = _Box2D.b2RopeJointDef_swigregister b2RopeJointDef_swigregister(b2RopeJointDef) class b2RopeJoint(b2Joint): """A rope joint enforces a maximum distance between two points on two bodies. It has no other effect. Warning: if you attempt to change the maximum length during the simulation you will get some non-physical behavior. A model that would allow you to dynamically modify the length would have some sponginess, so I chose not to implement it that way. See b2DistanceJointif you want to dynamically control length.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def GetLocalAnchorA(self): """GetLocalAnchorA(b2RopeJoint self) -> b2Vec2""" return _Box2D.b2RopeJoint_GetLocalAnchorA(self) def GetLocalAnchorB(self): """GetLocalAnchorB(b2RopeJoint self) -> b2Vec2""" return _Box2D.b2RopeJoint_GetLocalAnchorB(self) def SetMaxLength(self, length): """SetMaxLength(b2RopeJoint self, float32 length)""" return _Box2D.b2RopeJoint_SetMaxLength(self, length) def __GetMaxLength(self): """ __GetMaxLength(b2RopeJoint self) -> float32 Get the maximum length of the rope. """ return _Box2D.b2RopeJoint___GetMaxLength(self) def __GetLimitState(self): """__GetLimitState(b2RopeJoint self) -> b2LimitState""" return _Box2D.b2RopeJoint___GetLimitState(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2RopeJoint self) -> long""" return _Box2D.b2RopeJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-only properties maxLength = property(__GetMaxLength, None) limitState = property(__GetLimitState, None) # Read-write properties __swig_destroy__ = _Box2D.delete_b2RopeJoint b2RopeJoint.GetLocalAnchorA = new_instancemethod(_Box2D.b2RopeJoint_GetLocalAnchorA, None, b2RopeJoint) b2RopeJoint.GetLocalAnchorB = new_instancemethod(_Box2D.b2RopeJoint_GetLocalAnchorB, None, b2RopeJoint) b2RopeJoint.SetMaxLength = new_instancemethod(_Box2D.b2RopeJoint_SetMaxLength, None, b2RopeJoint) b2RopeJoint.__GetMaxLength = new_instancemethod(_Box2D.b2RopeJoint___GetMaxLength, None, b2RopeJoint) b2RopeJoint.__GetLimitState = new_instancemethod(_Box2D.b2RopeJoint___GetLimitState, None, b2RopeJoint) b2RopeJoint.__hash__ = new_instancemethod(_Box2D.b2RopeJoint___hash__, None, b2RopeJoint) b2RopeJoint_swigregister = _Box2D.b2RopeJoint_swigregister b2RopeJoint_swigregister(b2RopeJoint) class b2WeldJointDef(b2JointDef): """Weld joint definition. You need to specify local anchor points where they are attached and the relative body angle. The position of the anchor points is important for computing the reaction torque.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2WeldJointDef_swiginit(self,_Box2D.new_b2WeldJointDef()) _init_jointdef_kwargs(self, **kwargs) if self.bodyA and self.bodyB and 'referenceAngle' not in kwargs: self.referenceAngle = self.bodyB.angle - self.bodyA.angle def Initialize(self, bodyA, bodyB, anchor): """ Initialize(b2WeldJointDef self, b2Body bodyA, b2Body bodyB, b2Vec2 anchor) Initialize the bodies, anchors, and reference angle using a world anchor point. """ return _Box2D.b2WeldJointDef_Initialize(self, bodyA, bodyB, anchor) localAnchorA = _swig_property(_Box2D.b2WeldJointDef_localAnchorA_get, _Box2D.b2WeldJointDef_localAnchorA_set) localAnchorB = _swig_property(_Box2D.b2WeldJointDef_localAnchorB_get, _Box2D.b2WeldJointDef_localAnchorB_set) referenceAngle = _swig_property(_Box2D.b2WeldJointDef_referenceAngle_get, _Box2D.b2WeldJointDef_referenceAngle_set) frequencyHz = _swig_property(_Box2D.b2WeldJointDef_frequencyHz_get, _Box2D.b2WeldJointDef_frequencyHz_set) dampingRatio = _swig_property(_Box2D.b2WeldJointDef_dampingRatio_get, _Box2D.b2WeldJointDef_dampingRatio_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2WeldJointDef self) -> long""" return _Box2D.b2WeldJointDef___hash__(self) def __repr__(self): return _format_repr(self) def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") __swig_destroy__ = _Box2D.delete_b2WeldJointDef b2WeldJointDef.Initialize = new_instancemethod(_Box2D.b2WeldJointDef_Initialize, None, b2WeldJointDef) b2WeldJointDef.__hash__ = new_instancemethod(_Box2D.b2WeldJointDef___hash__, None, b2WeldJointDef) b2WeldJointDef_swigregister = _Box2D.b2WeldJointDef_swigregister b2WeldJointDef_swigregister(b2WeldJointDef) class b2WeldJoint(b2Joint): """A weld joint essentially glues two bodies together. A weld joint may distort somewhat because the island constraint solver is approximate.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def GetLocalAnchorA(self): """GetLocalAnchorA(b2WeldJoint self) -> b2Vec2""" return _Box2D.b2WeldJoint_GetLocalAnchorA(self) def GetLocalAnchorB(self): """GetLocalAnchorB(b2WeldJoint self) -> b2Vec2""" return _Box2D.b2WeldJoint_GetLocalAnchorB(self) def GetReferenceAngle(self): """GetReferenceAngle(b2WeldJoint self) -> float32""" return _Box2D.b2WeldJoint_GetReferenceAngle(self) def SetFrequency(self, hz): """SetFrequency(b2WeldJoint self, float32 hz)""" return _Box2D.b2WeldJoint_SetFrequency(self, hz) def GetFrequency(self): """GetFrequency(b2WeldJoint self) -> float32""" return _Box2D.b2WeldJoint_GetFrequency(self) def SetDampingRatio(self, ratio): """SetDampingRatio(b2WeldJoint self, float32 ratio)""" return _Box2D.b2WeldJoint_SetDampingRatio(self, ratio) def GetDampingRatio(self): """GetDampingRatio(b2WeldJoint self) -> float32""" return _Box2D.b2WeldJoint_GetDampingRatio(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2WeldJoint self) -> long""" return _Box2D.b2WeldJoint___hash__(self) def __repr__(self): return _format_repr(self) __swig_destroy__ = _Box2D.delete_b2WeldJoint b2WeldJoint.GetLocalAnchorA = new_instancemethod(_Box2D.b2WeldJoint_GetLocalAnchorA, None, b2WeldJoint) b2WeldJoint.GetLocalAnchorB = new_instancemethod(_Box2D.b2WeldJoint_GetLocalAnchorB, None, b2WeldJoint) b2WeldJoint.GetReferenceAngle = new_instancemethod(_Box2D.b2WeldJoint_GetReferenceAngle, None, b2WeldJoint) b2WeldJoint.SetFrequency = new_instancemethod(_Box2D.b2WeldJoint_SetFrequency, None, b2WeldJoint) b2WeldJoint.GetFrequency = new_instancemethod(_Box2D.b2WeldJoint_GetFrequency, None, b2WeldJoint) b2WeldJoint.SetDampingRatio = new_instancemethod(_Box2D.b2WeldJoint_SetDampingRatio, None, b2WeldJoint) b2WeldJoint.GetDampingRatio = new_instancemethod(_Box2D.b2WeldJoint_GetDampingRatio, None, b2WeldJoint) b2WeldJoint.__hash__ = new_instancemethod(_Box2D.b2WeldJoint___hash__, None, b2WeldJoint) b2WeldJoint_swigregister = _Box2D.b2WeldJoint_swigregister b2WeldJoint_swigregister(b2WeldJoint) class b2WheelJointDef(b2JointDef): """Line joint definition. This requires defining a line of motion using an axis and an anchor point. The definition uses local anchor points and a local axis so that the initial configuration can violate the constraint slightly. The joint translation is zero when the local anchor points coincide in world space. Using local anchors and a local axis helps when saving and loading a game.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') __repr__ = _swig_repr def __init__(self, **kwargs): _Box2D.b2WheelJointDef_swiginit(self,_Box2D.new_b2WheelJointDef()) _init_jointdef_kwargs(self, **kwargs) def Initialize(self, bodyA, bodyB, anchor, axis): """ Initialize(b2WheelJointDef self, b2Body bodyA, b2Body bodyB, b2Vec2 anchor, b2Vec2 axis) Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis. """ return _Box2D.b2WheelJointDef_Initialize(self, bodyA, bodyB, anchor, axis) localAnchorA = _swig_property(_Box2D.b2WheelJointDef_localAnchorA_get, _Box2D.b2WheelJointDef_localAnchorA_set) localAnchorB = _swig_property(_Box2D.b2WheelJointDef_localAnchorB_get, _Box2D.b2WheelJointDef_localAnchorB_set) localAxisA = _swig_property(_Box2D.b2WheelJointDef_localAxisA_get, _Box2D.b2WheelJointDef_localAxisA_set) enableMotor = _swig_property(_Box2D.b2WheelJointDef_enableMotor_get, _Box2D.b2WheelJointDef_enableMotor_set) maxMotorTorque = _swig_property(_Box2D.b2WheelJointDef_maxMotorTorque_get, _Box2D.b2WheelJointDef_maxMotorTorque_set) motorSpeed = _swig_property(_Box2D.b2WheelJointDef_motorSpeed_get, _Box2D.b2WheelJointDef_motorSpeed_set) frequencyHz = _swig_property(_Box2D.b2WheelJointDef_frequencyHz_get, _Box2D.b2WheelJointDef_frequencyHz_set) dampingRatio = _swig_property(_Box2D.b2WheelJointDef_dampingRatio_get, _Box2D.b2WheelJointDef_dampingRatio_set) __dir__ = _dir_filter def __hash__(self): """__hash__(b2WheelJointDef self) -> long""" return _Box2D.b2WheelJointDef___hash__(self) def __repr__(self): return _format_repr(self) def __set_anchor(self, value): if not self.bodyA: raise ValueError('bodyA not set.') if not self.bodyB: raise ValueError('bodyB not set.') self.localAnchorA=self.bodyA.GetLocalPoint(value) self.localAnchorB=self.bodyB.GetLocalPoint(value) def __get_anchor(self): if self.bodyA: return self.bodyA.GetWorldPoint(self.localAnchorA) if self.bodyB: return self.bodyB.GetWorldPoint(self.localAnchorB) raise ValueError('Neither body was set; unable to get world point.') def __set_axis(self, value): if not self.bodyA: raise ValueError('bodyA not set.') self.localAxisA=self.bodyA.GetLocalVector(value) def __get_axis(self): if self.bodyA: return self.bodyA.GetWorldVector(self.localAxisA) raise ValueError('Body A unset; unable to get world vector.') anchor = property(__get_anchor, __set_anchor, doc="""The anchor in world coordinates. Getting the property depends on either bodyA and localAnchorA or bodyB and localAnchorB. Setting the property requires that both bodies be set.""") axis = property(__get_axis, __set_axis, doc="""The world translation axis on bodyA. Getting the property depends on bodyA and localAxisA. Setting the property requires that bodyA be set.""") __swig_destroy__ = _Box2D.delete_b2WheelJointDef b2WheelJointDef.Initialize = new_instancemethod(_Box2D.b2WheelJointDef_Initialize, None, b2WheelJointDef) b2WheelJointDef.__hash__ = new_instancemethod(_Box2D.b2WheelJointDef___hash__, None, b2WheelJointDef) b2WheelJointDef_swigregister = _Box2D.b2WheelJointDef_swigregister b2WheelJointDef_swigregister(b2WheelJointDef) class b2WheelJoint(b2Joint): """A line joint. This joint provides two degrees of freedom: translation along an axis fixed in body1 and rotation in the plane. You can use a joint limit to restrict the range of motion and a joint motor to drive the rotation or to model rotational friction. This joint is designed for vehicle suspensions.""" thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined") __repr__ = _swig_repr def GetLocalAnchorA(self): """GetLocalAnchorA(b2WheelJoint self) -> b2Vec2""" return _Box2D.b2WheelJoint_GetLocalAnchorA(self) def GetLocalAnchorB(self): """GetLocalAnchorB(b2WheelJoint self) -> b2Vec2""" return _Box2D.b2WheelJoint_GetLocalAnchorB(self) def GetLocalAxisA(self): """GetLocalAxisA(b2WheelJoint self) -> b2Vec2""" return _Box2D.b2WheelJoint_GetLocalAxisA(self) def __GetJointTranslation(self): """ __GetJointTranslation(b2WheelJoint self) -> float32 Get the current joint translation, usually in meters. """ return _Box2D.b2WheelJoint___GetJointTranslation(self) def __GetJointSpeed(self): """ __GetJointSpeed(b2WheelJoint self) -> float32 Get the current joint translation speed, usually in meters per second. """ return _Box2D.b2WheelJoint___GetJointSpeed(self) def __IsMotorEnabled(self): """ __IsMotorEnabled(b2WheelJoint self) -> bool Is the joint motor enabled? """ return _Box2D.b2WheelJoint___IsMotorEnabled(self) def __EnableMotor(self, flag): """ __EnableMotor(b2WheelJoint self, bool flag) Enable/disable the joint motor. """ return _Box2D.b2WheelJoint___EnableMotor(self, flag) def __SetMotorSpeed(self, speed): """ __SetMotorSpeed(b2WheelJoint self, float32 speed) Set the motor speed, usually in radians per second. """ return _Box2D.b2WheelJoint___SetMotorSpeed(self, speed) def __GetMotorSpeed(self): """ __GetMotorSpeed(b2WheelJoint self) -> float32 Get the motor speed, usually in radians per second. """ return _Box2D.b2WheelJoint___GetMotorSpeed(self) def __SetMaxMotorTorque(self, torque): """ __SetMaxMotorTorque(b2WheelJoint self, float32 torque) Set/Get the maximum motor force, usually in N-m. """ return _Box2D.b2WheelJoint___SetMaxMotorTorque(self, torque) def __GetMaxMotorTorque(self): """__GetMaxMotorTorque(b2WheelJoint self) -> float32""" return _Box2D.b2WheelJoint___GetMaxMotorTorque(self) def GetMotorTorque(self, inv_dt): """ GetMotorTorque(b2WheelJoint self, float32 inv_dt) -> float32 Get the current motor torque given the inverse time step, usually in N-m. """ return _Box2D.b2WheelJoint_GetMotorTorque(self, inv_dt) def __SetSpringFrequencyHz(self, hz): """ __SetSpringFrequencyHz(b2WheelJoint self, float32 hz) Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring. """ return _Box2D.b2WheelJoint___SetSpringFrequencyHz(self, hz) def __GetSpringFrequencyHz(self): """__GetSpringFrequencyHz(b2WheelJoint self) -> float32""" return _Box2D.b2WheelJoint___GetSpringFrequencyHz(self) def __SetSpringDampingRatio(self, ratio): """ __SetSpringDampingRatio(b2WheelJoint self, float32 ratio) Set/Get the spring damping ratio. """ return _Box2D.b2WheelJoint___SetSpringDampingRatio(self, ratio) def __GetSpringDampingRatio(self): """__GetSpringDampingRatio(b2WheelJoint self) -> float32""" return _Box2D.b2WheelJoint___GetSpringDampingRatio(self) __dir__ = _dir_filter def __hash__(self): """__hash__(b2WheelJoint self) -> long""" return _Box2D.b2WheelJoint___hash__(self) def __repr__(self): return _format_repr(self) # Read-write properties motorSpeed = property(__GetMotorSpeed, __SetMotorSpeed) motorEnabled = property(__IsMotorEnabled, __EnableMotor) maxMotorTorque = property(__GetMaxMotorTorque, __SetMaxMotorTorque) springFrequencyHz = property(__GetSpringFrequencyHz , __SetSpringFrequencyHz) springDampingRatio = property(__GetSpringDampingRatio , __SetSpringDampingRatio) # Read-only speed = property(__GetJointSpeed, None) translation = property(__GetJointTranslation, None) __swig_destroy__ = _Box2D.delete_b2WheelJoint b2WheelJoint.GetLocalAnchorA = new_instancemethod(_Box2D.b2WheelJoint_GetLocalAnchorA, None, b2WheelJoint) b2WheelJoint.GetLocalAnchorB = new_instancemethod(_Box2D.b2WheelJoint_GetLocalAnchorB, None, b2WheelJoint) b2WheelJoint.GetLocalAxisA = new_instancemethod(_Box2D.b2WheelJoint_GetLocalAxisA, None, b2WheelJoint) b2WheelJoint.__GetJointTranslation = new_instancemethod(_Box2D.b2WheelJoint___GetJointTranslation, None, b2WheelJoint) b2WheelJoint.__GetJointSpeed = new_instancemethod(_Box2D.b2WheelJoint___GetJointSpeed, None, b2WheelJoint) b2WheelJoint.__IsMotorEnabled = new_instancemethod(_Box2D.b2WheelJoint___IsMotorEnabled, None, b2WheelJoint) b2WheelJoint.__EnableMotor = new_instancemethod(_Box2D.b2WheelJoint___EnableMotor, None, b2WheelJoint) b2WheelJoint.__SetMotorSpeed = new_instancemethod(_Box2D.b2WheelJoint___SetMotorSpeed, None, b2WheelJoint) b2WheelJoint.__GetMotorSpeed = new_instancemethod(_Box2D.b2WheelJoint___GetMotorSpeed, None, b2WheelJoint) b2WheelJoint.__SetMaxMotorTorque = new_instancemethod(_Box2D.b2WheelJoint___SetMaxMotorTorque, None, b2WheelJoint) b2WheelJoint.__GetMaxMotorTorque = new_instancemethod(_Box2D.b2WheelJoint___GetMaxMotorTorque, None, b2WheelJoint) b2WheelJoint.GetMotorTorque = new_instancemethod(_Box2D.b2WheelJoint_GetMotorTorque, None, b2WheelJoint) b2WheelJoint.__SetSpringFrequencyHz = new_instancemethod(_Box2D.b2WheelJoint___SetSpringFrequencyHz, None, b2WheelJoint) b2WheelJoint.__GetSpringFrequencyHz = new_instancemethod(_Box2D.b2WheelJoint___GetSpringFrequencyHz, None, b2WheelJoint) b2WheelJoint.__SetSpringDampingRatio = new_instancemethod(_Box2D.b2WheelJoint___SetSpringDampingRatio, None, b2WheelJoint) b2WheelJoint.__GetSpringDampingRatio = new_instancemethod(_Box2D.b2WheelJoint___GetSpringDampingRatio, None, b2WheelJoint) b2WheelJoint.__hash__ = new_instancemethod(_Box2D.b2WheelJoint___hash__, None, b2WheelJoint) b2WheelJoint_swigregister = _Box2D.b2WheelJoint_swigregister b2WheelJoint_swigregister(b2WheelJoint) # Backward-compatibility b2LoopShape = b2ChainShape # Initialize the alternative namespace b2.*, and clean-up the # dir listing of Box2D by removing *_swigregister. # # To see what this is, try import Box2D; print(dir(Box2D.b2)) from . import b2 s=None to_remove=[] for s in locals(): if s.endswith('_swigregister'): to_remove.append(s) elif s!='b2' and s.startswith('b2'): if s[2]=='_': # Covers b2_* setattr(b2, s[3].lower() + s[4:], locals()[s]) else: # The other b2* if s[3].isupper(): setattr(b2, s[2:], locals()[s]) else: setattr(b2, s[2].lower() + s[3:], locals()[s]) for s in to_remove: del locals()[s] del s del to_remove pybox2d-2.3.2/library/Box2D/b2/000077500000000000000000000000001276457661000160105ustar00rootroot00000000000000pybox2d-2.3.2/library/Box2D/b2/__init__.py000066400000000000000000000031711276457661000201230ustar00rootroot00000000000000# pybox2d -- http://pybox2d.googlecode.com # # Copyright (c) 2010 Ken Lauer / sirkne at gmail dot com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. __author__='Ken Lauer' __license__='zlib' __date__="$Date$" __version__="$Revision$" __doc__=""" This module holds the full usable contents of pybox2d. It offers an alternative syntax in the form of: from Box2D.b2 import * a = vec2(1,1) + vec2(2,2) This is fully equivalent to: from Box2D import * a = b2Vec2(1,1) + b2Vec2(2,2) All classes that exist in the main module that are prefixed by b2 or b2_ have been stripped. Beware that importing * from a module is generally frowned upon -- this is mainly here for convenience in debugging sessions where typing b2Vec2 repeatedly gets very old very quickly (trust me, I know.) """ # Populated by the parent package (see the end of ../Box2D.py) pass pybox2d-2.3.2/setup.py000066400000000000000000000147731276457661000146510ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ Setup script for pybox2d. For installation instructions, see INSTALL. Basic install steps: python setup.py build If that worked, then: python setup.py install """ import os import sys from glob import glob __author__='Ken Lauer' __license__='zlib' __date__="$Date$" __version__="$Revision$" import setuptools from setuptools import (setup, Extension) setuptools_version = setuptools.__version__ print('Using setuptools (version %s).' % setuptools_version) if setuptools_version: if (setuptools_version in ["0.6c%d"%i for i in range(1,9)] # old versions or setuptools_version=="0.7a1"): # 0.7a1 py 3k alpha version based on old version print('Patching setuptools.build_ext.get_ext_filename') from setuptools.command import build_ext def get_ext_filename(self, fullname): from setuptools.command.build_ext import (_build_ext, Library, use_stubs) filename = _build_ext.get_ext_filename(self,fullname) if fullname in self.ext_map: ext = self.ext_map[fullname] if isinstance(ext,Library): fn, ext = os.path.splitext(filename) return self.shlib_compiler.library_filename(fn,libtype) elif use_stubs and ext._links_to_dynamic: d,fn = os.path.split(filename) return os.path.join(d,'dl-'+fn) return filename build_ext.build_ext.get_ext_filename = get_ext_filename # release version number box2d_version = '2.3' release_number = 2 # create the version string version_str = "%s.%s" % (box2d_version, release_number) # setup some paths and names library_base='library' # the directory where the egg base will be for setuptools develop command library_name='Box2D' # the final name that the library should end up being library_path=os.path.join(library_base, library_name) # library/Box2D (e.g.) source_dir='Box2D' # where all of the C++ and SWIG source resides swig_source='Box2D.i' # the main SWIG source file use_kwargs=True # whether or not to default creating kwargs for all functions def write_init(): # read in the license header license_header = open(os.path.join(source_dir, 'pybox2d_license_header.txt')).read() # create the source code for the file if sys.version_info >= (2, 6): import_string = "from .%s import *" % library_name else: import_string = "from %s import *" % library_name init_source = [ import_string, "__author__ = '%s'" % __date__ , "__version__ = '%s'" % version_str, "__version_info__ = (%s,%d)" % (box2d_version.replace('.', ','), release_number), "__revision__ = '%s'" % __version__, "__license__ = '%s'" % __license__ , "__date__ = '%s'" % __date__ , ] # and create the __init__ file with the appropriate version string f=open(os.path.join(library_path, '__init__.py'), 'w') f.write(license_header) f.write( '\n'.join(init_source) ) f.close() source_paths = [ os.path.join(source_dir, 'Dynamics'), os.path.join(source_dir, 'Dynamics', 'Contacts'), os.path.join(source_dir, 'Dynamics', 'Joints'), os.path.join(source_dir, 'Common'), os.path.join(source_dir, 'Collision'), os.path.join(source_dir, 'Collision', 'Shapes'), ] # glob all of the paths and then flatten the list into one box2d_source_files = [os.path.join(source_dir, swig_source)] + \ sum( [glob(os.path.join(path, "*.cpp")) for path in source_paths], []) # arguments to pass to SWIG. for old versions of SWIG, -O (optimize) might not be present. # Defaults: # -O optimize, -includeall follow all include statements, -globals changes cvar->b2Globals # -Isource_dir adds source dir to include path, -outdir library_path sets the output directory # -small makes the Box2D_wrap.cpp file almost unreadable, but faster to compile. If you want # to try to understand it for whatever reason, I'd recommend removing that option. swig_arguments = \ '-c++ -I%s -small -O -includeall -ignoremissing -w201 -globals b2Globals -outdir %s' \ % (source_dir, library_path) if use_kwargs: # turn off the warnings about functions that can't use kwargs (-w511) # and let the wrapper know we're using kwargs (-D_SWIG_KWARGS) swig_arguments += " -keyword -w511 -D_SWIG_KWARGS" # depending on the platform, add extra compilation arguments. hopefully if the platform # isn't windows, g++ will be used; -Wno-unused then would suppress some annoying warnings # about the Box2D source. if sys.platform in ('win32', 'win64'): extra_args=['-I.'] else: extra_args=['-I.', '-Wno-unused'] pybox2d_extension = \ Extension('Box2D._Box2D', box2d_source_files, extra_compile_args=extra_args, language='c++') LONG_DESCRIPTION = \ """ 2D physics library Box2D %s for usage in Python. After installing please be sure to try out the testbed demos. They require either pygame or pyglet and are available on the homepage. pybox2d homepage: http://pybox2d.googlecode.com Box2D homepage: http://www.box2d.org """ % (box2d_version,) CLASSIFIERS = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: zlib/libpng License", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Libraries :: pygame", ] write_init() setup_dict = dict( name = "Box2D", version = version_str, author = "Ken Lauer", author_email = "sirkne at gmail dot com", description = "Python Box2D", license = "zlib", url ="http://pybox2d.googlecode.com/", long_description = LONG_DESCRIPTION, classifiers = CLASSIFIERS, packages = ['Box2D', 'Box2D.b2'], package_dir = {'Box2D': library_path, 'Box2D.b2': os.path.join(library_path, 'b2'), 'Box2D.tests' : 'tests'}, test_suite = 'tests', options = { 'build_ext': { 'swig_opts' : swig_arguments }, 'egg_info' : { 'egg_base' : library_base }, }, ext_modules = [ pybox2d_extension ], # use_2to3 = (sys.version_info >= (3,)), ) # run the actual setup from distutils setup(**setup_dict) pybox2d-2.3.2/tests/000077500000000000000000000000001276457661000142655ustar00rootroot00000000000000pybox2d-2.3.2/tests/__init__.py000066400000000000000000000000001276457661000163640ustar00rootroot00000000000000pybox2d-2.3.2/tests/basics.py000066400000000000000000000005631276457661000161070ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest import sys class testBasic (unittest.TestCase): # def setUp(self): # pass def test_import(self): try: import Box2D except ImportError: self.fail("Unable to import Box2D library (%s)" % sys.exc_info()[1]) if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_body.py000066400000000000000000000061221276457661000166340ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest from Box2D import * import Box2D class cl (b2ContactListener): pass class test_body (unittest.TestCase): def setUp(self): pass def test_world(self): world = b2World(gravity=(0,-10), doSleep=True) world = b2World((0,-10), True) world = b2World((0,-10), doSleep=True) def test_extended(self): world = b2World() fixture1=b2FixtureDef(shape=b2CircleShape(radius=1), density=1, friction=0.3) fixture2=b2FixtureDef(shape=b2CircleShape(radius=2), density=1, friction=0.3) shape1=b2PolygonShape(box=(5,1)) shape2=b2PolygonShape(box=(5,1)) shapefixture=b2FixtureDef(density=2.0, friction=0.3) world.CreateStaticBody(fixtures=[fixture1, fixture2], shapes=[shape1, shape2], shapeFixture=shapefixture) # make sure that 4 bodies were created self.assertEqual(len(world.bodies[-1].fixtures), 4) world.CreateKinematicBody(fixtures=[fixture1, fixture2], shapes=[shape1, shape2], shapeFixture=shapefixture) self.assertEqual(len(world.bodies[-1].fixtures), 4) world.CreateDynamicBody(fixtures=[fixture1, fixture2], shapes=[shape1, shape2], shapeFixture=shapefixture) self.assertEqual(len(world.bodies[-1].fixtures), 4) def test_body(self): self.cont_list=cl() world = b2World(gravity=(0,-10), doSleep=True, contactListener=self.cont_list) groundBody = world.CreateBody(b2BodyDef(position=(0,-10))) groundBody.CreateFixturesFromShapes(shapes=b2PolygonShape(box=(50,10))) body = world.CreateBody(b2BodyDef(type=b2_dynamicBody, position=(0,4))) body.CreateFixture(b2FixtureDef(shape=b2CircleShape(radius=1), density=1, friction=0.3)) timeStep = 1.0 / 60 vel_iters, pos_iters = 6, 2 for i in range(60): world.Step(timeStep, vel_iters, pos_iters) world.ClearForces() def test_new_createfixture(self): world = b2World(gravity=(0,-10), doSleep=True) body=world.CreateDynamicBody(position=(0,0)) body.CreateCircleFixture(radius=0.2, friction=0.2, density=1.0) body.fixtures[0] body.fixtures[0].friction body.fixtures[0].density body.fixtures[0].shape.radius body.CreatePolygonFixture(box=(1,1), friction=0.2, density=1.0) body.fixtures[1] body.fixtures[1].friction body.fixtures[1].density body.fixtures[1].shape.vertices v1=(-10, 0) v2=(-7, -1) v3=(-4, 0) v4=(0, 0) body.CreateEdgeFixture(vertices=[v1,v2,v3,v4], friction=0.3, density=1.0) body.fixtures[2] body.fixtures[2].friction body.fixtures[2].density body.fixtures[2].shape.vertices #TODO Loop shapes def test_fixture_without_shape(self): world = b2World(gravity=(0,-10), doSleep=True) body = world.CreateDynamicBody(position=(0,0)) self.assertRaises(ValueError, body.CreateFixture) if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_color.py000066400000000000000000000035201276457661000170140ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest from Box2D import b2Color class testColor (unittest.TestCase): def checkAlmostEqual(self, v1, v2, msg, places=3): for i, (a, b) in enumerate(zip(v1, v2)): self.assertAlmostEqual(a, b, places=places, msg="(index %d) %s, a=%f b=%f from %s, %s" % (i, msg, a, b, v1, v2)) def test_color(self): x, y, z = 1.0, 2.0, 3.0 c1 = b2Color(x, y, z) c2 = b2Color(z, y, x) c = c1 + c2 self.checkAlmostEqual(c, (x+z, y+y, z+x), msg='b2Color +') c = c1 - c2 self.checkAlmostEqual(c, (x-z, y-y, z-x), msg='b2Color -') c = 2.0 * c1 self.checkAlmostEqual(c, (x+x, y+y, z+z), msg='float * b2Color') c = c1 * 2.0 self.checkAlmostEqual(c, (x+x, y+y, z+z), msg='b2Color * float') c = c1 / 2.0 self.checkAlmostEqual(c, (x/2.0, y/2.0, z/2.0), msg='b2Color / float') c = c1.copy() c *= 2.0 self.checkAlmostEqual(c, (x+x, y+y, z+z), msg='b2Color *= float') c = b2Color(c1) c /= 2.0 self.checkAlmostEqual(c, (x/2.0, y/2.0, z/2.0), msg='b2Color /= float') c1 += (1.0, 1.0, 1.0) self.checkAlmostEqual(c1, (x+1, y+1, z+1), msg='b2Color +=') c1 -= (1.0, 1.0, 1.0) self.checkAlmostEqual(c1, (x, y, z), msg='b2Color -=') bytes=b2Color(1, 1, 1).bytes self.assertEqual(bytes, [255,255,255], msg='bytes (1,1,1)=>%s'%bytes) bytes=b2Color(0, 0, 0).bytes self.assertEqual(bytes, [0,0,0], msg='bytes (1,1,1)=>%s'%bytes) self.assertEqual(c1[0], x) self.assertEqual(c1[1], y) self.assertEqual(c1[2], z) c1.list = (x*2, y*2, z*2) self.checkAlmostEqual(c1, (x+x, y+y, z+z), msg='b2Color.list') if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_edgechain.py000066400000000000000000000023001276457661000176000ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest import Box2D as b2 import sys class testEdgeChain (unittest.TestCase): def setUp(self): pass def test_create_edge_chain(self): world = b2.b2World() ground = world.CreateBody(position=(0, 20)) try: ground.CreateEdgeChain([]) except ValueError: pass #good except Exception: self.fail("Failed to create empty edge chain (%s)" % sys.exc_info()[1]) try: ground.CreateEdgeChain( [ (-20,-20), (-20, 20), ( 20, 20), ( 20,-20), (-20,-20) ] ) except Exception: self.fail("Failed to create valid edge chain (%s)" % sys.exc_info()[1]) def test_b2EdgeShape(self): world = b2.b2World() v1=(-10.0, 0.0) v2=(-7.0, -1.0) v3=(-4.0, 0.0) ground=world.CreateStaticBody(shapes= [b2.b2EdgeShape(vertices=[None, v1, v2, v3])]) if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_joints.py000066400000000000000000000360311276457661000172070ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest import itertools import sys class testJoints (unittest.TestCase): world = None dbody1 = None dbody2 = None sbody1 = None sbody2 = None def _fail(self, s): # This little function would save us from an AssertionError on garbage collection. # It forces the gc to take care of the world early. self.world = None self.dbody1 = None self.dbody2 = None self.sbody1 = None self.sbody2 = None self.b2 = None self.fail(s) def setUp(self): self.b2 = __import__('Box2D') try: self.world = self.b2.b2World(self.b2.b2Vec2(0.0, -10.0), True) except Exception as ex: self.fail("Failed to create world (%s)" % ex) try: self.dbody1 = self.create_body((-3, 12)) self.dbody1.userData = "dbody1" self.dbody2 = self.create_body((0, 12)) self.dbody2.userData = "dbody2" except Exception as ex: self._fail("Failed to create dynamic bodies (%s)" % ex) try: self.sbody1 = self.create_body((0, 0), False) self.sbody1.userData = "sbody1" self.sbody2 = self.create_body((1, 4), False) self.sbody2.userData = "sbody2" except Exception as ex: self._fail("Failed to create static bodies (%s)" % ex) def create_body(self, position, dynamic=True): bodyDef = self.b2.b2BodyDef() fixtureDef = self.b2.b2FixtureDef() if dynamic: bodyDef.type = self.b2.b2_dynamicBody fixtureDef.density = 1 else: bodyDef.type = self.b2.b2_staticBody fixtureDef.density = 0 bodyDef.position = position body = self.world.CreateBody(bodyDef) dynamicBox = self.b2.b2PolygonShape() dynamicBox.SetAsBox(1, 1) fixtureDef.shape = dynamicBox fixtureDef.friction = 0.3 body.CreateFixture(fixtureDef) return body def create_circle_body(self, position, dynamic=True): bodyDef = self.b2.b2BodyDef() fixtureDef = self.b2.b2FixtureDef() if dynamic: bodyDef.type = self.b2.b2_dynamicBody fixtureDef.density = 1 else: bodyDef.type = self.b2.b2_staticBody fixtureDef.density = 0 bodyDef.position = position body = self.world.CreateBody(bodyDef) body.CreateFixture(shape=self.b2.b2CircleShape(radius=1.0), density=1.0, friction=0.3) return body def step_world(self, steps=10): timeStep = 1.0 / 60 vel_iters, pos_iters = 6, 2 for i in range(steps): self.world.Step(timeStep, vel_iters, pos_iters) def check(self, dfn, joint, prop, joint_prop=""): a = getattr(dfn, prop) if joint_prop: b = getattr(joint, joint_prop) else: b = getattr(joint, prop) self.assertEquals(a, b, "Property not equal from definition to joint: %s (dfn %s != joint %s)" % (prop, a, b) ) # ---- revolute joint ---- def revolute_definition(self, body1, body2, anchor): dfn=self.b2.b2RevoluteJointDef() dfn.Initialize(body1, body2, anchor) dfn.motorSpeed = 1.0 * self.b2.b2_pi dfn.maxMotorTorque = 10000.0 dfn.enableMotor = False dfn.lowerAngle = -0.25 * self.b2.b2_pi dfn.upperAngle = 0.5 * self.b2.b2_pi dfn.enableLimit = True dfn.collideConnected = True return dfn def revolute_asserts(self, dfn, joint): self.check(dfn, joint, "motorSpeed") self.check(dfn, joint, "lowerAngle", "lowerLimit") self.check(dfn, joint, "upperAngle", "upperLimit") self.check(dfn, joint, "enableMotor", "motorEnabled") self.check(dfn, joint, "enableLimit", "limitEnabled") self.check(dfn, joint, "bodyA") self.check(dfn, joint, "bodyB") def revolute_checks(self, dfn, joint): # check to make sure they are at least accessible joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) joint.GetMotorTorque(1.0) i = joint.angle i = joint.speed i = joint.anchorA i = joint.anchorB joint.upperLimit = 2 joint.maxMotorTorque = 10.0 joint.foobar = 2 # ---- prismatic joint ---- def prismatic_definition(self, body1, body2, anchor, axis): dfn=self.b2.b2PrismaticJointDef() dfn.Initialize(body1, body2, anchor, axis) dfn.motorSpeed = 10 dfn.maxMotorForce = 1000.0 dfn.enableMotor = True dfn.lowerTranslation = 0 dfn.upperTranslation = 20 dfn.enableLimit = True return dfn def prismatic_asserts(self, dfn, joint): self.check(dfn, joint, "motorSpeed") self.check(dfn, joint, "lowerTranslation", "lowerLimit") self.check(dfn, joint, "upperTranslation", "upperLimit") self.check(dfn, joint, "enableMotor", "motorEnabled") self.check(dfn, joint, "enableLimit", "limitEnabled") self.check(dfn, joint, "bodyA") self.check(dfn, joint, "bodyB") self.check(dfn, joint, "maxMotorForce") def prismatic_checks(self, dfn, joint): # check to make sure they are at least accessible i = joint.GetMotorForce(1.0) i = joint.anchorA i = joint.anchorB i = joint.speed i = joint.translation joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) # ---- distance joint ---- def distance_definition(self, body1, body2, anchorA, anchorB): dfn=self.b2.b2DistanceJointDef() dfn.Initialize(body1, body2, anchorA, anchorB) dfn.length = (self.b2.b2Vec2(*anchorA) - self.b2.b2Vec2(*anchorB)).length dfn.frequencyHz = 4.0 dfn.dampingRatio = 0.5 return dfn def distance_asserts(self, dfn, joint): self.check(dfn, joint, "bodyA") self.check(dfn, joint, "bodyB") self.check(dfn, joint, "length") self.check(dfn, joint, "frequencyHz", "frequency") self.check(dfn, joint, "dampingRatio") def distance_checks(self, dfn, joint): joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) # ---- Rope joint ---- def rope_definition(self, body1, body2, anchorA, anchorB, maxLength): dfn=self.b2.b2RopeJointDef(bodyA=body1, bodyB=body2, anchorA=anchorA, \ anchorB=anchorB, maxLength=maxLength) return dfn def rope_asserts(self, dfn, joint): self.check(dfn, joint, "bodyA") self.check(dfn, joint, "bodyB") self.check(dfn, joint, "maxLength") def rope_checks(self, dfn, joint): joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) joint.limitState # ---- pulley joint ---- def pulley_definition(self, body1, body2): if body2.mass == 0 or body1.mass == 0: body1 = self.dbody2 body2 = self.dbody1 dfn=self.b2.b2PulleyJointDef() a, b = 2, 4 y, L = 16, 12 anchor1 =(body1.position.x, y + b) anchor2 =(body1.position.x, y + b) groundAnchor1=(body1.position.x, y + b + L) groundAnchor2=(body1.position.x, y + b + L) dfn.Initialize(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, 2.0) return dfn def pulley_asserts(self, dfn, joint): self.check(dfn, joint, "bodyA") self.check(dfn, joint, "bodyB") self.check(dfn, joint, "groundAnchorA") self.check(dfn, joint, "groundAnchorB") self.check(dfn, joint, "ratio") def pulley_checks(self, dfn, joint): joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) # ---- mouse joint ---- def mouse_definition(self, body1, body2): dfn=self.b2.b2MouseJointDef() if body2.mass == 0: body2 = self.dbody1 if body2 == body1: body1 = self.sbody1 dfn.bodyA = body1 dfn.bodyB = body2 dfn.target = (2, 1) dfn.maxForce = 10 return dfn def mouse_asserts(self, dfn, joint): self.check(dfn, joint, "target") self.check(dfn, joint, "maxForce") self.check(dfn, joint, "frequencyHz", "frequency") self.check(dfn, joint, "dampingRatio") def mouse_checks(self, dfn, joint): joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) # ---- wheel joint ---- def wheel_definition(self, body1, body2, anchor, axis): dfn=self.b2.b2WheelJointDef() dfn.Initialize(body1, body2, anchor, axis) dfn.motorSpeed = 0 dfn.maxMotorForce = 100.0 dfn.enableMotor = True dfn.lowerTranslation = -4.0 dfn.upperTranslation = 4.0 dfn.enableLimit = True return dfn def wheel_asserts(self, dfn, joint): self.check(dfn, joint, "motorSpeed") self.check(dfn, joint, "maxMotorTorque") self.check(dfn, joint, "enableMotor", "motorEnabled") self.check(dfn, joint, "bodyA") self.check(dfn, joint, "bodyB") self.check(dfn, joint, "frequencyHz", "springFrequencyHz") self.check(dfn, joint, "dampingRatio", "springDampingRatio") def wheel_checks(self, dfn, joint): # check to make sure they are at least accessible i = joint.anchorA i = joint.anchorB i = joint.speed i = joint.translation joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) # ---- weld joint ---- def weld_definition(self, body1, body2): dfn=self.b2.b2WeldJointDef() dfn.bodyA = body1 dfn.bodyB = body2 return dfn def weld_asserts(self, dfn, joint): pass def weld_checks(self, dfn, joint): joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) # ---- friction joint ---- def friction_definition(self, body1, body2): dfn=self.b2.b2FrictionJointDef() dfn.bodyA = body1 dfn.bodyB = body2 dfn.localAnchorA = dfn.localAnchorB = (0,0) dfn.collideConnected = True dfn.maxForce = 10.0 dfn.maxTorque = 20.0 return dfn def friction_asserts(self, dfn, joint): self.check(dfn, joint, "maxForce") self.check(dfn, joint, "maxTorque") def friction_checks(self, dfn, joint): joint.GetReactionForce(1.0) joint.GetReactionTorque(1.0) def do_joint(self, name, init_args): '''test a joint by name''' get_dfn = getattr(self, "%s_definition"%name) asserts = getattr(self, "%s_asserts"%name) checks = getattr(self, "%s_checks"%name) create_name=getattr(self.world, "Create%sJoint" % (name.capitalize())) for bodyA, bodyB in itertools.permutations( ( self.sbody1, self.sbody2, self.dbody1, self.dbody2), 2 ): try: dfn = get_dfn(body1=bodyA, body2=bodyB, **init_args) except Exception as ex: self._fail("%s: Failed on bodies %s and %s, joint definition (%s)" % (name, bodyA.userData, bodyB.userData, ex)) kw_args = {} try: kw_args = dfn.to_kwargs() joint = create_name(**kw_args) self.world.DestroyJoint(joint) except Exception as ex: self._fail("%s: Failed on bodies %s and %s, joint creation by kwargs (%s) kw=%s" % (name, bodyA.userData, bodyB.userData, ex, kw_args)) try: joint = self.world.CreateJoint(dfn) except Exception as ex: self._fail("%s: Failed on bodies %s and %s, joint creation (%s)" % (name, bodyA.userData, bodyB.userData, ex)) try: asserts(dfn, joint) except Exception as ex: self.world.DestroyJoint(joint) raise try: checks(dfn, joint) except Exception as ex: self.world.DestroyJoint(joint) self._fail("%s: Failed on bodies %s and %s, joint checks (%s)" % (name, bodyA.userData, bodyB.userData, ex)) try: self.step_world(5) except Exception as ex: # self.world.DestroyJoint(joint) # -> locked try: # Ok, this will cause an assertion to go off during unwinding (in the b2StackAllocator deconstructor), # so do it once, catch that, and then fail finally self.fail() except AssertionError as ex: self._fail("%s: Failed on bodies %s and %s, joint simulation (%s)" % (name, bodyA.userData, bodyB.userData, ex)) try: self.world.DestroyJoint(joint) except Exception as ex: s=sys.exc_info()[1] self._fail("%s: Failed on bodies %s and %s joint deletion (%s)" % (name, bodyA.userData, bodyB.userData, s)) # --- the actual tests --- def test_revolute(self): self.do_joint("revolute", { 'anchor' : (0, 12) }) def test_prismatic(self): self.do_joint("prismatic", { 'anchor' : (0, 0), 'axis' : (1,0) }) def test_distance(self): self.do_joint("distance", { 'anchorA' : (-10, 0), 'anchorB' : (-0.5,-0.5) }) def test_rope(self): self.do_joint("rope", { 'anchorA' : (-10, 0), 'anchorB' : (-0.5,-0.5), 'maxLength' : 5.0 }) def test_pulley(self): self.do_joint("pulley", {} ) def test_mouse(self): self.do_joint("mouse", {} ) def test_wheel(self): self.do_joint("wheel", { 'anchor' : (0, 8.5), 'axis' : (2,1) }) def test_weld(self): self.do_joint("weld", {} ) def test_friction(self): self.do_joint("friction", {} ) def test_emptyjoint(self): try: self.world.CreateJoint( self.b2.b2RevoluteJointDef() ) except ValueError: pass # good else: raise Exception('Empty joint should have raised an exception') def test_gear(self): # creates 2 revolute joints and then joins them, so it's done separately ground=self.world.CreateBody( self.b2.b2BodyDef() ) shape=self.b2.b2EdgeShape(vertices=((50.0, 0.0), (-50.0, 0.0))) ground.CreateFixturesFromShapes(shapes=shape) body1=self.create_circle_body((-3, 12)) body2=self.create_circle_body(( 0, 12)) jd1=self.b2.b2RevoluteJointDef() jd1.Initialize(ground, body1, body1.position) joint1 = self.world.CreateJoint(jd1) jd2=self.b2.b2RevoluteJointDef() jd2.Initialize(ground, body2, body2.position) joint2 = self.world.CreateJoint(jd2) gjd=self.b2.b2GearJointDef() gjd.bodyA = body1 gjd.bodyB = body2 gjd.joint1 = joint1 gjd.joint2 = joint2 gjd.ratio = 2.0 gj = self.world.CreateJoint(gjd) self.step_world(10) self.check(gjd, gj, "ratio") gj.GetReactionForce(1.0) gj.GetReactionTorque(1.0) self.world.DestroyJoint(gj) self.world.DestroyJoint(joint2) self.world.DestroyJoint(joint1) if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_kwargs.py000066400000000000000000000044771276457661000172100ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest from Box2D import * class cl (b2ContactListener): pass class test_kwargs (unittest.TestCase): def setUp(self): pass def test_kwargs(self): self.cont_list=cl() world = b2World(gravity=(0,-10), doSleep=True, contactListener=self.cont_list) groundBody = world.CreateBody(b2BodyDef(position=(0,-10))) groundBody.CreateFixturesFromShapes(b2PolygonShape(box=(50,10))) body = world.CreateBody(b2BodyDef(type=b2_dynamicBody, position=(0,4), fixtures=[])) body = world.CreateBody( type=b2_dynamicBody, position=(0,4), fixtures=b2FixtureDef(shape=b2PolygonShape(box=(2,1)), density=1.0) ) body = world.CreateBody( type=b2_dynamicBody, position=(0,4), shapes=(b2PolygonShape(box=(2,1)), b2PolygonShape(box=(2,1))), shapeFixture=b2FixtureDef(density=1.0), ) body = world.CreateBody( type=b2_dynamicBody, position=(0,4), fixtures=b2FixtureDef(shape=b2CircleShape(radius=1), density=1, friction=0.3), shapes=(b2PolygonShape(box=(2,1)), b2PolygonShape(box=(2,1))), shapeFixture=b2FixtureDef(density=1.0), ) body.CreateFixture(shape=b2CircleShape(radius=1), density=1, friction=0.3) timeStep = 1.0 / 60 vel_iters, pos_iters = 6, 2 for i in range(60): world.Step(timeStep, vel_iters, pos_iters) world.ClearForces() def test_body(self): world = b2World(gravity=(0,-10), doSleep=True) body = world.CreateBody(b2BodyDef()) body2 = world.CreateBody(position=(1,1)) def test_joints(self): world = b2World(gravity=(0,-10), doSleep=True) body = world.CreateBody(b2BodyDef()) body2 = world.CreateBody(position=(1,1)) world.CreateJoint(type=b2RevoluteJoint, bodyA=body, bodyB=body2) world.CreateJoint(type=b2RevoluteJointDef, bodyA=body, bodyB=body2) kwargs=dict(type=b2RevoluteJointDef, bodyA=body, bodyB=body2) world.CreateJoint(**kwargs) if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_matrix.py000066400000000000000000000063131276457661000172050ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest from Box2D import b2Vec2, b2Vec3, b2Mat22, b2Mat33 class testMatrix (unittest.TestCase): def checkAlmostEqual(self, v1, v2, msg): for a, b in zip(v1, v2): self.assertAlmostEqual(a, b, places=3, msg="%s, a=%f b=%f from %s, %s" % (msg, a, b, v1, v2)) def test_mat22_identity(self): i2 = b2Mat22() self.checkAlmostEqual(i2.col1, (1.0, 0.0), msg='mat22 col1') self.checkAlmostEqual(i2.col2, (0.0, 1.0), msg='mat22 col2') def test_matrix(self): x, y, z = 1.0, 2.0, 3.0 v2 = b2Vec2(x, y) self.checkAlmostEqual(v2.skew, (-v2.y, v2.x), msg='skew') m2 = b2Mat22((x, y), (y, x)) # Note that you can't do: # m2 = b2Mat22(col1=(x, y), col2=(y, x)) # as SWIG will not allow the kwargs option to be used when there are multiple constructors m = m2 + m2 self.checkAlmostEqual(m.col1, (x+x, y+y), msg='b2Mat22 +') self.checkAlmostEqual(m.col2, (y+y, x+x), msg='b2Mat22 +') m = m2 - m2 self.checkAlmostEqual(m.col1, (0,0), msg='b2Mat22 -') self.checkAlmostEqual(m.col2, (0,0), msg='b2Mat22 -') # x y * x # y x y v = m2 * v2 self.checkAlmostEqual(v, (x*x + y*y, y*x + y*x), msg='b2Mat22 * b2Vec2') i=m2.inverse i=m2.angle m = m2 * m2 self.checkAlmostEqual(m.col1, (x*x + y*y, y*x + y*x), msg='b2Mat22 * b2Mat22') self.checkAlmostEqual(m.col2, (x*y + y*x, y*y + x*x), msg='b2Mat22 * b2Mat22') m2 += m2 self.checkAlmostEqual(m2.col1, (x+x, y+y), msg='b2Mat22 +=') self.checkAlmostEqual(m2.col2, (y+y, x+x), msg='b2Mat22 +=') m2 -= m2 self.checkAlmostEqual(m2.col1, (0,0), msg='b2Mat22 -=') self.checkAlmostEqual(m2.col2, (0,0), msg='b2Mat22 -=') def test_mat33_identity(self): i3 = b2Mat33() self.checkAlmostEqual(i3.col1, (1.0, 0.0, 0.0), msg='mat33 col1') self.checkAlmostEqual(i3.col2, (0.0, 1.0, 0.0), msg='mat33 col2') self.checkAlmostEqual(i3.col3, (0.0, 0.0, 1.0), msg='mat33 col3') def test_mat33(self): x, y, z = 1.0, 2.0, 3.0 v3 = b2Vec3(x, y, z) m3 = b2Mat33((x, y, z), (z, y, x), (y, x, z)) m = m3 + m3 self.checkAlmostEqual(m.col1, (x+x, y+y, z+z), msg='b2Mat33 +') self.checkAlmostEqual(m.col2, (z+z, y+y, x+x), msg='b2Mat33 +') self.checkAlmostEqual(m.col3, (y+y, x+x, z+z), msg='b2Mat33 +') m = m3 - m3 self.checkAlmostEqual(m.col1, (0,0,0), msg='b2Mat33 -') self.checkAlmostEqual(m.col2, (0,0,0), msg='b2Mat33 -') self.checkAlmostEqual(m.col3, (0,0,0), msg='b2Mat33 -') m3 += m3 self.checkAlmostEqual(m3.col1, (x+x, y+y, z+z), msg='b2Mat33 +=') self.checkAlmostEqual(m3.col2, (z+z, y+y, x+x), msg='b2Mat33 +=') self.checkAlmostEqual(m3.col3, (y+y, x+x, z+z), msg='b2Mat33 +=') m3 -= m3 self.checkAlmostEqual(m3.col1, (0,0,0), msg='b2Mat33 -=') self.checkAlmostEqual(m3.col2, (0,0,0), msg='b2Mat33 -=') self.checkAlmostEqual(m3.col3, (0,0,0), msg='b2Mat33 -=') if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_polyshape.py000066400000000000000000000111201276457661000176750ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest from Box2D import * from math import cos, sin import sys class ContactListener(b2ContactListener): pass class testPolyshape (unittest.TestCase): def setUp(self): pass def dotest(self, world, v): body = world.CreateDynamicBody(position=(0,0), shapes=b2PolygonShape(vertices=v) ) for v1, v2 in zip(v, body.fixtures[0].shape.vertices): if v1 != v2: raise Exception('Vertices before and after creation unequal. Before and after zipped=%s' % zip(v, body.fixtures[0].shape.vertices)) def test_vertices(self): body = None self.cont_list=ContactListener() world = b2World(gravity=(0,-10), doSleep=True, contactListener=self.cont_list) try: # bad vertices list body = world.CreateDynamicBody( position=(0,4), shapes=[b2PolygonShape(vertices=(2,1)), b2PolygonShape(box=(2,1)) ] ) except ValueError: pass # good else: raise Exception("Should have failed with ValueError / length 1") self.dotest(world, [(1,0),(1,1),(-1,1)] ) self.dotest(world, [b2Vec2(1,0),(1,1),b2Vec2(-1,1)] ) try: self.dotest(world, [(0,1,5),(1,1)] ) except ValueError: pass # good else: raise Exception("Should have failed with ValueError / length 3") pi=b2_pi n=b2_maxPolygonVertices # int so floating point representation inconsistencies # don't make the vertex check fail v = [(int(20*cos(x*2*pi/n)), int(20*sin(x*2*pi/n))) for x in range(n)] self.dotest(world, v) try: self.dotest(world, [(0,1)]*(b2_maxPolygonVertices+1) ) except ValueError: pass # good else: raise Exception("Should have failed with ValueError / max+1") # convex hull is used now, this is no longer valid #try: # shape=b2PolygonShape(vertices=[(1,0),(0,-1),(-1,0)] ) #except ValueError: # pass # good, not convex #else: # raise Exception("Should have failed with ValueError / checkpolygon") shape=b2PolygonShape(vertices=[(0,0), (0,1), (-1,0)] ) temp=shape.valid def checkAlmostEqual(self, v1, v2, msg, places=3): if hasattr(v1, '__len__'): for i, (a, b) in enumerate(zip(v1, v2)): self.assertAlmostEqual(a, b, places=places, msg="(index %d) %s, a=%f b=%f from %s, %s" % (i, msg, a, b, v1, v2)) else: self.assertAlmostEqual(v1, v2, places=places, msg="%s, a=%f b=%f" % (msg, v1, v2)) def test_distance(self): # Transform A -- a simple translation/offset of (0,-0.2) self.transformA = b2Transform() self.transformA.SetIdentity() self.transformA.position = (0, -0.2) # Transform B -- a translation and a rotation self.transformB = b2Transform() self.positionB = b2Vec2(12.017401,0.13678508) self.angleB = -0.0109265 self.transformB.Set(self.positionB, self.angleB) # The two shapes, transformed by the respective transform[A,B] self.polygonA = b2PolygonShape(box=(10,0.2)) self.polygonB = b2PolygonShape(box=(2,0.1)) # Calculate the distance between the two shapes with the specified transforms dist_result=b2Distance(shapeA=self.polygonA, transformA=self.transformA, idxA=0, shapeB=self.polygonB, transformB=self.transformB, idxB=0, useRadii=True) self.checkAlmostEqual(dist_result[0], (10, 0.01), 'point A', places=2) self.checkAlmostEqual(dist_result[1], (10, 0.05), 'point B', places=1) self.checkAlmostEqual(dist_result[2], 0.04, 'distance', places=2) assert(dist_result[3] == 2) input_ = b2DistanceInput(proxyA=b2DistanceProxy(self.polygonA, 0), transformA=self.transformA, proxyB=b2DistanceProxy(self.polygonB, 0), transformB=self.transformB, useRadii=True) assert(dist_result == b2Distance(input_)) if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_vector.py000066400000000000000000000065141276457661000172060ustar00rootroot00000000000000#!/usr/bin/env python import unittest from Box2D import (b2Vec2, b2Vec3) class testVector (unittest.TestCase): def test_vec2_zero(self): v2 = b2Vec2() self.assertAlmostEqual(v2.x, 0.0) self.assertAlmostEqual(v2.y, 0.0) def test_vec2(self): x, y = 1.0, 2.0 v = b2Vec2(x, y) v += (0.1, 0.1) self.assertAlmostEqual(v.x, x + 0.1, places=2) self.assertAlmostEqual(v.y, y + 0.1, places=2) v -= (0.1, 0.1) self.assertAlmostEqual(v.x, x, places=2) self.assertAlmostEqual(v.y, y, places=2) v = b2Vec2(x, y) v /= 2.0 self.assertAlmostEqual(v.x, x / 2.0) self.assertAlmostEqual(v.y, y / 2.0) v *= 2.0 self.assertAlmostEqual(v.x, x) self.assertAlmostEqual(v.y, y) v2 = b2Vec2(x, y) v = v2 + v2 self.assertAlmostEqual(v.x, x * 2) self.assertAlmostEqual(v.y, y * 2) v = v2 - v2 self.assertAlmostEqual(v.x, 0) self.assertAlmostEqual(v.y, 0) v = v2 / 2.0 self.assertAlmostEqual(v.x, x / 2) self.assertAlmostEqual(v.y, y / 2) v = v2 * 2.0 self.assertAlmostEqual(v.x, x * 2) self.assertAlmostEqual(v.y, y * 2) v = 0.5 * v2 self.assertAlmostEqual(v.x, x * 0.5) self.assertAlmostEqual(v.y, y * 0.5) v = 2.0 * v2 self.assertAlmostEqual(v.x, x * 2) self.assertAlmostEqual(v.y, y * 2) def test_vec3_zero(self): v3 = b2Vec3() self.assertAlmostEqual(v3.x, 0.0) self.assertAlmostEqual(v3.y, 0.0) self.assertAlmostEqual(v3.z, 0.0) def test_vec3(self): x, y, z = 1.0, 2.0, 3.0 v3 = b2Vec3(x, y, z) v = v3 + v3 self.assertAlmostEqual(v.x, x * 2) self.assertAlmostEqual(v.y, y * 2) self.assertAlmostEqual(v.z, z * 2) v = v3 - v3 self.assertAlmostEqual(v.x, 0) self.assertAlmostEqual(v.y, 0) self.assertAlmostEqual(v.z, 0) v = v3 / 2.0 self.assertAlmostEqual(v.x, x / 2) self.assertAlmostEqual(v.y, y / 2) self.assertAlmostEqual(v.z, z / 2) v = v3 * 2.0 self.assertAlmostEqual(v.x, x * 2) self.assertAlmostEqual(v.y, y * 2) self.assertAlmostEqual(v.z, z * 2) v = 0.5 * v3 self.assertAlmostEqual(v.x, x * 0.5) self.assertAlmostEqual(v.y, y * 0.5) self.assertAlmostEqual(v.z, z * 0.5) v = 2.0 * v3 self.assertAlmostEqual(v.x, x * 2) self.assertAlmostEqual(v.y, y * 2) self.assertAlmostEqual(v.z, z * 2) v = b2Vec3(x, y, z) v += (0.1, 0.1, 0.1) self.assertAlmostEqual(v.x, x + 0.1, places=2) self.assertAlmostEqual(v.y, y + 0.1, places=2) self.assertAlmostEqual(v.z, z + 0.1, places=2) v -= (0.1, 0.1, 0.1) self.assertAlmostEqual(v.x, x, places=2) self.assertAlmostEqual(v.y, y, places=2) self.assertAlmostEqual(v.z, z, places=2) v /= 1 self.assertAlmostEqual(v.x, x, places=2) self.assertAlmostEqual(v.y, y, places=2) self.assertAlmostEqual(v.z, z, places=2) v *= 1 self.assertAlmostEqual(v.x, x, places=2) self.assertAlmostEqual(v.y, y, places=2) self.assertAlmostEqual(v.z, z, places=2) if __name__ == '__main__': unittest.main() pybox2d-2.3.2/tests/test_world.py000066400000000000000000000033671276457661000170360ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import unittest import Box2D import sys class testWorld (unittest.TestCase): def setUp(self): pass def test_world(self): try: world = Box2D.b2World(Box2D.b2Vec2(0.0, -10.0), True) world = Box2D.b2World((0.0, -10.0), True) world = Box2D.b2World([0.0, -10.0], False) world = Box2D.b2World([0.0, -10.0]) world = Box2D.b2World() world = Box2D.b2World(gravity=[0.0, -10.0]) except Exception: self.fail("Failed to create world (%s)" % sys.exc_info()[1]) def test_helloworld(self): gravity = Box2D.b2Vec2(0, -10) doSleep = True world = Box2D.b2World(gravity, doSleep) groundBodyDef = Box2D.b2BodyDef() groundBodyDef.position = [0, -10] groundBody = world.CreateBody(groundBodyDef) groundBox = Box2D.b2PolygonShape() groundBox.SetAsBox(50, 10) groundBody.CreateFixturesFromShapes(groundBox) bodyDef = Box2D.b2BodyDef() bodyDef.type = Box2D.b2_dynamicBody bodyDef.position = (0, 4) body = world.CreateBody(bodyDef) dynamicBox = Box2D.b2PolygonShape() dynamicBox.SetAsBox(1, 1) fixtureDef = Box2D.b2FixtureDef() fixtureDef.shape = dynamicBox fixtureDef.density = 1 fixtureDef.friction = 0.3 body.CreateFixture(fixtureDef) timeStep = 1.0 / 60 vel_iters, pos_iters = 6, 2 for i in range(60): world.Step(timeStep, vel_iters, pos_iters) world.ClearForces() if __name__ == '__main__': unittest.main()