# HG changeset patch # User Thierry Florac # Date 1531302009 -7200 # Node ID 829abfdd6d27e7e1605dad49c1c83fbe2f0e197e # Parent 4ce98983666a74ea0875213137e589959a721cc5 Moved widget to ZMI module diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/widget/__init__.py --- a/src/pyams_gis/widget/__init__.py Wed Jul 11 11:39:49 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -# -# Copyright (c) 2008-2017 Thierry Florac -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# - -__docformat__ = 'restructuredtext' - - -# import standard library - -# import interfaces - -# import packages diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/widget/area.py --- a/src/pyams_gis/widget/area.py Wed Jul 11 11:39:49 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -# -# Copyright (c) 2008-2017 Thierry Florac -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# - -__docformat__ = 'restructuredtext' - - -# import standard library -import json - -# import interfaces -from pyams_form.interfaces.form import IFormLayer, IForm -from pyams_gis.interfaces import IGeoArea -from pyams_gis.interfaces.widget import IGeoAreaWidget -from pyams_gis.schema import IGeoAreaField -from pyams_utils.interfaces.data import IObjectData -from z3c.form.interfaces import IFieldWidget, IObjectFactory - -# import packages -from pyams_form.widget import widgettemplate_config -from pyams_gis.area import GeoArea -from pyams_utils.adapter import adapter_config -from z3c.form.browser.object import ObjectWidget -from z3c.form.object import getIfName -from z3c.form.widget import FieldWidget -from zope.interface import implementer_only, alsoProvides, Interface - - -@adapter_config(name=getIfName(IGeoArea), - context=(Interface, IFormLayer, IForm, IGeoAreaWidget), provides=IObjectFactory) -class GeoAreaObjectFactory(object): - """GeoArea object factory""" - - def __init__(self, context, request, form, widget): - self.context = context - self.request = request - self.form = form - self.widget = widget - - def __call__(self, data): - return GeoArea() - - -@widgettemplate_config(mode='input', template='templates/geoarea-input.pt', layer=IFormLayer) -@implementer_only(IGeoAreaWidget) -class GeoAreaWidget(ObjectWidget): - """GeoArea widget""" - - def updateWidgets(self, setErrors=True): - super(GeoAreaWidget, self).updateWidgets() - widgets = self.subform.widgets - x1 = widgets['x1'] - x1.input_css_class = 'col-md-2' - x1.object_data = {'ams-change-handler': 'PyAMS_GIS.area.changedCoordinate'} - alsoProvides(x1, IObjectData) - x2 = widgets['x2'] - x2.input_css_class = 'col-md-2' - x2.object_data = {'ams-change-handler': 'PyAMS_GIS.area.changedCoordinate'} - alsoProvides(x2, IObjectData) - y1 = widgets['y1'] - y1.input_css_class = 'col-md-2' - y1.object_data = {'ams-change-handler': 'PyAMS_GIS.area.changedCoordinate'} - alsoProvides(y1, IObjectData) - y2 = widgets['y2'] - y2.input_css_class = 'col-md-2' - y2.object_data = {'ams-change-handler': 'PyAMS_GIS.area.changedCoordinate'} - alsoProvides(y2, IObjectData) - projection = widgets['projection'] - projection.object_data = { - 'ams-events-handlers': { - 'change.select2': 'PyAMS_GIS.area.changedProjection' - } - } - alsoProvides(projection, IObjectData) - - @property - def wgs_coordinates(self): - value = self.field.get(self.field.interface(self.context)) - if not value: - return json.dumps({'x1': None, - 'y1': None, - 'x2': None, - 'y2': None}) - else: - point1, point2 = value.wgs_coordinates - return json.dumps({'x1': float(point1[0]), - 'y1': float(point1[1]), - 'x2': float(point2[0]), - 'y2': float(point2[1])}) - - -@adapter_config(context=(IGeoAreaField, IFormLayer), provides=IFieldWidget) -def GeoAreaFieldWidget(field, request): - """GeoArea field widget factory""" - return FieldWidget(field, GeoAreaWidget(request)) diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/widget/point.py --- a/src/pyams_gis/widget/point.py Wed Jul 11 11:39:49 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -# -# Copyright (c) 2008-2017 Thierry Florac -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# - -__docformat__ = 'restructuredtext' - - -# import standard library -import json - -# import interfaces -from pyams_gis.interfaces import IGeoPointZ -from pyams_form.interfaces.form import IFormLayer, IForm -from pyams_gis.interfaces.widget import IGeoPointWidget, IGeoPointZWidget -from pyams_gis.schema import IGeoPoint, IGeoPointField, IGeoPointZField -from pyams_utils.interfaces.data import IObjectData -from z3c.form.interfaces import IFieldWidget, IObjectFactory - -# import packages -from pyams_form.widget import widgettemplate_config -from pyams_gis.point import GeoPoint, GeoPointZ -from pyams_utils.adapter import adapter_config -from z3c.form.browser.object import ObjectWidget -from z3c.form.object import getIfName -from z3c.form.widget import FieldWidget -from zope.interface import implementer_only, alsoProvides, Interface - - -@adapter_config(name=getIfName(IGeoPoint), - context=(Interface, IFormLayer, IForm, IGeoPointWidget), provides=IObjectFactory) -class GeoPointObjectFactory(object): - """GeoPointZ object factory""" - - def __init__(self, context, request, form, widget): - self.context = context - self.request = request - self.form = form - self.widget = widget - - def __call__(self, data): - return GeoPoint() - - -@widgettemplate_config(mode='input', template='templates/geopoint-input.pt', layer=IFormLayer) -@implementer_only(IGeoPointWidget) -class GeoPointWidget(ObjectWidget): - """GeoPoint widget""" - - def updateWidgets(self, setErrors=True): - super(GeoPointWidget, self).updateWidgets(setErrors) - widgets = self.subform.widgets - longitude = widgets['longitude'] - longitude.label_css_class = 'control-label col-md-3' - longitude.input_css_class = 'col-md-2' - longitude.object_data = {'ams-change-handler': 'PyAMS_GIS.position.changedCoordinate'} - alsoProvides(longitude, IObjectData) - latitude = widgets['latitude'] - latitude.label_css_class = 'control-label col-md-3' - latitude.input_css_class = 'col-md-2' - latitude.object_data = {'ams-change-handler': 'PyAMS_GIS.position.changedCoordinate'} - alsoProvides(latitude, IObjectData) - projection = widgets['projection'] - projection.label_css_class = 'control-label col-md-3' - projection.input_css_class = 'col-md-9' - projection.object_data = {'ams-events-handlers': {'change.select2': 'PyAMS_GIS.position.changedProjection'}} - alsoProvides(projection, IObjectData) - - @property - def wgs_coordinates(self): - value = self.field.get(self.field.interface(self.context)) - if not value: - return json.dumps({'longitude': None, - 'latitude': None}) - else: - point = value.wgs_coordinates - return json.dumps({'longitude': float(point[0]), - 'latitude': float(point[1])}) - - -@adapter_config(context=(IGeoPointField, IFormLayer), provides=IFieldWidget) -def GeoPointFieldWidget(field, request): - """GeoPoint field widget factory""" - return FieldWidget(field, GeoPointWidget(request)) - - -@adapter_config(name=getIfName(IGeoPointZ), - context=(Interface, IFormLayer, IForm, IGeoPointZWidget), provides=IObjectFactory) -class GeoPointZObjectFactory(object): - """GeoPointZ object factory""" - - def __init__(self, context, request, form, widget): - self.context = context - self.request = request - self.form = form - self.widget = widget - - def __call__(self, data): - return GeoPointZ() - - -@widgettemplate_config(mode='input', template='templates/geopoint-input.pt', layer=IFormLayer) -@implementer_only(IGeoPointZWidget) -class GeoPointZWidget(ObjectWidget): - """GeoPointZ widget""" - - def updateWidgets(self, setErrors=True): - super(GeoPointZWidget, self).updateWidgets(setErrors) - widgets = self.subform.widgets - longitude = widgets['longitude'] - longitude.label_css_class = 'control-label col-md-3' - longitude.input_css_class = 'col-md-2' - longitude.object_data = {'ams-change-handler': 'PyAMS_GIS.position.changedCoordinate'} - alsoProvides(longitude, IObjectData) - latitude = widgets['latitude'] - latitude.label_css_class = 'control-label col-md-3' - latitude.input_css_class = 'col-md-2' - latitude.object_data = {'ams-change-handler': 'PyAMS_GIS.position.changedCoordinate'} - alsoProvides(latitude, IObjectData) - projection = widgets['projection'] - projection.label_css_class = 'control-label col-md-3' - latitude.input_css_class = 'col-md-9' - projection.object_data = {'ams-events-handlers': {'change.select2': 'PyAMS_GIS.position.changedProjection'}} - alsoProvides(projection, IObjectData) - altitude = widgets['altitude'] - altitude.label_css_class = 'control-label col-md-3' - altitude.input_css_class = 'col-md-2' - - @property - def wgs_coordinates(self): - value = self.field.get(self.field.interface(self.context)) - if not value: - return json.dumps({'longitude': None, - 'latitude': None}) - else: - point = value.wgs_coordinates - return json.dumps({'longitude': float(point[0]), - 'latitude': float(point[1])}) - - -@adapter_config(context=(IGeoPointZField, IFormLayer), provides=IFieldWidget) -def GeoPointZFieldWidget(field, request): - """GeoPointZ field widget factory""" - return FieldWidget(field, GeoPointZWidget(request)) diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/widget/templates/geoarea-input.pt --- a/src/pyams_gis/widget/templates/geoarea-input.pt Wed Jul 11 11:39:49 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -
-
-
-
- -
-
- -
- -
-
- - - -
- -
- -
-
-
-
- -
-
diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/widget/templates/geopoint-input.pt --- a/src/pyams_gis/widget/templates/geopoint-input.pt Wed Jul 11 11:39:49 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -
-
-
-
- -
-
- -
- -
-
- - - -
- -
- -
-
-
-
- -
-
diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/zmi/widget/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_gis/zmi/widget/__init__.py Wed Jul 11 11:40:09 2018 +0200 @@ -0,0 +1,20 @@ +# +# Copyright (c) 2008-2017 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/zmi/widget/area.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_gis/zmi/widget/area.py Wed Jul 11 11:40:09 2018 +0200 @@ -0,0 +1,103 @@ +# +# Copyright (c) 2008-2017 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library +import json + +# import interfaces +from pyams_form.interfaces.form import IFormLayer, IForm +from pyams_gis.interfaces import IGeoArea +from pyams_gis.interfaces.widget import IGeoAreaWidget +from pyams_gis.schema import IGeoAreaField +from pyams_utils.interfaces.data import IObjectData +from z3c.form.interfaces import IFieldWidget, IObjectFactory + +# import packages +from pyams_form.widget import widgettemplate_config +from pyams_gis.area import GeoArea +from pyams_utils.adapter import adapter_config +from z3c.form.browser.object import ObjectWidget +from z3c.form.object import getIfName +from z3c.form.widget import FieldWidget +from zope.interface import implementer_only, alsoProvides, Interface + + +@adapter_config(name=getIfName(IGeoArea), + context=(Interface, IFormLayer, IForm, IGeoAreaWidget), provides=IObjectFactory) +class GeoAreaObjectFactory(object): + """GeoArea object factory""" + + def __init__(self, context, request, form, widget): + self.context = context + self.request = request + self.form = form + self.widget = widget + + def __call__(self, data): + return GeoArea() + + +@widgettemplate_config(mode='input', template='templates/geoarea-input.pt', layer=IFormLayer) +@implementer_only(IGeoAreaWidget) +class GeoAreaWidget(ObjectWidget): + """GeoArea widget""" + + def updateWidgets(self, setErrors=True): + super(GeoAreaWidget, self).updateWidgets() + widgets = self.subform.widgets + x1 = widgets['x1'] + x1.input_css_class = 'col-md-2' + x1.object_data = {'ams-change-handler': 'PyAMS_GIS.area.changedCoordinate'} + alsoProvides(x1, IObjectData) + x2 = widgets['x2'] + x2.input_css_class = 'col-md-2' + x2.object_data = {'ams-change-handler': 'PyAMS_GIS.area.changedCoordinate'} + alsoProvides(x2, IObjectData) + y1 = widgets['y1'] + y1.input_css_class = 'col-md-2' + y1.object_data = {'ams-change-handler': 'PyAMS_GIS.area.changedCoordinate'} + alsoProvides(y1, IObjectData) + y2 = widgets['y2'] + y2.input_css_class = 'col-md-2' + y2.object_data = {'ams-change-handler': 'PyAMS_GIS.area.changedCoordinate'} + alsoProvides(y2, IObjectData) + projection = widgets['projection'] + projection.object_data = { + 'ams-events-handlers': { + 'change.select2': 'PyAMS_GIS.area.changedProjection' + } + } + alsoProvides(projection, IObjectData) + + @property + def wgs_coordinates(self): + value = self.field.get(self.field.interface(self.context)) + if not value: + return json.dumps({'x1': None, + 'y1': None, + 'x2': None, + 'y2': None}) + else: + point1, point2 = value.wgs_coordinates + return json.dumps({'x1': float(point1[0]), + 'y1': float(point1[1]), + 'x2': float(point2[0]), + 'y2': float(point2[1])}) + + +@adapter_config(context=(IGeoAreaField, IFormLayer), provides=IFieldWidget) +def GeoAreaFieldWidget(field, request): + """GeoArea field widget factory""" + return FieldWidget(field, GeoAreaWidget(request)) diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/zmi/widget/point.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_gis/zmi/widget/point.py Wed Jul 11 11:40:09 2018 +0200 @@ -0,0 +1,151 @@ +# +# Copyright (c) 2008-2017 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library +import json + +# import interfaces +from pyams_gis.interfaces import IGeoPointZ +from pyams_form.interfaces.form import IFormLayer, IForm +from pyams_gis.interfaces.widget import IGeoPointWidget, IGeoPointZWidget +from pyams_gis.schema import IGeoPoint, IGeoPointField, IGeoPointZField +from pyams_utils.interfaces.data import IObjectData +from z3c.form.interfaces import IFieldWidget, IObjectFactory + +# import packages +from pyams_form.widget import widgettemplate_config +from pyams_gis.point import GeoPoint, GeoPointZ +from pyams_utils.adapter import adapter_config +from z3c.form.browser.object import ObjectWidget +from z3c.form.object import getIfName +from z3c.form.widget import FieldWidget +from zope.interface import implementer_only, alsoProvides, Interface + + +@adapter_config(name=getIfName(IGeoPoint), + context=(Interface, IFormLayer, IForm, IGeoPointWidget), provides=IObjectFactory) +class GeoPointObjectFactory(object): + """GeoPointZ object factory""" + + def __init__(self, context, request, form, widget): + self.context = context + self.request = request + self.form = form + self.widget = widget + + def __call__(self, data): + return GeoPoint() + + +@widgettemplate_config(mode='input', template='templates/geopoint-input.pt', layer=IFormLayer) +@implementer_only(IGeoPointWidget) +class GeoPointWidget(ObjectWidget): + """GeoPoint widget""" + + def updateWidgets(self, setErrors=True): + super(GeoPointWidget, self).updateWidgets(setErrors) + widgets = self.subform.widgets + longitude = widgets['longitude'] + longitude.label_css_class = 'control-label col-md-3' + longitude.input_css_class = 'col-md-2' + longitude.object_data = {'ams-change-handler': 'PyAMS_GIS.position.changedCoordinate'} + alsoProvides(longitude, IObjectData) + latitude = widgets['latitude'] + latitude.label_css_class = 'control-label col-md-3' + latitude.input_css_class = 'col-md-2' + latitude.object_data = {'ams-change-handler': 'PyAMS_GIS.position.changedCoordinate'} + alsoProvides(latitude, IObjectData) + projection = widgets['projection'] + projection.label_css_class = 'control-label col-md-3' + projection.input_css_class = 'col-md-9' + projection.object_data = {'ams-events-handlers': {'change.select2': 'PyAMS_GIS.position.changedProjection'}} + alsoProvides(projection, IObjectData) + + @property + def wgs_coordinates(self): + value = self.field.get(self.field.interface(self.context)) + if not value: + return json.dumps({'longitude': None, + 'latitude': None}) + else: + point = value.wgs_coordinates + return json.dumps({'longitude': float(point[0]), + 'latitude': float(point[1])}) + + +@adapter_config(context=(IGeoPointField, IFormLayer), provides=IFieldWidget) +def GeoPointFieldWidget(field, request): + """GeoPoint field widget factory""" + return FieldWidget(field, GeoPointWidget(request)) + + +@adapter_config(name=getIfName(IGeoPointZ), + context=(Interface, IFormLayer, IForm, IGeoPointZWidget), provides=IObjectFactory) +class GeoPointZObjectFactory(object): + """GeoPointZ object factory""" + + def __init__(self, context, request, form, widget): + self.context = context + self.request = request + self.form = form + self.widget = widget + + def __call__(self, data): + return GeoPointZ() + + +@widgettemplate_config(mode='input', template='templates/geopoint-input.pt', layer=IFormLayer) +@implementer_only(IGeoPointZWidget) +class GeoPointZWidget(ObjectWidget): + """GeoPointZ widget""" + + def updateWidgets(self, setErrors=True): + super(GeoPointZWidget, self).updateWidgets(setErrors) + widgets = self.subform.widgets + longitude = widgets['longitude'] + longitude.label_css_class = 'control-label col-md-3' + longitude.input_css_class = 'col-md-2' + longitude.object_data = {'ams-change-handler': 'PyAMS_GIS.position.changedCoordinate'} + alsoProvides(longitude, IObjectData) + latitude = widgets['latitude'] + latitude.label_css_class = 'control-label col-md-3' + latitude.input_css_class = 'col-md-2' + latitude.object_data = {'ams-change-handler': 'PyAMS_GIS.position.changedCoordinate'} + alsoProvides(latitude, IObjectData) + projection = widgets['projection'] + projection.label_css_class = 'control-label col-md-3' + latitude.input_css_class = 'col-md-9' + projection.object_data = {'ams-events-handlers': {'change.select2': 'PyAMS_GIS.position.changedProjection'}} + alsoProvides(projection, IObjectData) + altitude = widgets['altitude'] + altitude.label_css_class = 'control-label col-md-3' + altitude.input_css_class = 'col-md-2' + + @property + def wgs_coordinates(self): + value = self.field.get(self.field.interface(self.context)) + if not value: + return json.dumps({'longitude': None, + 'latitude': None}) + else: + point = value.wgs_coordinates + return json.dumps({'longitude': float(point[0]), + 'latitude': float(point[1])}) + + +@adapter_config(context=(IGeoPointZField, IFormLayer), provides=IFieldWidget) +def GeoPointZFieldWidget(field, request): + """GeoPointZ field widget factory""" + return FieldWidget(field, GeoPointZWidget(request)) diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/zmi/widget/templates/geoarea-input.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_gis/zmi/widget/templates/geoarea-input.pt Wed Jul 11 11:40:09 2018 +0200 @@ -0,0 +1,85 @@ +
+
+
+
+ +
+
+ +
+ +
+
+ + + +
+ +
+ +
+
+
+
+ +
+
diff -r 4ce98983666a -r 829abfdd6d27 src/pyams_gis/zmi/widget/templates/geopoint-input.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_gis/zmi/widget/templates/geopoint-input.pt Wed Jul 11 11:40:09 2018 +0200 @@ -0,0 +1,87 @@ +
+
+
+
+ +
+
+ +
+ +
+
+ + + +
+ +
+ +
+
+
+
+ +
+