From 6c7041dcda5eacd2ce85a0e53057458c102d0cd9 Mon Sep 17 00:00:00 2001 From: charithag Date: Fri, 4 Mar 2016 10:59:33 +0530 Subject: [PATCH] Add ESP8266 based fire alarm sample --- .../firealarm/component/analytics/build.xml | 40 + .../firealarm/component/analytics/pom.xml | 90 ++ .../component/analytics/src/assembly/src.xml | 36 + .../EventReceiver_humidity.xml | 27 + .../Eventreceiver_humidity_1.0.0/artifact.xml | 23 + .../Eventstore_humidity_1.0.0/artifact.xml | 23 + .../org_wso2_iot_devices_humidity.xml | 62 + .../Eventstream_humidity_1.0.0/artifact.xml | 24 + .../org.wso2.iot.devices.humidity_1.0.0.json | 33 + .../Humidity_Sensor_Script.xml | 37 + .../Sparkscripts_1.0.0/artifact.xml | 23 + .../carbonapps/Humidity_Sensor/artifacts.xml | 33 + .../EventReceiver_temperature.xml | 27 + .../artifact.xml | 23 + .../Eventstore_temperature_1.0.0/artifact.xml | 23 + .../org_wso2_iot_devices_temperature.xml | 62 + .../artifact.xml | 24 + ...rg.wso2.iot.devices.temperature_1.0.0.json | 33 + .../Temperature_Sensor_Script.xml | 37 + .../Sparkscripts_1.0.0/artifact.xml | 23 + .../Temperature_Sensor/artifacts.xml | 34 + .../firealarm/component/controller/pom.xml | 226 +++ .../controller/api/ControllerService.java | 220 +++ .../controller/api/dto/DeviceJSON.java | 38 + .../api/exception/DeviceTypeException.java | 57 + .../api/transport/MQTTConnector.java | 229 +++ .../controller/api/util/ServiceUtils.java | 83 ++ .../webapp/META-INF/webapp-classloading.xml | 35 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 42 + .../src/main/webapp/WEB-INF/web.xml | 68 + .../firealarm/component/manager/pom.xml | 231 +++ .../firealarm/manager/api/ManagerService.java | 337 +++++ .../firealarm/manager/api/util/APIUtil.java | 54 + .../manager/api/util/ResponsePayload.java | 108 ++ .../src/main/webapp/META-INF/permissions.xml | 73 + .../webapp/META-INF/webapp-classloading.xml | 35 + .../src/main/webapp/WEB-INF/cxf-servlet.xml | 38 + .../manager/src/main/webapp/WEB-INF/web.xml | 68 + .../firealarm/component/plugin/pom.xml | 114 ++ .../plugin/constants/DeviceTypeConstants.java | 33 + .../exception/FirealarmPluginException.java | 56 + .../plugin/impl/DeviceTypeManager.java | 259 ++++ .../plugin/impl/DeviceTypeManagerService.java | 114 ++ .../plugin/impl/dao/DeviceTypeDAO.java | 132 ++ .../impl/dao/impl/DeviceTypeDAOImpl.java | 239 ++++ .../plugin/impl/dao/util/DeviceTypeUtils.java | 87 ++ .../plugin/internal/ServiceComponent.java | 72 + modules/samples/firealarm/component/pom.xml | 268 ++++ .../samples/firealarm/component/ui/pom.xml | 58 + .../component/ui/src/assembly/src.xml | 38 + .../device-view.hbs | 130 ++ .../device-view.js | 57 + .../device-view.json | 3 + .../public/images/current-sensor.png | Bin 0 -> 38879 bytes .../policy-edit.hbs | 18 + .../policy-edit.json | 3 + .../policy-view.hbs | 18 + .../policy-view.json | 3 + .../policy-wizard.hbs | 18 + .../policy-wizard.json | 3 + .../public/images/deviceType.png | Bin 0 -> 28584 bytes .../public/images/myDevices_analytics.png | Bin 0 -> 6693 bytes .../public/images/schematicsGuide.png | Bin 0 -> 128984 bytes .../public/images/thumb.png | Bin 0 -> 31021 bytes .../public/js/download.js | 195 +++ .../public/js/jquery.validate.js | 1234 +++++++++++++++++ .../type-view.hbs | 378 +++++ .../type-view.json | 3 + .../samples/firealarm/feature/feature/pom.xml | 244 ++++ .../src/main/resources/agent/dht_lib.lua | 65 + .../feature/src/main/resources/agent/init.lua | 4 + .../src/main/resources/agent/read-sensor.lua | 74 + .../main/resources/agent/sketch.properties | 16 + .../src/main/resources/agent/wifi-connect.lua | 2 + .../src/main/resources/build.properties | 18 + .../src/main/resources/configs/firealarm.json | 54 + .../src/main/resources/configs/firealarm.xml | 25 + .../datasources/firealarm-datasources.xml | 48 + .../src/main/resources/dbscripts/h2.sql | 13 + .../src/main/resources/dbscripts/mysql.sql | 12 + .../feature/feature/src/main/resources/p2.inf | 16 + modules/samples/firealarm/feature/pom.xml | 37 + modules/samples/firealarm/pom.xml | 257 ++++ modules/samples/installer/device-deployer.xml | 8 + 84 files changed, 7105 insertions(+) create mode 100644 modules/samples/firealarm/component/analytics/build.xml create mode 100644 modules/samples/firealarm/component/analytics/pom.xml create mode 100644 modules/samples/firealarm/component/analytics/src/assembly/src.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventreceiver_humidity_1.0.0/EventReceiver_humidity.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventreceiver_humidity_1.0.0/artifact.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstore_humidity_1.0.0/artifact.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstore_humidity_1.0.0/org_wso2_iot_devices_humidity.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstream_humidity_1.0.0/artifact.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstream_humidity_1.0.0/org.wso2.iot.devices.humidity_1.0.0.json create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Sparkscripts_1.0.0/Humidity_Sensor_Script.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Sparkscripts_1.0.0/artifact.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/artifacts.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml create mode 100644 modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml create mode 100644 modules/samples/firealarm/component/controller/pom.xml create mode 100644 modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/ControllerService.java create mode 100644 modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/dto/DeviceJSON.java create mode 100644 modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/exception/DeviceTypeException.java create mode 100644 modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/transport/MQTTConnector.java create mode 100644 modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/util/ServiceUtils.java create mode 100644 modules/samples/firealarm/component/controller/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 modules/samples/firealarm/component/controller/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 modules/samples/firealarm/component/controller/src/main/webapp/WEB-INF/web.xml create mode 100644 modules/samples/firealarm/component/manager/pom.xml create mode 100644 modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/ManagerService.java create mode 100644 modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/util/APIUtil.java create mode 100644 modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/util/ResponsePayload.java create mode 100644 modules/samples/firealarm/component/manager/src/main/webapp/META-INF/permissions.xml create mode 100644 modules/samples/firealarm/component/manager/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 modules/samples/firealarm/component/manager/src/main/webapp/WEB-INF/cxf-servlet.xml create mode 100644 modules/samples/firealarm/component/manager/src/main/webapp/WEB-INF/web.xml create mode 100644 modules/samples/firealarm/component/plugin/pom.xml create mode 100644 modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/constants/DeviceTypeConstants.java create mode 100644 modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/exception/FirealarmPluginException.java create mode 100644 modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/DeviceTypeManager.java create mode 100644 modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/DeviceTypeManagerService.java create mode 100644 modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/DeviceTypeDAO.java create mode 100644 modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/impl/DeviceTypeDAOImpl.java create mode 100644 modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/util/DeviceTypeUtils.java create mode 100644 modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/internal/ServiceComponent.java create mode 100644 modules/samples/firealarm/component/pom.xml create mode 100644 modules/samples/firealarm/component/ui/pom.xml create mode 100644 modules/samples/firealarm/component/ui/src/assembly/src.xml create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.hbs create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.js create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.json create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/public/images/current-sensor.png create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-edit/policy-edit.hbs create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-edit/policy-edit.json create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-view/policy-view.hbs create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-view/policy-view.json create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-wizard/policy-wizard.hbs create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-wizard/policy-wizard.json create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/images/deviceType.png create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/images/myDevices_analytics.png create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/images/schematicsGuide.png create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/images/thumb.png create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/js/download.js create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/js/jquery.validate.js create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/type-view.hbs create mode 100644 modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/type-view.json create mode 100644 modules/samples/firealarm/feature/feature/pom.xml create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/agent/dht_lib.lua create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/agent/init.lua create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/agent/read-sensor.lua create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/agent/sketch.properties create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/agent/wifi-connect.lua create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/build.properties create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/configs/firealarm.json create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/configs/firealarm.xml create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/datasources/firealarm-datasources.xml create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/dbscripts/h2.sql create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/dbscripts/mysql.sql create mode 100644 modules/samples/firealarm/feature/feature/src/main/resources/p2.inf create mode 100644 modules/samples/firealarm/feature/pom.xml create mode 100644 modules/samples/firealarm/pom.xml diff --git a/modules/samples/firealarm/component/analytics/build.xml b/modules/samples/firealarm/component/analytics/build.xml new file mode 100644 index 00000000..2f3be332 --- /dev/null +++ b/modules/samples/firealarm/component/analytics/build.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/samples/firealarm/component/analytics/pom.xml b/modules/samples/firealarm/component/analytics/pom.xml new file mode 100644 index 00000000..d587c1ae --- /dev/null +++ b/modules/samples/firealarm/component/analytics/pom.xml @@ -0,0 +1,90 @@ + + + + + + + org.homeautomation + firealarm-component + 1.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + ${groupId}.firealarm.analytics + 1.0.0-SNAPSHOT + pom + ${groupId}.firealarm.analytics + http://wso2.org + + + + maven-clean-plugin + ${maven-clean-plugin.version} + + + auto-clean + initialize + + clean + + + + + + maven-antrun-plugin + ${wso2.maven.compiler.source} + + + process-resources + + + + + + + run + + + + + + maven-assembly-plugin + ${maven-assembly-plugin.version} + + ${project.artifactId}-1.0.0-SNAPSHOT + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/analytics/src/assembly/src.xml b/modules/samples/firealarm/component/analytics/src/assembly/src.xml new file mode 100644 index 00000000..b7735b0b --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/assembly/src.xml @@ -0,0 +1,36 @@ + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/target/carbonapps + / + true + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventreceiver_humidity_1.0.0/EventReceiver_humidity.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventreceiver_humidity_1.0.0/EventReceiver_humidity.xml new file mode 100644 index 00000000..8f117bdb --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventreceiver_humidity_1.0.0/EventReceiver_humidity.xml @@ -0,0 +1,27 @@ + + + + + + false + + + + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventreceiver_humidity_1.0.0/artifact.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventreceiver_humidity_1.0.0/artifact.xml new file mode 100644 index 00000000..59756609 --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventreceiver_humidity_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + EventReceiver_humidity.xml + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstore_humidity_1.0.0/artifact.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstore_humidity_1.0.0/artifact.xml new file mode 100644 index 00000000..484978bb --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstore_humidity_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org_wso2_iot_devices_humidity.xml + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstore_humidity_1.0.0/org_wso2_iot_devices_humidity.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstore_humidity_1.0.0/org_wso2_iot_devices_humidity.xml new file mode 100644 index 00000000..5d490868 --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstore_humidity_1.0.0/org_wso2_iot_devices_humidity.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.humidity:1.0.0 + + EVENT_STORE + + + meta_owner + true + true + false + STRING + + + meta_deviceType + true + true + false + STRING + + + meta_deviceId + true + true + false + STRING + + + meta_time + true + true + false + LONG + + + humidity + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstream_humidity_1.0.0/artifact.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstream_humidity_1.0.0/artifact.xml new file mode 100644 index 00000000..84836c69 --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstream_humidity_1.0.0/artifact.xml @@ -0,0 +1,24 @@ + + + + + org.wso2.iot.devices.humidity_1.0.0.json + + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstream_humidity_1.0.0/org.wso2.iot.devices.humidity_1.0.0.json b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstream_humidity_1.0.0/org.wso2.iot.devices.humidity_1.0.0.json new file mode 100644 index 00000000..fd9ea41b --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Eventstream_humidity_1.0.0/org.wso2.iot.devices.humidity_1.0.0.json @@ -0,0 +1,33 @@ +{ + "name": "org.wso2.iot.devices.humidity", + "version": "1.0.0", + "nickName": "Humidity Data", + "description": "Humidity data received from the Device", + "metaData": [ + { + "name": "owner", + "type": "STRING" + }, + { + "name": "deviceType", + "type": "STRING" + }, + { + "name": "deviceId", + "type": "STRING" + }, + { + "name": "time", + "type": "LONG" + } + ], + "payloadData": [ + { + "name": "humidity", + "type": "FLOAT" + } + ] +} + + + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Sparkscripts_1.0.0/Humidity_Sensor_Script.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Sparkscripts_1.0.0/Humidity_Sensor_Script.xml new file mode 100644 index 00000000..ed215baa --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Sparkscripts_1.0.0/Humidity_Sensor_Script.xml @@ -0,0 +1,37 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Sparkscripts_1.0.0/artifact.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 00000000..1d92c387 --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + Humidity_Sensor_Script.xml + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/artifacts.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/artifacts.xml new file mode 100644 index 00000000..d89620e4 --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Humidity_Sensor/artifacts.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml new file mode 100644 index 00000000..b4026b4e --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/EventReceiver_temperature.xml @@ -0,0 +1,27 @@ + + + + + + false + + + + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml new file mode 100644 index 00000000..7cac6e0b --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventreceiver_temperature_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + EventReceiver_temperature.xml + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml new file mode 100644 index 00000000..02990e3c --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + org_wso2_iot_devices_temperature.xml + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml new file mode 100644 index 00000000..9e41647b --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstore_temperature_1.0.0/org_wso2_iot_devices_temperature.xml @@ -0,0 +1,62 @@ + + + + + + org.wso2.iot.devices.temperature:1.0.0 + + EVENT_STORE + + + meta_owner + true + true + false + STRING + + + meta_deviceType + true + true + false + STRING + + + meta_deviceId + true + true + false + STRING + + + meta_time + true + true + false + LONG + + + temperature + false + false + false + FLOAT + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml new file mode 100644 index 00000000..6f41292b --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/artifact.xml @@ -0,0 +1,24 @@ + + + + + org.wso2.iot.devices.temperature_1.0.0.json + + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json new file mode 100644 index 00000000..b851e5bb --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Eventstream_temperature_1.0.0/org.wso2.iot.devices.temperature_1.0.0.json @@ -0,0 +1,33 @@ +{ + "name": "org.wso2.iot.devices.temperature", + "version": "1.0.0", + "nickName": "Temperature Data", + "description": "Temperature data received from the Device", + "metaData": [ + { + "name": "owner", + "type": "STRING" + }, + { + "name": "deviceType", + "type": "STRING" + }, + { + "name": "deviceId", + "type": "STRING" + }, + { + "name": "time", + "type": "LONG" + } + ], + "payloadData": [ + { + "name": "temperature", + "type": "FLOAT" + } + ] +} + + + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml new file mode 100644 index 00000000..d184528c --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/Temperature_Sensor_Script.xml @@ -0,0 +1,37 @@ + + + + + IoTServer_Sensor_Script + + 0 * * * * ? + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml new file mode 100644 index 00000000..fa653516 --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/Sparkscripts_1.0.0/artifact.xml @@ -0,0 +1,23 @@ + + + + + Temperature_Sensor_Script.xml + diff --git a/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml new file mode 100644 index 00000000..4fa4b796 --- /dev/null +++ b/modules/samples/firealarm/component/analytics/src/main/resources/carbonapps/Temperature_Sensor/artifacts.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/modules/samples/firealarm/component/controller/pom.xml b/modules/samples/firealarm/component/controller/pom.xml new file mode 100644 index 00000000..0ffa899e --- /dev/null +++ b/modules/samples/firealarm/component/controller/pom.xml @@ -0,0 +1,226 @@ + + + + + + + org.homeautomation + firealarm-component + 1.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + ${groupId}.firealarm.controller + 1.0.0-SNAPSHOT + war + ${groupId}.firealarm.controller + http://wso2.com + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + ${maven-war-plugin.version} + + ${groupId}.firealarm.controller + + + + + + + org.homeautomation + ${project-base-package}.plugin + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + + + org.apache.cxf + cxf-rt-frontend-jaxrs + + + org.apache.cxf + cxf-rt-transports-http + + + + + org.apache.httpcomponents + httpasyncclient + 4.1 + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + + + javax.ws.rs + jsr311-api + + + commons-httpclient.wso2 + commons-httpclient + + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.bouncycastle.wso2 + bcprov-jdk15on + + + org.wso2.carbon + org.wso2.carbon.user.api + + + org.wso2.carbon + org.wso2.carbon.queuing + + + org.wso2.carbon + org.wso2.carbon.base + + + org.apache.axis2.wso2 + axis2 + + + org.igniterealtime.smack.wso2 + smack + + + org.igniterealtime.smack.wso2 + smackx + + + jaxen + jaxen + + + commons-fileupload.wso2 + commons-fileupload + + + org.apache.ant.wso2 + ant + + + org.apache.ant.wso2 + ant + + + commons-httpclient.wso2 + commons-httpclient + + + org.eclipse.equinox + javax.servlet + + + org.wso2.carbon + org.wso2.carbon.registry.api + + + + + org.igniterealtime.smack.wso2 + smack + + + org.igniterealtime.smack.wso2 + smackx + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + + + org.json.wso2 + json + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/ControllerService.java b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/ControllerService.java new file mode 100644 index 00000000..20fdcd86 --- /dev/null +++ b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/ControllerService.java @@ -0,0 +1,220 @@ +/* +* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except +* in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.homeautomation.firealarm.controller.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.homeautomation.firealarm.controller.api.dto.DeviceJSON; +import org.homeautomation.firealarm.controller.api.exception.DeviceTypeException; +import org.homeautomation.firealarm.controller.api.transport.MQTTConnector; +import org.homeautomation.firealarm.plugin.constants.DeviceTypeConstants; +import org.wso2.carbon.apimgt.annotations.api.API; +import org.wso2.carbon.apimgt.annotations.device.DeviceType; +import org.wso2.carbon.apimgt.annotations.device.feature.Feature; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.iot.DeviceManagement; +import org.wso2.carbon.device.mgt.iot.DeviceValidator; +import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; +import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; +import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; +import org.wso2.carbon.device.mgt.iot.sensormgt.SensorRecord; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * This is the controller API which is used to control agent side functionality + */ +@SuppressWarnings("NonJaxWsWebServices") +@API(name = "firealarm", version = "1.0.0", context = "/firealarm") +@DeviceType(value = "firealarm") +public class ControllerService { + + private static Log log = LogFactory.getLog(ControllerService.class); + private MQTTConnector mqttConnector; + + private boolean waitForServerStartup() { + while (!DeviceManagement.isServerReady()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return true; + } + } + return false; + } + + @SuppressWarnings("unused") + public MQTTConnector getMQTTConnector() { + return mqttConnector; + } + + @SuppressWarnings("unused") + public void setMQTTConnector(final MQTTConnector MQTTConnector) { + Runnable connector = new Runnable() { + public void run() { + if (waitForServerStartup()) { + return; + } + ControllerService.this.mqttConnector = MQTTConnector; + if (MqttConfig.getInstance().isEnabled()) { + mqttConnector.connect(); + } else { + log.warn("MQTT disabled in 'devicemgt-config.xml'. Hence, MQTTConnector" + + " not started."); + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + /** + * @param agentInfo device owner,id and sensor value + * @return device registration status + */ + @Path("controller/register") + @POST + @Consumes(MediaType.APPLICATION_JSON) + public Response registerDevice(final DeviceJSON agentInfo) { + if ((agentInfo.deviceId != null) && (agentInfo.owner != null)) { + return Response.status(Response.Status.OK).entity("Device has been registered successfully").build(); + } + return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Message body not " + + "well-formed and still invalid").build(); + } + + /** + * @param owner device owner + * @param deviceId unique identifier for given device type + * @param protocol name of supported protocol. here MQTT is used + * @param response to request + * @return sensor record + */ + @Path("controller/read-temperature") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Feature(code = "read-temperature", name = "Temperature", type = "monitor", + description = "Request temperature reading from device") + public SensorRecord readTemperature(@HeaderParam("owner") String owner, + @HeaderParam("deviceId") String deviceId, + @HeaderParam("protocol") String protocol, + @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + if (isPermitted(owner, deviceId, response)) { + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + DeviceTypeConstants.SENSOR_TEMPERATURE); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + response.setStatus(Response.Status.OK.getStatusCode()); + } + return sensorRecord; + } + + /** + * @param owner device owner + * @param deviceId unique identifier for given device type + * @param protocol name of supported protocol. here MQTT is used + * @param response to request + * @return sensor record + */ + @Path("controller/read-humidity") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Feature(code = "read-humidity", name = "Humidity", type = "monitor", + description = "Request humidity reading from device") + public SensorRecord readHumidity(@HeaderParam("owner") String owner, + @HeaderParam("deviceId") String deviceId, + @HeaderParam("protocol") String protocol, + @Context HttpServletResponse response) { + SensorRecord sensorRecord = null; + if (isPermitted(owner, deviceId, response)) { + try { + sensorRecord = SensorDataManager.getInstance().getSensorRecord(deviceId, + DeviceTypeConstants.SENSOR_HUMIDITY); + } catch (DeviceControllerException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + response.setStatus(Response.Status.OK.getStatusCode()); + } + return sensorRecord; + } + + /** + * @param owner device owner + * @param deviceId unique identifier for given device type + * @param protocol name of supported protocol. Here MQTT is used + * @param state change status of buzzer: on/off + * @param response to request + */ + @Path("controller/change-status") + @POST + @Feature(code = "change-status", name = "Buzzer: on/off", type = "operation", + description = "Switch on/off Fire Alarm Buzzer. (On / Off)") + public void changeBuzzerState(@HeaderParam("owner") String owner, + @HeaderParam("deviceId") String deviceId, + @HeaderParam("protocol") String protocol, + @FormParam("state") String state, + @Context HttpServletResponse response) { + if (isPermitted(owner, deviceId, response)) { + try { + mqttConnector.sendCommandViaMQTT(owner, deviceId, "buzzer:", state.toUpperCase()); + response.setStatus(Response.Status.OK.getStatusCode()); + } catch (DeviceManagementException e) { + log.error(e); + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } catch (DeviceTypeException e) { + log.error(e); + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + } + } + + private boolean isPermitted(String owner, String deviceId, HttpServletResponse response) { + DeviceValidator deviceValidator = new DeviceValidator(); + try { + String tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + if (!deviceValidator.isExist(owner, tenantDomain, new DeviceIdentifier( + deviceId, DeviceTypeConstants.DEVICE_TYPE))) { + response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); + } else { + return true; + } + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + return false; + } +} \ No newline at end of file diff --git a/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/dto/DeviceJSON.java b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/dto/DeviceJSON.java new file mode 100644 index 00000000..db95b8ea --- /dev/null +++ b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/dto/DeviceJSON.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.controller.api.dto; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * These information are sent by agent in each request to server + */ +@XmlRootElement +@JsonIgnoreProperties(ignoreUnknown = true) +public class DeviceJSON { + @XmlElement(required = true) + public String owner; + @XmlElement(required = true) + public String deviceId; + @XmlElement(required = true) + public Float sensorValue; +} diff --git a/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/exception/DeviceTypeException.java b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/exception/DeviceTypeException.java new file mode 100644 index 00000000..e790a4fc --- /dev/null +++ b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/exception/DeviceTypeException.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.controller.api.exception; + +public class DeviceTypeException extends Exception { + + private static final long serialVersionUID = 2736466230451105441L; + + private String errorMessage; + + public DeviceTypeException(String msg, DeviceTypeException nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public DeviceTypeException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public DeviceTypeException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public DeviceTypeException() { + super(); + } + + public DeviceTypeException(Throwable cause) { + super(cause); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/transport/MQTTConnector.java b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/transport/MQTTConnector.java new file mode 100644 index 00000000..803e4a97 --- /dev/null +++ b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/transport/MQTTConnector.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.controller.api.transport; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.homeautomation.firealarm.controller.api.exception.DeviceTypeException; +import org.homeautomation.firealarm.controller.api.util.ServiceUtils; +import org.homeautomation.firealarm.plugin.constants.DeviceTypeConstants; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.iot.controlqueue.mqtt.MqttConfig; +import org.wso2.carbon.device.mgt.iot.sensormgt.SensorDataManager; +import org.wso2.carbon.device.mgt.iot.transport.TransportHandlerException; +import org.wso2.carbon.device.mgt.iot.transport.mqtt.MQTTTransportHandler; + +import java.io.File; +import java.util.Calendar; +import java.util.UUID; + +/** + * MQTT is used as transport protocol. So this will provide basic functional requirement in order to communicate over + * MQTT + */ +@SuppressWarnings("no JAX-WS annotation") +public class MQTTConnector extends MQTTTransportHandler { + + private static final String publisherContext = "publisher"; + private static final String subscriberContext = "subscriber"; + private static final String subscribeTopic = + "wso2" + File.separator + "iot" + File.separator + "+" + File.separator + + DeviceTypeConstants.DEVICE_TYPE + File.separator + "+" + File.separator + + publisherContext; + private static Log log = LogFactory.getLog(MQTTConnector.class); + private static String iotServerSubscriber = UUID.randomUUID().toString().substring(0, 5); + String publisher = "wso2/iot/%s/firealarm/%s/" + subscriberContext; + + private MQTTConnector() { + super(iotServerSubscriber, DeviceTypeConstants.DEVICE_TYPE, + MqttConfig.getInstance().getMqttQueueEndpoint(), subscribeTopic); + } + + /** + * This method will initialize connection with message broker + */ + @Override + public void connect() { + Runnable connector = new Runnable() { + public void run() { + while (!isConnected()) { + try { + String brokerUsername = MqttConfig.getInstance().getMqttQueueUsername(); + String brokerPassword = MqttConfig.getInstance().getMqttQueuePassword(); + setUsernameAndPassword(brokerUsername, brokerPassword); + connectToQueue(); + } catch (TransportHandlerException e) { + log.error("Connection to MQTT Broker at: " + mqttBrokerEndPoint + " failed", e); + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException ex) { + log.error("MQTT-Connector: Thread Sleep Interrupt Exception.", ex); + } + } + try { + subscribeToQueue(); + } catch (TransportHandlerException e) { + log.warn("Subscription to MQTT Broker at: " + mqttBrokerEndPoint + " failed", e); + } + } + } + }; + Thread connectorThread = new Thread(connector); + connectorThread.setDaemon(true); + connectorThread.start(); + } + + /** + * This callback function will be called by message broker when some messages available to subscribed topic + * + * @param message mqtt message which is coming form agent side + * @param messageParams metadata of mqtt message + */ + @Override + public void processIncomingMessage(MqttMessage message, String... messageParams) { + String topic = messageParams[0]; + String ownerAndId = topic.replace("wso2" + File.separator + "iot" + File.separator, ""); + ownerAndId = ownerAndId.replace(File.separator + DeviceTypeConstants.DEVICE_TYPE + + File.separator, ":"); + ownerAndId = ownerAndId.replace(File.separator + publisherContext, ""); + String owner = ownerAndId.split(":")[0]; + String deviceId = ownerAndId.split(":")[1]; + String[] messageData = message.toString().split(":"); + if (log.isDebugEnabled()) { + log.debug("Received MQTT message for: [OWNER-" + owner + "] & [DEVICE.ID-" + deviceId + "]"); + } + if (messageData.length == 4) { + SensorDataManager.getInstance().setSensorRecord(deviceId, DeviceTypeConstants.SENSOR_TEMPERATURE, + messageData[1], Calendar.getInstance().getTimeInMillis()); + SensorDataManager.getInstance().setSensorRecord(deviceId, DeviceTypeConstants.SENSOR_HUMIDITY, + messageData[3], Calendar.getInstance().getTimeInMillis()); + + + if (!ServiceUtils.publishTemperatureToDAS(owner, deviceId, messageData[1])) { + log.error("MQTT Subscriber: Publishing data to DAS failed."); + } + + if (!ServiceUtils.publishHumidityToDAS(owner, deviceId, messageData[3])) { + log.error("MQTT Subscriber: Publishing data to DAS failed."); + } + + if (log.isDebugEnabled()) { + log.debug("Temperature: " + messageData[1]); + log.debug("Humidity: " + messageData[3]); + } + } + } + + /** + * Publish a MQTT message to device through message broker + * + * @param topic mqtt topic which will be used to uniquely identify who are the subscribers to this topic + * @param payLoad message is to be published + * @param qos level of qos(quality of service):1,2,3 + * @param retained life status + * @throws TransportHandlerException + */ + private void publishToAgent(String topic, String payLoad, int qos, boolean retained) + throws TransportHandlerException { + if (log.isDebugEnabled()) { + log.debug("Publishing message [" + payLoad + "to topic [" + topic + "]."); + } + publishToQueue(topic, payLoad, qos, retained); + } + + /** + * Publish a MQTT message to device through message broker + * + * @param deviceOwner person who own the device + * @param deviceId unique identifier for each device + * @param operation command is to executed at agent side e.g: off, on + * @param param additional payload + * @throws DeviceManagementException + * @throws DeviceTypeException + */ + public void sendCommandViaMQTT(String deviceOwner, String deviceId, String operation, + String param) + throws DeviceManagementException, DeviceTypeException { + String topic = String.format(publisher, deviceOwner, deviceId); + String payload = operation + param; + try { + publishToAgent(topic, payload, 2, false); + } catch (TransportHandlerException e) { + String errorMessage = "Error publishing data to device with ID " + deviceId; + throw new DeviceTypeException(errorMessage, e); + } + } + + /** + * connection with message broker can be terminated + */ + @Override + public void disconnect() { + Runnable stopConnection = new Runnable() { + public void run() { + while (isConnected()) { + try { + closeConnection(); + } catch (MqttException e) { + if (log.isDebugEnabled()) { + log.warn("Unable to 'STOP' MQTT connection at broker at: " + mqttBrokerEndPoint); + } + try { + Thread.sleep(timeoutInterval); + } catch (InterruptedException e1) { + log.error("MQTT-Terminator: Thread Sleep Interrupt Exception"); + } + } + } + } + }; + Thread terminatorThread = new Thread(stopConnection); + terminatorThread.setDaemon(true); + terminatorThread.start(); + } + + + @Override + public void publishDeviceData() throws TransportHandlerException { + + } + + @Override + public void publishDeviceData(MqttMessage publishData) throws TransportHandlerException { + + } + + @Override + public void publishDeviceData(String... publishData) throws TransportHandlerException { + + } + + @Override + public void processIncomingMessage() { + + } + + @Override + public void processIncomingMessage(MqttMessage message) throws TransportHandlerException { + + } + +} diff --git a/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/util/ServiceUtils.java b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/util/ServiceUtils.java new file mode 100644 index 00000000..98ad99c2 --- /dev/null +++ b/modules/samples/firealarm/component/controller/src/main/java/org.homeautomation/firealarm/controller/api/util/ServiceUtils.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.controller.api.util; + +import org.homeautomation.firealarm.plugin.constants.DeviceTypeConstants; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.analytics.exception.DataPublisherConfigurationException; +import org.wso2.carbon.device.mgt.analytics.service.DeviceAnalyticsService; + +public class ServiceUtils { + + private static final String ORG_WSO2_IOT_DEVICES_TEMPERATURE = "org.wso2.iot.devices.temperature"; + private static final String ORG_WSO2_IOT_DEVICES_HUMIDITY = "org.wso2.iot.devices.humidity"; + private static final String SENSOR_STREAM_VERSION = "1.0.0"; + + /** + * sensor data are published to DAS + * + * @param owner name of device owner + * @param deviceId unique identifier of the device + * @param sensorValue current value of sensor which is set at agent side + * @return status + */ + public static boolean publishTemperatureToDAS(String owner, String deviceId, + String sensorValue) { + float temperature = Float.parseFloat(sensorValue); + Object payloadCurrent[] = {temperature}; + return publishToDAS(owner, deviceId, payloadCurrent, ORG_WSO2_IOT_DEVICES_TEMPERATURE); + } + + /** + * sensor data are published to DAS + * + * @param owner name of device owner + * @param deviceId unique identifier of the device + * @param sensorValue current value of sensor which is set at agent side + * @return status + */ + public static boolean publishHumidityToDAS(String owner, String deviceId, + String sensorValue) { + float humidity = Float.parseFloat(sensorValue); + Object payloadCurrent[] = {humidity}; + return publishToDAS(owner, deviceId, payloadCurrent, ORG_WSO2_IOT_DEVICES_HUMIDITY); + } + + private static boolean publishToDAS(String owner, String deviceId, Object[] payloadCurrent, + String definition) { + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + ctx.setUsername(owner); + if (ctx.getTenantDomain(true) == null) { + ctx.setTenantDomain("carbon.super", true); + } + DeviceAnalyticsService deviceAnalyticsService = (DeviceAnalyticsService) ctx.getOSGiService( + DeviceAnalyticsService.class, null); + Object metaData[] = {owner, DeviceTypeConstants.DEVICE_TYPE, deviceId, System.currentTimeMillis()}; + try { + deviceAnalyticsService.publishEvent(definition, SENSOR_STREAM_VERSION, metaData, + new Object[0], payloadCurrent); + } catch (DataPublisherConfigurationException e) { + return false; + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + return true; + } +} diff --git a/modules/samples/firealarm/component/controller/src/main/webapp/META-INF/webapp-classloading.xml b/modules/samples/firealarm/component/controller/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 00000000..b410b426 --- /dev/null +++ b/modules/samples/firealarm/component/controller/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,35 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/modules/samples/firealarm/component/controller/src/main/webapp/WEB-INF/cxf-servlet.xml b/modules/samples/firealarm/component/controller/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 00000000..46a71e29 --- /dev/null +++ b/modules/samples/firealarm/component/controller/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + diff --git a/modules/samples/firealarm/component/controller/src/main/webapp/WEB-INF/web.xml b/modules/samples/firealarm/component/controller/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..7f6126d2 --- /dev/null +++ b/modules/samples/firealarm/component/controller/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,68 @@ + + + + + + Sample-Webapp-Controller + + JAX-WS/JAX-RS Endpoint + JAX-WS/JAX-RS Servlet + CXFServlet + + org.apache.cxf.transport.servlet.CXFServlet + + 1 + + + CXFServlet + /* + + + isAdminService + false + + + doAuthentication + false + + + + managed-api-enabled + true + + + managed-api-owner + admin + + + managed-api-context-template + /firealarm/{version} + + + managed-api-application + firealarm + + + managed-api-isSecured + true + + diff --git a/modules/samples/firealarm/component/manager/pom.xml b/modules/samples/firealarm/component/manager/pom.xml new file mode 100644 index 00000000..fd549767 --- /dev/null +++ b/modules/samples/firealarm/component/manager/pom.xml @@ -0,0 +1,231 @@ + + + + + + + org.homeautomation + firealarm-component + 1.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + ${groupId}.firealarm.manager + war + 1.0.0-SNAPSHOT + ${groupId}.firealarm.manager + http://wso2.org + + ${basedir}/src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + maven-war-plugin + ${maven-war-plugin.version} + + ${groupId}.firealarm.manager_mgt + + + + + + + org.homeautomation + ${project-base-package}.plugin + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + + + org.apache.axis2.wso2 + axis2-client + + + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + + + commons-codec.wso2 + commons-codec + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxws + + + org.apache.cxf + cxf-rt-frontend-jaxrs + + + org.apache.cxf + cxf-rt-transports-http + + + + org.apache.httpcomponents + httpasyncclient + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-jaxrs + + + javax + javaee-web-api + + + javax.ws.rs + jsr311-api + + + commons-httpclient.wso2 + commons-httpclient + + + org.wso2.carbon + org.wso2.carbon.utils + + + org.bouncycastle.wso2 + bcprov-jdk15on + + + org.wso2.carbon + org.wso2.carbon.user.api + + + org.wso2.carbon + org.wso2.carbon.queuing + + + org.wso2.carbon + org.wso2.carbon.base + + + org.apache.axis2.wso2 + axis2 + + + org.igniterealtime.smack.wso2 + smack + + + org.igniterealtime.smack.wso2 + smackx + + + jaxen + jaxen + + + commons-fileupload.wso2 + commons-fileupload + + + org.apache.ant.wso2 + ant + + + org.apache.ant.wso2 + ant + + + commons-httpclient.wso2 + commons-httpclient + + + org.eclipse.equinox + javax.servlet + + + org.wso2.carbon + org.wso2.carbon.registry.api + + + + + commons-codec + commons-codec + + + commons-io + commons-io + + + + org.igniterealtime.smack.wso2 + smack + + + org.igniterealtime.smack.wso2 + smackx + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/ManagerService.java b/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/ManagerService.java new file mode 100644 index 00000000..9c4cc572 --- /dev/null +++ b/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/ManagerService.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.manager.api; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.homeautomation.firealarm.manager.api.util.APIUtil; +import org.homeautomation.firealarm.manager.api.util.ResponsePayload; +import org.homeautomation.firealarm.plugin.constants.DeviceTypeConstants; +import org.wso2.carbon.apimgt.annotations.device.DeviceType; +import org.wso2.carbon.apimgt.webapp.publisher.KeyGenerationUtil; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; +import org.wso2.carbon.device.mgt.iot.apimgt.AccessTokenInfo; +import org.wso2.carbon.device.mgt.iot.apimgt.TokenClient; +import org.wso2.carbon.device.mgt.iot.exception.AccessTokenException; +import org.wso2.carbon.device.mgt.iot.exception.DeviceControllerException; +import org.wso2.carbon.device.mgt.iot.util.ZipArchive; +import org.wso2.carbon.device.mgt.iot.util.ZipUtil; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +@SuppressWarnings("NonJaxWsWebServices") +@DeviceType(value = "firealarm") +public class ManagerService { + + private static Log log = LogFactory.getLog(ManagerService.class); + + @Context //injected response proxy supporting multiple thread + private HttpServletResponse response; + + /** + * Generate UUID + * + * @return generated UUID + */ + private static String shortUUID() { + UUID uuid = UUID.randomUUID(); + long l = ByteBuffer.wrap(uuid.toString().getBytes(StandardCharsets.UTF_8)).getLong(); + return Long.toString(l, Character.MAX_RADIX); + } + + /** + * Register new device into IoT Server + * + * @param deviceId unique identifier for device + * @param name name of new device + * @return registration status + */ + @Path("manager/device/register") + @PUT + public boolean register(@QueryParam("deviceId") String deviceId, + @QueryParam("name") String name) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DeviceTypeConstants.DEVICE_TYPE); + try { + if (APIUtil.getDeviceManagementService().isEnrolled(deviceIdentifier)) { + response.setStatus(Response.Status.CONFLICT.getStatusCode()); + return false; + } + + String owner = APIUtil.getAuthenticatedUser(); + Device device = new Device(); + device.setDeviceIdentifier(deviceId); + EnrolmentInfo enrolmentInfo = new EnrolmentInfo(); + enrolmentInfo.setDateOfEnrolment(new Date().getTime()); + enrolmentInfo.setDateOfLastUpdate(new Date().getTime()); + enrolmentInfo.setStatus(EnrolmentInfo.Status.ACTIVE); + enrolmentInfo.setOwnership(EnrolmentInfo.OwnerShip.BYOD); + device.setName(name); + device.setType(DeviceTypeConstants.DEVICE_TYPE); + enrolmentInfo.setOwner(owner); + device.setEnrolmentInfo(enrolmentInfo); + KeyGenerationUtil.createApplicationKeys(DeviceTypeConstants.DEVICE_TYPE); + TokenClient accessTokenClient = new TokenClient(DeviceTypeConstants.DEVICE_TYPE); + AccessTokenInfo accessTokenInfo = accessTokenClient.getAccessToken(owner, deviceId); + + //create token + String accessToken = accessTokenInfo.getAccess_token(); + String refreshToken = accessTokenInfo.getRefresh_token(); + List properties = new ArrayList<>(); + Device.Property accessTokenProperty = new Device.Property(); + accessTokenProperty.setName("accessToken"); + accessTokenProperty.setValue(accessToken); + Device.Property refreshTokenProperty = new Device.Property(); + refreshTokenProperty.setName("refreshToken"); + refreshTokenProperty.setValue(refreshToken); + properties.add(accessTokenProperty); + properties.add(refreshTokenProperty); + device.setProperties(properties); + + boolean added = APIUtil.getDeviceManagementService().enrollDevice(device); + if (added) { + response.setStatus(Response.Status.OK.getStatusCode()); + } else { + response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode()); + } + return added; + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error(e.getErrorMessage(), e); + return false; + } catch (AccessTokenException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + log.error("Unable to obtain access token", e); + return false; + } + } + + /** + * Remove installed device + * + * @param deviceId unique identifier for device + * @param response to request + */ + @Path("manager/device/remove/{device_id}") + @DELETE + public void removeDevice(@PathParam("device_id") String deviceId, + @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DeviceTypeConstants.DEVICE_TYPE); + try { + boolean removed = APIUtil.getDeviceManagementService().disenrollDevice( + deviceIdentifier); + if (removed) { + response.setStatus(Response.Status.OK.getStatusCode()); + } else { + response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode()); + } + } catch (DeviceManagementException e) { + response.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + } + } + + /** + * Update device name + * + * @param deviceId unique identifier for device + * @param name new name of the device + * @param response to request + * @return update status + */ + @Path("manager/device/update/{device_id}") + @POST + public boolean updateDevice(@PathParam("device_id") String deviceId, + @QueryParam("name") String name, + @Context HttpServletResponse response) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DeviceTypeConstants.DEVICE_TYPE); + try { + Device device = APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + device.setDeviceIdentifier(deviceId); + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.setName(name); + device.setType(DeviceTypeConstants.DEVICE_TYPE); + boolean updated = APIUtil.getDeviceManagementService().modifyEnrollment(device); + if (updated) { + response.setStatus(Response.Status.OK.getStatusCode()); + } else { + response.setStatus(Response.Status.NOT_ACCEPTABLE.getStatusCode()); + } + return updated; + } catch (DeviceManagementException e) { + log.error(e.getErrorMessage()); + return false; + } + } + + /** + * Get device information + * + * @param deviceId unique identifier for device + * @return device + */ + @Path("manager/device/{device_id}") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Device getDevice(@PathParam("device_id") String deviceId) { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(DeviceTypeConstants.DEVICE_TYPE); + try { + return APIUtil.getDeviceManagementService().getDevice(deviceIdentifier); + } catch (DeviceManagementException ex) { + log.error("Error occurred while retrieving device with Id " + deviceId + "\n" + ex); + return null; + } + } + + /** + * This will download the agent for given device type + * + * @param deviceName name of the device which is to be created + * @param sketchType name of sketch type + * @return agent archive + */ + @Path("manager/device/{sketch_type}/download") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response downloadSketch(@QueryParam("deviceName") String deviceName, + @PathParam("sketch_type") String sketchType) { + try { + ZipArchive zipFile = createDownloadFile(APIUtil.getAuthenticatedUser(), deviceName, sketchType); + Response.ResponseBuilder response = Response.ok(FileUtils.readFileToByteArray(zipFile.getZipFile())); + response.type("application/zip"); + response.header("Content-Disposition", "attachment; filename=\"" + zipFile.getFileName() + "\""); + return response.build(); + } catch (IllegalArgumentException ex) { + return Response.status(400).entity(ex.getMessage()).build();//bad request + } catch (DeviceManagementException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (AccessTokenException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (DeviceControllerException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } catch (IOException ex) { + return Response.status(500).entity(ex.getMessage()).build(); + } + } + + /** + * This will give link to generated agent + * + * @param deviceName name of the device which is to be created + * @param sketchType name of sketch type + * @return link to generated agent + */ + @Path("manager/device/{sketch_type}/generate_link") + @GET + public Response generateSketchLink(@QueryParam("deviceName") String deviceName, + @PathParam("sketch_type") String sketchType) { + + try { + ZipArchive zipFile = createDownloadFile(APIUtil.getAuthenticatedUser(), deviceName, sketchType); + ResponsePayload responsePayload = new ResponsePayload(); + responsePayload.setStatusCode(HttpStatus.SC_OK); + responsePayload.setMessageFromServer("Sending Requested sketch by type: " + sketchType + + " and id: " + zipFile.getDeviceId() + "."); + responsePayload.setResponseContent(zipFile.getDeviceId()); + return Response.status(HttpStatus.SC_OK).entity(responsePayload).build(); + } catch (IllegalArgumentException ex) { + return Response.status(HttpStatus.SC_BAD_REQUEST).entity(ex.getMessage()).build(); + } catch (DeviceManagementException ex) { + log.error("Error occurred while creating device with name " + deviceName + "\n", ex); + return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); + } catch (AccessTokenException ex) { + log.error(ex.getMessage(), ex); + return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); + } catch (DeviceControllerException ex) { + log.error(ex.getMessage(), ex); + return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); + } + } + + /** + * Make zip file which include all the agent source codes and configuration file + * + * @param owner owner of the device + * @param deviceName name of device + * @param sketchType name of sketch type + * @return zip archive file + * @throws DeviceManagementException + * @throws AccessTokenException + * @throws DeviceControllerException + */ + private ZipArchive createDownloadFile(String owner, String deviceName, String sketchType) + throws DeviceManagementException, AccessTokenException, DeviceControllerException { + if (owner == null) { + throw new IllegalArgumentException("Error on createDownloadFile() Owner is null!"); + } + //create new device id + String deviceId = shortUUID(); + KeyGenerationUtil.createApplicationKeys(DeviceTypeConstants.DEVICE_TYPE); + TokenClient accessTokenClient = new TokenClient(DeviceTypeConstants.DEVICE_TYPE); + AccessTokenInfo accessTokenInfo = accessTokenClient.getAccessToken(owner, deviceId); + //create token + String accessToken = accessTokenInfo.getAccess_token(); + String refreshToken = accessTokenInfo.getRefresh_token(); + //adding registering data + boolean status; + //Register the device with CDMF + status = register(deviceId, deviceName); + if (!status) { + String msg = "Error occurred while registering the device with " + "id: " + deviceId + " owner:" + owner; + throw new DeviceManagementException(msg); + } + ZipUtil ziputil = new ZipUtil(); + ZipArchive zipFile = ziputil.createZipFile(owner, APIUtil.getTenantDomainOfUser(), sketchType, deviceId, deviceName, accessToken, + refreshToken); + zipFile.setDeviceId(deviceId); + return zipFile; + } + +} diff --git a/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/util/APIUtil.java b/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/util/APIUtil.java new file mode 100644 index 00000000..c3699691 --- /dev/null +++ b/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/util/APIUtil.java @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except +* in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +package org.homeautomation.firealarm.manager.api.util; + +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; + +/** + * This class provides utility functions used by REST-API. + */ +public class APIUtil { + + public static String getAuthenticatedUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + String username = threadLocalCarbonContext.getUsername(); + String tenantDomain = threadLocalCarbonContext.getTenantDomain(); + if (username.endsWith(tenantDomain)) { + return username.substring(0, username.lastIndexOf("@")); + } + return username; + } + + public static String getTenantDomainOfUser() { + PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + return threadLocalCarbonContext.getTenantDomain(); + } + + public static DeviceManagementProviderService getDeviceManagementService() { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + DeviceManagementProviderService deviceManagementProviderService = + (DeviceManagementProviderService) ctx.getOSGiService(DeviceManagementProviderService.class, null); + if (deviceManagementProviderService == null) { + String msg = "Device Management service has not initialized."; + throw new IllegalStateException(msg); + } + return deviceManagementProviderService; + } +} diff --git a/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/util/ResponsePayload.java b/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/util/ResponsePayload.java new file mode 100644 index 00000000..684e9374 --- /dev/null +++ b/modules/samples/firealarm/component/manager/src/main/java/org/homeautomation/firealarm/manager/api/util/ResponsePayload.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.manager.api.util; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class ResponsePayload { + + private int statusCode; + private String messageFromServer; + private Object responseContent; + + public static ResponsePayload.ResponsePayloadBuilder statusCode(int statusCode) { + ResponsePayload message = new ResponsePayload(); + return message.getBuilder().statusCode(statusCode); + } + + public static ResponsePayload.ResponsePayloadBuilder messageFromServer( + String messageFromServer) { + ResponsePayload message = new ResponsePayload(); + return message.getBuilder().messageFromServer(messageFromServer); + } + + public static ResponsePayload.ResponsePayloadBuilder responseContent(String responseContent) { + ResponsePayload message = new ResponsePayload(); + return message.getBuilder().responseContent(responseContent); + } + + @XmlElement + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + @XmlElement + public String getMessageFromServer() { + return messageFromServer; + } + + public void setMessageFromServer(String messageFromServer) { + this.messageFromServer = messageFromServer; + } + + @XmlElement + public Object getResponseContent() { + return responseContent; + } + + public void setResponseContent(Object responseContent) { + this.responseContent = responseContent; + } + + private ResponsePayload.ResponsePayloadBuilder getBuilder() { + return new ResponsePayload.ResponsePayloadBuilder(); + } + + public class ResponsePayloadBuilder { + + private int statusCode; + private String messageFromServer; + private Object responseContent; + + public ResponsePayloadBuilder statusCode(int statusCode) { + this.statusCode = statusCode; + return this; + } + + public ResponsePayloadBuilder messageFromServer(String messageFromServer) { + this.messageFromServer = messageFromServer; + return this; + } + + public ResponsePayloadBuilder responseContent(String responseContent) { + this.responseContent = responseContent; + return this; + } + + public ResponsePayload build() { + ResponsePayload payload = new ResponsePayload(); + payload.setStatusCode(statusCode); + payload.setMessageFromServer(messageFromServer); + payload.setResponseContent(responseContent); + return payload; + } + } + +} diff --git a/modules/samples/firealarm/component/manager/src/main/webapp/META-INF/permissions.xml b/modules/samples/firealarm/component/manager/src/main/webapp/META-INF/permissions.xml new file mode 100644 index 00000000..a98f6a8e --- /dev/null +++ b/modules/samples/firealarm/component/manager/src/main/webapp/META-INF/permissions.xml @@ -0,0 +1,73 @@ + + + + + + + + + + Get device + /device-mgt/user/devices/list + /manager/device/* + GET + emm_admin,emm_user + + + Add device + /device-mgt/user/devices/add + /manager/device/register + PUT + emm_admin,emm_user + + + Download device + /device-mgt/user/devices/add + /manager/device/firealarm/download + GET + emm_admin,emm_user + + + Generate link to download + /device-mgt/user/devices/add + /manager/device/firealarm/generate_link + GET + emm_admin,emm_user + + + Update device + /device-mgt/user/devices/update + /manager/device/update/* + POST + emm_admin,emm_user + + + Remove device + /device-mgt/user/devices/remove + /manager/device/remove/* + DELETE + emm_admin,emm_user + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/manager/src/main/webapp/META-INF/webapp-classloading.xml b/modules/samples/firealarm/component/manager/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 00000000..b410b426 --- /dev/null +++ b/modules/samples/firealarm/component/manager/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,35 @@ + + + + + + + + + false + + + CXF,Carbon + diff --git a/modules/samples/firealarm/component/manager/src/main/webapp/WEB-INF/cxf-servlet.xml b/modules/samples/firealarm/component/manager/src/main/webapp/WEB-INF/cxf-servlet.xml new file mode 100644 index 00000000..854b0248 --- /dev/null +++ b/modules/samples/firealarm/component/manager/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + diff --git a/modules/samples/firealarm/component/manager/src/main/webapp/WEB-INF/web.xml b/modules/samples/firealarm/component/manager/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..a5f0c0c6 --- /dev/null +++ b/modules/samples/firealarm/component/manager/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,68 @@ + + + + + + Firealarm-Webapp-Manager + + JAX-WS/JAX-RS Endpoint + JAX-WS/JAX-RS Servlet + CXFServlet + + org.apache.cxf.transport.servlet.CXFServlet + + 1 + + + CXFServlet + /* + + + isAdminService + false + + + doAuthentication + true + + + + managed-api-enabled + false + + + managed-api-owner + admin + + + managed-api-context-template + /firealarm/{version} + + + managed-api-application + firealarm + + + managed-api-isSecured + true + + diff --git a/modules/samples/firealarm/component/plugin/pom.xml b/modules/samples/firealarm/component/plugin/pom.xml new file mode 100644 index 00000000..492d5a4e --- /dev/null +++ b/modules/samples/firealarm/component/plugin/pom.xml @@ -0,0 +1,114 @@ + + + + + + + org.homeautomation + firealarm-component + 1.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + 1.0.0-SNAPSHOT + ${groupId}.firealarm.plugin + bundle + ${groupId}.firealarm.plugin + http://wso2.org + + + + org.apache.felix + maven-scr-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + UTF-8 + ${wso2.maven.compiler.source} + ${wso2.maven.compiler.target} + + + + org.apache.felix + maven-bundle-plugin + ${org.apache.felix.version} + true + + + ${groupId}.firealarm.plugin + ${groupId}.firealarm.plugin + 1.0.0-SNAPSHOT + IoT Server Impl Bundle + ${project-base-package}.plugin.internal + + org.osgi.framework, + org.osgi.service.component, + org.apache.commons.logging, + javax.naming, + javax.sql, + javax.xml.parsers, + javax.net, + javax.net.ssl, + org.w3c.dom, + org.wso2.carbon.device.mgt.common.*, + org.wso2.carbon.context.*, + org.wso2.carbon.ndatasource.core, + org.wso2.carbon.device.mgt.iot.*, + + + !${project-base-package}.plugin.internal, + ${project-base-package}.plugin.* + + + + + + + + + org.eclipse.osgi + org.eclipse.osgi + + + org.eclipse.osgi + org.eclipse.osgi.services + + + org.wso2.carbon + org.wso2.carbon.logging + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + + + org.wso2.carbon + org.wso2.carbon.ndatasource.core + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/constants/DeviceTypeConstants.java b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/constants/DeviceTypeConstants.java new file mode 100644 index 00000000..48db43cf --- /dev/null +++ b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/constants/DeviceTypeConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.plugin.constants; + +public class DeviceTypeConstants { + + public final static String DEVICE_TYPE = "firealarm"; + public final static String DEVICE_PLUGIN_DEVICE_NAME = "DEVICE_NAME"; + public final static String DEVICE_PLUGIN_DEVICE_ID = "firealarm_DEVICE_ID"; + public final static String SENSOR_TEMPERATURE = "temperature"; + public final static String SENSOR_HUMIDITY = "humidity"; + public static final String DATA_SOURCE_NAME = "jdbc/firealarmDM_DB"; + + public final static String DEVICE_PLUGIN_PROPERTY_ACCESS_TOKEN = "accessToken"; + public final static String DEVICE_PLUGIN_PROPERTY_REFRESH_TOKEN = "refreshToken"; + +} diff --git a/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/exception/FirealarmPluginException.java b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/exception/FirealarmPluginException.java new file mode 100644 index 00000000..60b41c98 --- /dev/null +++ b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/exception/FirealarmPluginException.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.plugin.exception; + +public class FirealarmPluginException extends Exception { + + private String errorMessage; + + public FirealarmPluginException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public FirealarmPluginException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public FirealarmPluginException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public FirealarmPluginException() { + super(); + } + + public FirealarmPluginException(Throwable cause) { + super(cause); + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + +} diff --git a/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/DeviceTypeManager.java b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/DeviceTypeManager.java new file mode 100644 index 00000000..63063cc6 --- /dev/null +++ b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/DeviceTypeManager.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.plugin.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.homeautomation.firealarm.plugin.exception.FirealarmPluginException; +import org.homeautomation.firealarm.plugin.impl.dao.DeviceTypeDAO; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceManager; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.common.configuration.mgt.TenantConfiguration; +import org.wso2.carbon.device.mgt.common.license.mgt.License; +import org.wso2.carbon.device.mgt.common.license.mgt.LicenseManagementException; + +import java.util.List; + +/** + * + */ +public class DeviceTypeManager implements DeviceManager { + + private static final Log log = LogFactory.getLog(DeviceTypeManager.class); + + private static final DeviceTypeDAO connectedCupDAO = new DeviceTypeDAO(); + + @Override + public FeatureManager getFeatureManager() { + return null; + } + + @Override + public boolean saveConfiguration(TenantConfiguration tenantConfiguration) + throws DeviceManagementException { + //TODO implement this + return false; + } + + @Override + public TenantConfiguration getConfiguration() throws DeviceManagementException { + //TODO implement this + return null; + } + + @Override + public boolean enrollDevice(Device device) throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug("Enrolling a new Connected Cup device : " + device.getDeviceIdentifier()); + } + DeviceTypeDAO.beginTransaction(); + status = connectedCupDAO.getConnectedCupDeviceDAO().addDevice(device); + DeviceTypeDAO.commitTransaction(); + } catch (FirealarmPluginException e) { + try { + DeviceTypeDAO.rollbackTransaction(); + } catch (FirealarmPluginException iotDAOEx) { + String msg = "Error occurred while roll back the device enrol transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while enrolling the Connected Cup device : " + device.getDeviceIdentifier(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public boolean modifyEnrollment(Device device) throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug("Modifying the Connected Cup device enrollment data"); + } + DeviceTypeDAO.beginTransaction(); + status = connectedCupDAO.getConnectedCupDeviceDAO().updateDevice(device); + DeviceTypeDAO.commitTransaction(); + } catch (FirealarmPluginException e) { + try { + DeviceTypeDAO.rollbackTransaction(); + } catch (FirealarmPluginException iotDAOEx) { + String msg = "Error occurred while roll back the update device transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while updating the enrollment of the Connected Cup device : " + + device.getDeviceIdentifier(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public boolean disenrollDevice(DeviceIdentifier deviceId) throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug("Dis-enrolling Connected Cup device : " + deviceId); + } + DeviceTypeDAO.beginTransaction(); + status = connectedCupDAO.getConnectedCupDeviceDAO().deleteDevice(deviceId.getId()); + DeviceTypeDAO.commitTransaction(); + } catch (FirealarmPluginException e) { + try { + DeviceTypeDAO.rollbackTransaction(); + } catch (FirealarmPluginException iotDAOEx) { + String msg = "Error occurred while roll back the device dis enrol transaction :" + deviceId.toString(); + log.warn(msg, iotDAOEx); + } + String msg = "Error while removing the Connected Cup device : " + deviceId.getId(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public boolean isEnrolled(DeviceIdentifier deviceId) throws DeviceManagementException { + boolean isEnrolled = false; + try { + if (log.isDebugEnabled()) { + log.debug("Checking the enrollment of Connected Cup device : " + deviceId.getId()); + } + Device iotDevice = connectedCupDAO.getConnectedCupDeviceDAO().getDevice(deviceId.getId()); + if (iotDevice != null) { + isEnrolled = true; + } + } catch (FirealarmPluginException e) { + String msg = "Error while checking the enrollment status of Connected Cup device : " + + deviceId.getId(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return isEnrolled; + } + + @Override + public boolean isActive(DeviceIdentifier deviceId) throws DeviceManagementException { + return true; + } + + @Override + public boolean setActive(DeviceIdentifier deviceId, boolean status) + throws DeviceManagementException { + return true; + } + + @Override + public Device getDevice(DeviceIdentifier deviceId) throws DeviceManagementException { + Device device; + try { + if (log.isDebugEnabled()) { + log.debug("Getting the details of Connected Cup device : " + deviceId.getId()); + } + device = connectedCupDAO.getConnectedCupDeviceDAO().getDevice(deviceId.getId()); + + } catch (FirealarmPluginException e) { + String msg = "Error while fetching the Connected Cup device : " + deviceId.getId(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return device; + } + + @Override + public boolean setOwnership(DeviceIdentifier deviceId, String ownershipType) + throws DeviceManagementException { + return true; + } + + public boolean isClaimable(DeviceIdentifier deviceIdentifier) throws DeviceManagementException { + return false; + } + + @Override + public boolean setStatus(DeviceIdentifier deviceId, String currentOwner, + EnrolmentInfo.Status status) throws DeviceManagementException { + return false; + } + + @Override + public License getLicense(String s) throws LicenseManagementException { + return null; + } + + @Override + public void addLicense(License license) throws LicenseManagementException { + + } + + @Override + public boolean requireDeviceAuthorization() { + return false; + } + + @Override + public boolean updateDeviceInfo(DeviceIdentifier deviceIdentifier, Device device) + throws DeviceManagementException { + boolean status; + try { + if (log.isDebugEnabled()) { + log.debug( + "updating the details of Connected Cup device : " + deviceIdentifier); + } + DeviceTypeDAO.beginTransaction(); + status = connectedCupDAO.getConnectedCupDeviceDAO().updateDevice(device); + DeviceTypeDAO.commitTransaction(); + } catch (FirealarmPluginException e) { + try { + DeviceTypeDAO.rollbackTransaction(); + } catch (FirealarmPluginException iotDAOEx) { + String msg = "Error occurred while roll back the update device info transaction :" + device.toString(); + log.warn(msg, iotDAOEx); + } + String msg = + "Error while updating the Connected Cup device : " + deviceIdentifier; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return status; + } + + @Override + public List getAllDevices() throws DeviceManagementException { + List devices; + try { + if (log.isDebugEnabled()) { + log.debug("Fetching the details of all Connected Cup devices"); + } + devices = connectedCupDAO.getConnectedCupDeviceDAO().getAllDevices(); + } catch (FirealarmPluginException e) { + String msg = "Error while fetching all Connected Cup devices."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return devices; + } + +} \ No newline at end of file diff --git a/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/DeviceTypeManagerService.java b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/DeviceTypeManagerService.java new file mode 100644 index 00000000..86d7351b --- /dev/null +++ b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/DeviceTypeManagerService.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.plugin.impl; + +import org.homeautomation.firealarm.plugin.constants.DeviceTypeConstants; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceManager; +import org.wso2.carbon.device.mgt.common.app.mgt.Application; +import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException; +import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManager; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; + +import java.util.List; + +public class DeviceTypeManagerService implements DeviceManagementService { + private DeviceManager deviceManager; + + @Override + public String getType() { + return DeviceTypeConstants.DEVICE_TYPE; + } + + + @Override + public String getProviderTenantDomain() { + return "carbon.super"; + } + + @Override + public boolean isSharedWithAllTenants() { + return true; + } + + @Override + public String[] getSharedTenantsDomain() { + return new String[0]; + } + + @Override + public void init() throws DeviceManagementException { + this.deviceManager = new DeviceTypeManager(); + } + + @Override + public DeviceManager getDeviceManager() { + return deviceManager; + } + + @Override + public ApplicationManager getApplicationManager() { + return null; + } + + @Override + public void notifyOperationToDevices(Operation operation, List deviceIds) + throws DeviceManagementException { + + } + + @Override + public Application[] getApplications(String domain, int pageNumber, int size) + throws ApplicationManagementException { + return new Application[0]; + } + + @Override + public void updateApplicationStatus(DeviceIdentifier deviceId, Application application, + String status) throws ApplicationManagementException { + + } + + @Override + public String getApplicationStatus(DeviceIdentifier deviceId, Application application) + throws ApplicationManagementException { + return null; + } + + @Override + public void installApplicationForDevices(Operation operation, + List deviceIdentifiers) + throws ApplicationManagementException { + + } + + @Override + public void installApplicationForUsers(Operation operation, List userNameList) + throws ApplicationManagementException { + + } + + @Override + public void installApplicationForUserRoles(Operation operation, List userRoleList) + throws ApplicationManagementException { + + } +} diff --git a/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/DeviceTypeDAO.java b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/DeviceTypeDAO.java new file mode 100644 index 00000000..e78b3ab0 --- /dev/null +++ b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/DeviceTypeDAO.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.plugin.impl.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.homeautomation.firealarm.plugin.constants.DeviceTypeConstants; +import org.homeautomation.firealarm.plugin.exception.FirealarmPluginException; +import org.homeautomation.firealarm.plugin.impl.dao.impl.DeviceTypeDAOImpl; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +public class DeviceTypeDAO { + + private static final Log log = LogFactory.getLog(DeviceTypeDAO.class); + private static DataSource dataSource; + private static ThreadLocal currentConnection = new ThreadLocal<>(); + + public DeviceTypeDAO() { + initConnectedCupDAO(); + } + + public static void initConnectedCupDAO() { + try { + Context ctx = new InitialContext(); + dataSource = (DataSource) ctx.lookup(DeviceTypeConstants.DATA_SOURCE_NAME); + } catch (NamingException e) { + log.error("Error while looking up the data source: " + + DeviceTypeConstants.DATA_SOURCE_NAME); + } + + } + + public static void beginTransaction() throws FirealarmPluginException { + try { + Connection conn = dataSource.getConnection(); + conn.setAutoCommit(false); + currentConnection.set(conn); + } catch (SQLException e) { + throw new FirealarmPluginException( + "Error occurred while retrieving datasource connection", e); + } + } + + public static Connection getConnection() throws FirealarmPluginException { + if (currentConnection.get() == null) { + try { + currentConnection.set(dataSource.getConnection()); + } catch (SQLException e) { + throw new FirealarmPluginException( + "Error occurred while retrieving data source connection", e); + } + } + return currentConnection.get(); + } + + public static void commitTransaction() throws FirealarmPluginException { + try { + Connection conn = currentConnection.get(); + if (conn != null) { + conn.commit(); + } else { + if (log.isDebugEnabled()) { + log.debug("Datasource connection associated with the current thread is null, " + + "hence commit has not been attempted"); + } + } + } catch (SQLException e) { + throw new FirealarmPluginException( + "Error occurred while committing the transaction", e); + } finally { + closeConnection(); + } + } + + public static void closeConnection() throws FirealarmPluginException { + + Connection con = currentConnection.get(); + if (con != null) { + try { + con.close(); + } catch (SQLException e) { + log.error("Error occurred while close the connection"); + } + } + currentConnection.remove(); + } + + public static void rollbackTransaction() throws FirealarmPluginException { + try { + Connection conn = currentConnection.get(); + if (conn != null) { + conn.rollback(); + } else { + if (log.isDebugEnabled()) { + log.debug( + "Datasource connection associated with the current thread is null, " + + "hence rollback has not been attempted"); + } + } + } catch (SQLException e) { + throw new FirealarmPluginException("Error occurred while rollback the transaction", e); + } finally { + closeConnection(); + } + } + + public DeviceTypeDAOImpl getConnectedCupDeviceDAO() { + return new DeviceTypeDAOImpl(); + } +} diff --git a/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/impl/DeviceTypeDAOImpl.java b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/impl/DeviceTypeDAOImpl.java new file mode 100644 index 00000000..e9b09baa --- /dev/null +++ b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/impl/DeviceTypeDAOImpl.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.plugin.impl.dao.impl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.homeautomation.firealarm.plugin.constants.DeviceTypeConstants; +import org.homeautomation.firealarm.plugin.exception.FirealarmPluginException; +import org.homeautomation.firealarm.plugin.impl.dao.DeviceTypeDAO; +import org.homeautomation.firealarm.plugin.impl.dao.util.DeviceTypeUtils; +import org.wso2.carbon.device.mgt.common.Device; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Device Dao for Firealarm Devices. + */ +public class DeviceTypeDAOImpl { + + private static final Log log = LogFactory.getLog(DeviceTypeDAOImpl.class); + + public Device getDevice(String deviceId) throws FirealarmPluginException { + Connection conn; + PreparedStatement stmt = null; + Device connectedCupDevice = null; + ResultSet resultSet = null; + try { + conn = DeviceTypeDAO.getConnection(); + String selectDBQuery = + "SELECT firealarm_DEVICE_ID, DEVICE_NAME, ACCESS_TOKEN, REFRESH_TOKEN" + + " FROM firealarm_DEVICE WHERE firealarm_DEVICE_ID = ?"; + stmt = conn.prepareStatement(selectDBQuery); + stmt.setString(1, deviceId); + resultSet = stmt.executeQuery(); + + if (resultSet.next()) { + connectedCupDevice = new Device(); + connectedCupDevice.setName(resultSet.getString( + DeviceTypeConstants.DEVICE_PLUGIN_DEVICE_NAME)); + List propertyList = new ArrayList<>(); + propertyList.add(DeviceTypeUtils.getProperty( + DeviceTypeConstants.DEVICE_PLUGIN_PROPERTY_ACCESS_TOKEN, + resultSet.getString("ACCESS_TOKEN"))); + propertyList.add(DeviceTypeUtils.getProperty( + DeviceTypeConstants.DEVICE_PLUGIN_PROPERTY_REFRESH_TOKEN, + resultSet.getString("REFRESH_TOKEN"))); + connectedCupDevice.setProperties(propertyList); + + if (log.isDebugEnabled()) { + log.debug("Firealarm service " + deviceId + " data has been fetched from" + + "Firealarm database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while fetching Firealarm device : '" + deviceId + "'"; + log.error(msg, e); + throw new FirealarmPluginException(msg, e); + } finally { + DeviceTypeUtils.cleanupResources(stmt, resultSet); + DeviceTypeDAO.closeConnection(); + } + return connectedCupDevice; + } + + public boolean addDevice(Device connectedCupDevice) throws FirealarmPluginException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = DeviceTypeDAO.getConnection(); + String createDBQuery = + "INSERT INTO firealarm_DEVICE(firealarm_DEVICE_ID, DEVICE_NAME, " + + "ACCESS_TOKEN, REFRESH_TOKEN) VALUES (?, ?, ?, ?)"; + + stmt = conn.prepareStatement(createDBQuery); + stmt.setString(1, connectedCupDevice.getDeviceIdentifier()); + stmt.setString(2, connectedCupDevice.getName()); + stmt.setString(3, DeviceTypeUtils.getDeviceProperty( + connectedCupDevice.getProperties(), + DeviceTypeConstants.DEVICE_PLUGIN_PROPERTY_ACCESS_TOKEN)); + stmt.setString(4, DeviceTypeUtils.getDeviceProperty( + connectedCupDevice.getProperties(), + DeviceTypeConstants.DEVICE_PLUGIN_PROPERTY_REFRESH_TOKEN)); + + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Connected Cup device " + connectedCupDevice.getDeviceIdentifier() + + " data has been added to the Connected Cup database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while adding the Connected Cup device '" + + connectedCupDevice.getDeviceIdentifier() + "' to the Connected Cup db."; + throw new FirealarmPluginException(msg, e); + } finally { + DeviceTypeUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean updateDevice(Device connectedCupDevice) throws FirealarmPluginException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = DeviceTypeDAO.getConnection(); + String updateDBQuery = + "UPDATE firealarm_DEVICE SET DEVICE_NAME = ?, ACCESS_TOKEN=?, " + + "REFRESH_TOKEN=? WHERE firealarm_DEVICE_ID = ?"; + + stmt = conn.prepareStatement(updateDBQuery); + + if (connectedCupDevice.getProperties() == null) { + connectedCupDevice.setProperties(new ArrayList()); + } + stmt.setString(1, connectedCupDevice.getName()); + stmt.setString(2, DeviceTypeUtils.getDeviceProperty( + connectedCupDevice.getProperties(), + DeviceTypeConstants.DEVICE_PLUGIN_PROPERTY_ACCESS_TOKEN)); + stmt.setString(3, DeviceTypeUtils.getDeviceProperty( + connectedCupDevice.getProperties(), + DeviceTypeConstants.DEVICE_PLUGIN_PROPERTY_REFRESH_TOKEN)); + stmt.setString(4, connectedCupDevice.getDeviceIdentifier()); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Connected Cup device " + connectedCupDevice.getDeviceIdentifier() + + " data has been modified."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while modifying the Connected Cup device '" + + connectedCupDevice.getDeviceIdentifier() + "' data."; + log.error(msg, e); + throw new FirealarmPluginException(msg, e); + } finally { + DeviceTypeUtils.cleanupResources(stmt, null); + } + return status; + } + + public boolean deleteDevice(String deviceId) throws FirealarmPluginException { + boolean status = false; + Connection conn; + PreparedStatement stmt = null; + try { + conn = DeviceTypeDAO.getConnection(); + String deleteDBQuery = + "DELETE FROM firealarm_DEVICE WHERE firealarm_DEVICE_ID = ?"; + stmt = conn.prepareStatement(deleteDBQuery); + stmt.setString(1, deviceId); + int rows = stmt.executeUpdate(); + if (rows > 0) { + status = true; + if (log.isDebugEnabled()) { + log.debug("Connected Cup device " + deviceId + " data has deleted" + + " from the Connected Cup database."); + } + } + } catch (SQLException e) { + String msg = "Error occurred while deleting Connected Cup device " + deviceId; + log.error(msg, e); + throw new FirealarmPluginException(msg, e); + } finally { + DeviceTypeUtils.cleanupResources(stmt, null); + } + return status; + } + + public List getAllDevices() throws FirealarmPluginException { + Connection conn; + PreparedStatement stmt = null; + ResultSet resultSet = null; + Device connectedCupDevice; + List iotDevices = new ArrayList<>(); + + try { + conn = DeviceTypeDAO.getConnection(); + String selectDBQuery = + "SELECT firealarm_DEVICE_ID, DEVICE_NAME, ACCESS_TOKEN, REFRESH_TOKEN" + + "FROM firealarm_DEVICE"; + stmt = conn.prepareStatement(selectDBQuery); + resultSet = stmt.executeQuery(); + while (resultSet.next()) { + connectedCupDevice = new Device(); + connectedCupDevice.setDeviceIdentifier(resultSet.getString( + DeviceTypeConstants.DEVICE_PLUGIN_DEVICE_ID)); + connectedCupDevice.setName(resultSet.getString( + DeviceTypeConstants.DEVICE_PLUGIN_DEVICE_NAME)); + + List propertyList = new ArrayList<>(); + propertyList.add(DeviceTypeUtils.getProperty( + DeviceTypeConstants.DEVICE_PLUGIN_PROPERTY_ACCESS_TOKEN, + resultSet.getString("ACCESS_TOKEN"))); + propertyList.add(DeviceTypeUtils.getProperty( + DeviceTypeConstants.DEVICE_PLUGIN_PROPERTY_REFRESH_TOKEN, + resultSet.getString("REFRESH_TOKEN"))); + connectedCupDevice.setProperties(propertyList); + } + if (log.isDebugEnabled()) { + log.debug("All Connected Cup device details have fetched from Connected Cup database" + + "."); + } + return iotDevices; + } catch (SQLException e) { + String msg = "Error occurred while fetching all Connected Cup device data'"; + log.error(msg, e); + throw new FirealarmPluginException(msg, e); + } finally { + DeviceTypeUtils.cleanupResources(stmt, resultSet); + DeviceTypeDAO.closeConnection(); + } + } + +} diff --git a/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/util/DeviceTypeUtils.java b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/util/DeviceTypeUtils.java new file mode 100644 index 00000000..e8c5c6c9 --- /dev/null +++ b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/impl/dao/util/DeviceTypeUtils.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.plugin.impl.dao.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * Contains utility methods used by FireAlarm plugin. + */ +public class DeviceTypeUtils { + + private static Log log = LogFactory.getLog(DeviceTypeUtils.class); + + public static String getDeviceProperty(List deviceProperties, + String propertyKey) { + String deviceProperty = ""; + for (Device.Property property : deviceProperties) { + if (propertyKey.equals(property.getName())) { + deviceProperty = property.getValue(); + } + } + return deviceProperty; + } + + public static Device.Property getProperty(String property, String value) { + if (property != null) { + Device.Property prop = new Device.Property(); + prop.setName(property); + prop.setValue(value); + return prop; + } + return null; + } + + public static void cleanupResources(Connection conn, PreparedStatement stmt, ResultSet rs) { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + log.warn("Error occurred while closing result set", e); + } + } + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException e) { + log.warn("Error occurred while closing prepared statement", e); + } + } + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + log.warn("Error occurred while closing database connection", e); + } + } + } + + public static void cleanupResources(PreparedStatement stmt, ResultSet rs) { + cleanupResources(null, stmt, rs); + } + +} diff --git a/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/internal/ServiceComponent.java b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/internal/ServiceComponent.java new file mode 100644 index 00000000..d949e6a8 --- /dev/null +++ b/modules/samples/firealarm/component/plugin/src/main/java/org/homeautomation/firealarm/plugin/internal/ServiceComponent.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.homeautomation.firealarm.plugin.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.homeautomation.firealarm.plugin.impl.DeviceTypeManagerService; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.ComponentContext; +import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; + +/** + * @scr.component name="org.homeautomation.firealarm.plugin.internal.ServiceComponent" + * immediate="true" + */ + +public class ServiceComponent { + + private static final Log log = LogFactory.getLog(ServiceComponent.class); + private ServiceRegistration serviceRegistration; + + protected void activate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("Activating firealarm Management Service Component"); + } + try { + BundleContext bundleContext = ctx.getBundleContext(); + serviceRegistration = + bundleContext.registerService(DeviceManagementService.class.getName(), new + DeviceTypeManagerService(), null); + if (log.isDebugEnabled()) { + log.debug("firealarm Management Service Component has been successfully activated"); + } + } catch (Throwable e) { + log.error("Error occurred while activating Current Sensor Management Service Component", e); + } + } + + protected void deactivate(ComponentContext ctx) { + if (log.isDebugEnabled()) { + log.debug("De-activating firealarm Management Service Component"); + } + try { + if (serviceRegistration != null) { + serviceRegistration.unregister(); + } + if (log.isDebugEnabled()) { + log.debug("Current Sensor Management Service Component has been successfully de-activated"); + } + } catch (Throwable e) { + log.error("Error occurred while de-activating Iot Device Management bundle", e); + } + } + +} diff --git a/modules/samples/firealarm/component/pom.xml b/modules/samples/firealarm/component/pom.xml new file mode 100644 index 00000000..45d5e76c --- /dev/null +++ b/modules/samples/firealarm/component/pom.xml @@ -0,0 +1,268 @@ + + + + + + + org.homeautomation + firealarm + 1.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + 1.0.0-SNAPSHOT + firealarm-component + pom + + + + + org.apache.felix + maven-scr-plugin + ${maven-scr-plugin.version} + + + generate-scr-scrdescriptor + + scr + + + + + + + + + + + org.homeautomation + ${project-base-package}.plugin + 1.0.0-SNAPSHOT + provided + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.webapp.publisher + ${carbon.device.mgt.version} + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.apimgt.webapp.publisher_${carbon.device.mgt.jar.version}.jar + + + + org.wso2.carbon + org.wso2.carbon.ndatasource.core + ${carbon.kernel.version} + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.ndatasource.core_${carbon.kernel.version}.jar + + + + org.wso2.carbon.devicemgt-plugins + org.wso2.carbon.device.mgt.iot + ${carbon.iot.device.mgt.version} + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.device.mgt.iot_${carbon.iot.device.mgt.jar.version}.jar + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.core + ${carbon.device.mgt.version} + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.device.mgt.core_${carbon.device.mgt.jar.version}.jar + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.common + ${carbon.device.mgt.version} + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.device.mgt.common_${carbon.device.mgt.jar.version}.jar + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.certificate.mgt.core + ${carbon.device.mgt.version} + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.certificate.mgt.core_${carbon.device.mgt.jar.version}.jar + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.apimgt.annotations + ${carbon.device.mgt.version} + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.apimgt.annotations_${carbon.device.mgt.jar.version}.jar + + + + org.wso2.carbon.devicemgt + org.wso2.carbon.device.mgt.analytics + ${carbon.device.mgt.version} + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.device.mgt.analytics_${carbon.device.mgt.jar.version}.jar + + + + commons-httpclient.wso2 + commons-httpclient + ${commons-httpclient.orbit.version} + system + + ${basedir}/../../../../repository/components/plugins/commons-httpclient_3.1.0.wso2v2.jar + + + + commons-httpclient.wso2 + commons-httpclient + ${commons-httpclient.orbit.version} + system + + ${basedir}/../../../../repository/components/plugins/commons-httpclient_3.1.0.wso2v2.jar + + + + org.wso2.carbon + org.wso2.carbon.utils + ${carbon.kernel.version} + + + org.bouncycastle.wso2 + bcprov-jdk15on + + + org.wso2.carbon + org.wso2.carbon.user.api + + + org.wso2.carbon + org.wso2.carbon.queuing + + + org.wso2.carbon + org.wso2.carbon.base + + + org.apache.axis2.wso2 + axis2 + + + org.igniterealtime.smack.wso2 + smack + + + org.igniterealtime.smack.wso2 + smackx + + + jaxen + jaxen + + + commons-fileupload.wso2 + commons-fileupload + + + org.apache.ant.wso2 + ant + + + org.apache.ant.wso2 + ant + + + commons-httpclient.wso2 + commons-httpclient + + + org.eclipse.equinox + javax.servlet + + + org.wso2.carbon + org.wso2.carbon.registry.api + + + system + + ${basedir}/../../../../repository/components/plugins/org.wso2.carbon.utils_${carbon.kernel.version}.jar + + + + org.igniterealtime.smack.wso2 + smack + ${smack.wso2.version} + system + + ${basedir}/../../../../repository/components/plugins/smack_3.0.4.wso2v1.jar + + + + org.igniterealtime.smack.wso2 + smackx + ${smackx.wso2.version} + system + + ${basedir}/../../../../repository/components/plugins/smackx_3.0.4.wso2v1.jar + + + + org.json.wso2 + json + ${commons-json.version} + system + + ${basedir}/../../../../repository/components/plugins/json_2.0.0.wso2v1.jar + + + + commons-codec + commons-codec + 1.4.0.wso2v1 + system + + ${basedir}/../../../../repository/components/plugins/commons-codec_1.4.0.wso2v1.jar + + + + commons-io + commons-io + ${commons-io.version} + + + + + plugin + controller + manager + analytics + ui + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/pom.xml b/modules/samples/firealarm/component/ui/pom.xml new file mode 100644 index 00000000..3e6076d1 --- /dev/null +++ b/modules/samples/firealarm/component/ui/pom.xml @@ -0,0 +1,58 @@ + + + + + + + org.homeautomation + firealarm-component + 1.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + ${groupId}.firealarm.ui + ${groupId}.firealarm.ui + pom + + + + maven-assembly-plugin + ${maven-assembly-plugin.version} + + ${project.artifactId}-1.0.0-SNAPSHOT + false + + src/assembly/src.xml + + + + + create-archive + package + + single + + + + + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/assembly/src.xml b/modules/samples/firealarm/component/ui/src/assembly/src.xml new file mode 100644 index 00000000..3f381cbe --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/assembly/src.xml @@ -0,0 +1,38 @@ + + + + + + src + + zip + + false + ${basedir}/src + + + ${basedir}/src/main/resources/jaggeryapps/ + / + true + + + \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.hbs b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.hbs new file mode 100644 index 00000000..429c632a --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.hbs @@ -0,0 +1,130 @@ + +{{#zone "topCss"}} + +{{/zone}} + +{{#zone "device-thumbnail"}} + +{{/zone}} + +{{#zone "operation-status"}} + +{{/zone}} + +{{#zone "device-opetations"}} +
+ Operations +
+
+ {{unit "iot.unit.device.operation-bar" device=device}} +
+{{/zone}} + +{{#zone "device-detail-properties"}} +
+ +
+
+
+
Device Statistics
+ {{unit "iot.unit.device.stats" device=device}} +
+
+
Policy Compliance +
+
+
Policies
+
+ +
+
+ No policies found +
+
+
+
+
+ + + + + Add device specific policy +
+
+
Operations Log
+
+ +
+
+ Not available yet +
+
+
+
+
+
+
+
+{{/zone}} + + + diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.js b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.js new file mode 100644 index 00000000..9cf48f5e --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.js @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +function onRequest(context) { + + var log = new Log("device-view.js"); + var deviceType = context.uriParams.deviceType; + var deviceId = request.getParameter("id"); + + var getProperty = require("process").getProperty; + var port = getProperty("carbon.https.port"); + var host = getProperty("carbon.local.ip"); + var sessionId = session.getId(); + if (deviceType != null && deviceType != undefined && deviceId != null && deviceId != undefined) { + var deviceModule = require("/app/modules/device.js").deviceModule; + var device = deviceModule.viewDevice(deviceType, deviceId); + + if (device && device.status != "error") { + log.info(device); + return {"device": device, "port": port, "host": host, "sessionId": sessionId}; + } + } +} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.json b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.json new file mode 100644 index 00000000..688e9398 --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/device-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/public/images/current-sensor.png b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.device-view/public/images/current-sensor.png new file mode 100644 index 0000000000000000000000000000000000000000..b1ce4901bcbd4f7485f759d26d81520cd22623be GIT binary patch literal 38879 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 Jbz07G{{fC<96A61 literal 0 HcmV?d00001 diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-edit/policy-edit.hbs b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-edit/policy-edit.hbs new file mode 100644 index 00000000..cf80b006 --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-edit/policy-edit.hbs @@ -0,0 +1,18 @@ + +{{unit "iot.unit.policy.edit"}} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-edit/policy-edit.json b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-edit/policy-edit.json new file mode 100644 index 00000000..688e9398 --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-edit/policy-edit.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-view/policy-view.hbs b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-view/policy-view.hbs new file mode 100644 index 00000000..c2a4706b --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-view/policy-view.hbs @@ -0,0 +1,18 @@ + +{{unit "iot.unit.policy.view"}} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-view/policy-view.json b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-view/policy-view.json new file mode 100644 index 00000000..688e9398 --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-view/policy-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-wizard/policy-wizard.hbs b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-wizard/policy-wizard.hbs new file mode 100644 index 00000000..7b94f953 --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-wizard/policy-wizard.hbs @@ -0,0 +1,18 @@ + +{{unit "iot.unit.policy.wizard"}} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-wizard/policy-wizard.json b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-wizard/policy-wizard.json new file mode 100644 index 00000000..688e9398 --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.policy-wizard/policy-wizard.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/images/deviceType.png b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/images/deviceType.png new file mode 100644 index 0000000000000000000000000000000000000000..7c5808697e193b734c127fdf563f335ecd094bea GIT binary patch literal 28584 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 n9x@LG1!9c`wn52X|@D literal 0 HcmV?d00001 diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/images/schematicsGuide.png b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/images/schematicsGuide.png new file mode 100644 index 0000000000000000000000000000000000000000..db4d0adbb760dbff877884209c7f878083b1aa2f GIT binary patch literal 128984 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

(E+-BQ13%VTKFa^1 zqaSYI9r0q#9zF;(f*b?__+ydrM_Ppr$zDCyOK=3xF93NBL4f)++{&}6)1$hlu8z;> z-veV-gTQeBNP-7paYB~)2WQ8`2Mv?Sa%xNR++@#Ok2-+k5%{BgcFd2O%D-yeP>)1m z?0fC&5?{X8v~Kjs9-+ys-V;h-9v8s1C?MHq_sEXKb1Ednv=}t`(~{h%4J+JOp_yuk zRlA5{i9eL%ca>633hJyH#(RXzU@)D{|04Ihnn=PQ6@N_My>l0Q@AhxN%**$Sug-bD zi$eQ3S^C0%WA@IXnkt2{rVa)J-JfD|Pt)F zQ5XO2La*C{UZ*32f^N4X0gp=~k`x0SfiG4zxCr(LqOmt^=6dJu-vCaCg?J1tj}E7T z3H{M?+tc9U^@Vj-jX;m8Xv0MURq^ji0qsjg0H8%v(wjI=B(&u*i%eg9Y>I5Z*#&5c zkKGdbXDSP@LucCYo!7`3J2CE(2CH2 zbE&hOgS6p{Z#dw_1k@;=sj`^Ty9G!lD-=#NhpHYqV|MmY(ibInfLikc;*S*A>rQN| zg==nsAq`q~CGoOx-SRMHc}LpheWQR%j7S{=vGe~#1HS&g$G5OOe$N}g^aGHfhhFwL zZaP+>uwsbAP(f9G=o_Ho?>X9nJMMlGc0TwdJh^KZ%pZM4+%)?E1$EMG3L?ks)QBCH z^hsRT@3(*N;%irc3||Vr@!^ld=RWgMxZy*WU3dBV%Fb*Ddvn&olaLelN={GP>Lo{*L8VG#@XWT?}^)^C$^Wai0dQqvA2FDjWf{C*4w^bI0;)?9XP+yEc{-tmoOSBl}k`87J-e#Fg7s;Bcr2Gtqwz}RD{Ea4=YfQ z1o%a<9;GrwJ2PtM`s^`JXX1MMCbon>z-t~7+VoDWM+Fe>`FYqt1ratp6k(Y@_txcfTh@sVqpwm;2SX?8iFK-^iNa?1mScy_-!(+h_ zFRPqJh@T$YDuyG~5kFtHC2mTIO`f?_kTalYwCy=KnOl`@|jw8)^8r*G)*>!l-Y zxaYy=;Rkm;01rR(un2}lw%(c+fd8_1xwg&jIf6Uyh_6MuHy;A)E!ZB8iEnu@CcamN z+}K%g<(7W|pZUy<@Y#=Dx$gW`;gM`N`}MC^PC{AaEP3%Zo2 zl{Y9B?jmtVDX_;!AON32M{Frw@#p@nJxAjRKNpW^{mS4i2>>$CKf~9)8Cbj2hAoXY z-_q#9=5{CA)amxtb~-&txNB}zmJQC9|voINHp^%ro`5;uY$e1A`a0OIJvto8% zTd2X%(2)FD+|;`wU@*^x#4tOWCo8~;=)}R5_)Xb5F>7zy0ea+{5QmM-IIU?$zv;=E z-n|9<*k!9m5*1n2V-*f#2>3-cTD6?H36||oHVB-oaX2yChJ{)a>h*?r)S+2#3E*$b zfGF0qdTXkJ?Seuat6Qzb6N5u9GW|D;@VV zxk2apR=?fq-6Ii^J8gT#Ves|veSA%s&iG{t3@BvOW~vN<hbL6#|oG95dw-^uyp60lvFq>s^4ypFa-w-2W`xyYo>vcJwH;n>AoduL5Zu1?VhD z#=R?3<;10|sK}R!=rb4+h|<-rf?A}A3<2b(VCbw1;et!Agd48^Fl_(SH8)>*Za(YT zzZqHmG~`4aUyjA2%lLo5B3zFVD!vv(;tw*47*VY{jtl2eLVXJ`@%JAo0x;!afGr@x z#g_Bwkdm&rwR$0iAMHODVL%YCUlqQo;Gcp18MuCa0=5c_+FEO|t<84tidL&z!m_*s zcmobo-Ss33jG*ppx zp;#q2apHt7Wi#b^$DKqj_l;@vC>bOe_L{oxWrwlC8w>j8+g4SNxKciXjR{<=;RzD- zaui0&Tv?ZvI8^e6ZB6<%@x=~-ql*BqO?Tnw^dg*^o`K`Xj*Ih}hPk;pSX@|yW}^xq9X=cVTeXJd6*R0J&xZE7ZunC1YU<+E`hlwz)v692j9BmXK?@h55oMb zy9L0Xls6cO8wsYpe_fGnFW^Km^H~F+Hz!^1)ZvK($e#-%Yc7P}yzXQ0JDE*^2%iy|r#84|@2kE58105;M>*7*0tRWd}0 zOo+t$9tV`i;$y+g)i9}|5lHdI{yEDG^t1KG*MS)*&39n?QWG?(vLBC` zcNa5Kk$uaXQa%vWQ6oGLd6A(@z{fsjA>3Oo(A`5t`q)qjc3rY6?U0w=cgU^JA1~e- zgsXlSMe)SU%q-MuOSYt~M$(LryW5zx1v-$#o}IF;<^AG1K$2uX1T*8IA_EKYNy14@ z0Dh&2rCKf-*Atk*A06?cJp~LwUS(@II)xcrc?`nxI26iNd5sGN1pF$Djg7+8)FhmB)@oR_dZip| z#LtI^EAl;|UPVKdn@xYfvDujhey&Ll1ltnKfr%XZ$F>S{dUQ4~HqyM{^yRT-LuGK~ z2Z5>;wE72nN6 zdF4j9;S)E(j^F+G>}Nl`ZZg~9-sEcN2?6$9sB{_p`%VwSb`OG1HwwkRNuyqmbUVGU zr>dbOjwMAn#I1)0G!Cf(dyyE)zh3+|X8bvo?Terv?iC*!BIECDJS*sC<^62^v)BGv zm{@GVjkOkBS8v51XtuhWngZlIl62RWC3eL^CNc}hvT{ymokc7&7jms~DSTD{{H{uo zJXS5hW9Lu88}1Qax*8r^Z02sApC9^D%x1C7Z$MvV`>Iq;Q#$IN`fEb#-FeY-u+n-4 zg81}t74KKgE7hZnx zWq9d@-Ei`?z0h3{m!vZ-UaSsUA}EoG%YR2HQJ_W+dO-<#VMT7{5ENj#Fakkk9IE3} z0`S+udFP%3XP8Icx>z!!fAm)|%RX!udi98uxqIL7Bv2FDtI-fWwzlVKvW-2_? zmc-T5vxK5ypAe7k%o97tMy%YiI%cK`AS9v4Xhn6H?}|t4j6P;#)k+?!MFK0u{V_Gf zA*2KbY4oSpOdV})pM$Ue?>pg{XP<@otN{A@Ya*+k6&JV(BsU^nMBHe-d40W*8xhO# zI-);^a9jnB-5ITuUlJMrxiGZuQuy#ku7%&e>3aCW$2Vn}{aXR}$6-W({8SXfEv+tu ztu7OQ-wV5)Zm!emQ1Ov;I^7_OdJ^!tir|RYS6MC;a9+sA*cuALkRczWC?dyl0e)7@ zlet0&3nI5_uU{3srDVPg^xs8m&nehc>%i7}3$`pZ5$HP-=rN=3iBJ_w+fw*WY~Bd+ zSZYR)M<5nA<7~N*+g&Zu$41KVqf1u}_PPJ(tg#B*E&_=^HLppe&`u=V2+Wg^1xWJN z>^wJt6qqG@^*V=CcwzTbuyFhUu%#oiq*k<`&_jrio?(>_i|C)haMQ zGbWz@EI4-L5S)GFJeZ%Khh}ploD-idvi@->Y2e2!-vj{G7eKS(h@DCxHmjAHIdK4o zs&I@lt^B7)1G)6Rvn6ou&G##&xXDgELmo)BfmG$3*(rmh+;Eb-$iayH=!yZpKUOeD ziU0Vledf<3TJa#3u-vt^3rp_c+N#Ot0=WLYA?YdZ1%X1b03($U){GH3YmdAR-;Q^= zH7x?e2cCQd{`MPp!2=IG0F6@u>^rB#-x`t}7sTc3sB^{OkQmJYE&(5CUIb=k1@Ne> z$Gb|iAv{Y4g_GxA4p)EZBk<{M*TTR0t&20Tf2$Iw<4{Jx??mt=%5Rn-G#kJAan^e>|2fz^PXCgnl0I`ew0 zYyC>!xehmb2aNtu5(yx-i;_;Y*m|w*}xgJFR@D*$G;$ zR?uiP#n(C*1mIpqrB;Fn=|nak6vZA}E?1)JaD`VYWinLG-B&G=ed6|-*|a98z1`=Q zf&M#mJ%?nx7HnN=v8_wZ&X$Hq?>nuw9H+yq1+#es3M7!_Wj2q1pKDdc4LDpPJ4H6X z^P&~7`z^cCLOL6S;RJ#{M#XrHnC+_;nB!RoTH(&{m`S2e4g&$eFU2#KECrj)4hdP6 zB9WG+*uNhuDMHpD5IeL8@c7;)Jo!)0!F@ly7oL0aQHU0g0*U9v&qs2E3j6g0oU&dD z0=+qO;=`YP*y%L?T&(C!Qv?8u!0H?h?qf1oo1B`2RjXG38y}Hc0Y-1Y&Z`^MLaN#r zOn2O6Wrw(Fhgd5PN;z0*T0pG&Ak!NCs*j$Q@6{25tP9Zo>xNSuggUQ#OY&1?c%I0{ zJ(W7H0hkbLEzFIpu9&-9LfpW5zDf_?)te%;4MEe&ABLV=db#b|iA%0@dN4^5U#}Jus4-4x0Fw6FL zvzpdkm?*GMi!M3KVy-7r0-)kCH5$O#BWesUA5c%w$(M{$3$O13yQkqB-`NTG-up8+ zcI2@19^i3H0RFtX7m(w@+PV_cl{5AvH>Aq?BJ+0#CC(#%w)lDps*~ez)s}1F6CeFB zY`x~2!V>=)VKjGsj^2VjDhEYsLcTJDZyI zCP!sEoS#=&bO`x!5%QSL%d&mp$Z$E>iM{kI&U*98_HSera`bR6pWBQZEpEoWUZkDt z5cmT(iHH4aYrpEr=o;{$e)$)yQ=J@!)gm{lq_4z+a-jnJsVbKY?BU|zaXbtz_M8$K z{)=<)=%bIr-9P#<9NGIEKyOKBj>d70O5o$z%h&32QX*B0sUSW0|4ozotksMi zk2ChWrW0T-bj@faPeoKf>~-bdh@={aRAYKU;P@3>kM21SKn>7Fq=(1O;D(z(#LN1L zlUO81kx4(7FQ+R-fVi8{WTvh{jJkgRdrR!iL)>T}#p#p~hKdwciUb=u9=1x57-e+N zwf}erZu{P&@ZInI7+!kuIaOgnEd`Oy$Gt`I7K?iVOZt+X-<0f+zMZWoDrGUhFpOY!jV5KN4Z^0Bc|%(cLPd%!x+53B692o3SDU_+n8h;FU}HBh_-aQ`~HKUbz-dyDXuQBl`-4q6|=Q zDdCz(3iL#=>%$vOd?cz7hZ6~#Tu221CbKhTeFJ8Bf$pPN&KF76R7Gs;MIxsa(hD{6 zUpfi!S zTt}S5Ew_679#PWEbD8&h#L)k_H}h`-FPqI1&m6%71+jA7Gv+=C{)G{{HRGGaIuhEz zgFA&m0m8t>4ZRubKsndu7nT% z=7->ht?z>`-gsdK_NT$ZKE5RG_27#L_{ho^fFEN2zAm!+rKNffLBHGW1Y-Y^H(R+} zB%@;^(Zs|!85>Zn5TPj<{!BQxOLm|zGoIAU1UMcSR2?1 zw6dOG5jG%X;nR%eX~35OQ9gt*0r+Twf-LOnK*An}r4E7Tj&OMD#Ut?G{SU$eKf51h zP8^obWfG7{pg~M)%*#|6)q5%`V-sM{1N@kin?0vGv*&?M6}_?qf;cECZZIEZxj9ya zV+r=!dmb%PWeGxLhFWX@&x=skgC`zvno5bvP>Btm2siWl+>WJzM{-l`0pc0+a4*2} z0tx`H9Isy6Ra=Z}9k;C&6PZ~eo|NmQ8nlsd5ZHNsZdx&B3X|%VkM4UzLMoZ)K0UG8 z__|WAgFi@A5bQf`oV3pOP%0)hMIbOI?iF;r6W<>`8#Z2cHC%W7N8oop z{oz}$y?p#j*=~1wtb?Z@*Xl~9{vWiuJZQJOVOwPQ&1M?`KVPfWgIa9~iF-lR>jomr zC#6!6kBpA+$%%0~J~qlmhs)m^8zN6!yp|j~ozFD`{nKbYKMh-E>+prSrQY_%#ifb* zQbT6MO7gbAODNG=DTyqlxOb#XcM71t?bkV4_hzng9(EV>)Bp;p7~Os>??;+g#`V}e zXC8~6Co_Em_#P)NArp(7fkHlzguRu+YAmmuBLl_L>OBHaA7b$2?pH;2e?L6@;DfMu z^0>_Kk!+<9F0_CwyVsb-g=G;7h>bl!FLPDe$IPB5Jbd-PO~ev2XBJ>(URCyM=G}q1 z%owd`C4ym(IV^~CD#&tlsIBTEJ=sgW$+;d^<$ViuO#c8keRDru_o^s9coXiC=G;#t zu3tZI(FPBO-ynmeM1T=kQ(t*3lEv-<1T{Jcva~M&9XTo}#)HSHgC0ZFWGpqt;VCjX zMgF8*uM7rJ&REJVQy3H3eI=*76Yx=F$&*5t#BbiS55Dr3e+w@@_Y6es1whYZ3FaNV zN7@qHW%Z)@iZsE&0FdF=^$b3z6@bb{Ao+2aSg{g5{khMRU?XcArpx6i0^k7rTr%}>9^;IXIo!oBzW6rOy17u4tGRR0yUFFR)KaR*4O%O)E!T7Kz95mFU3ZOp#jej4%22HiL9tMj0gWlw zCt!*>aUx|H%kfu}WqBz%oBSo^(C0hUc_uza)sMKqf-$f>iex5j+AVrkUuxzvb*@@M z$3_~S*1n68)Vu-H5gr0Qu|MN99DEkPF%@Fmoj<;Bv8QBeIUb-YK&3(e6GQsGK;kP^ z21|vUJC~P^w&5?n`UAM*`**?I^l=gY)z#7G#7)&WEP{}ZKB8FiH&kI}Nd$o<5ugo= zb3?9%c#)xVVfBW~;e)?-f)4y%R}s=z;t_EPdI>$J2Xq5Iq(J@ zo=_|5L%sQXNS4@%%G`M(K=9|*eIWJ%m&7Hf+KAV+1x#sP{*O~PX`!PL6tlrVgmLG6 zY(^tZW=|4R8t$06ZaYvD*~qs-wUA^GAs&;%0Zdi6ypDJca!B?JKuZ7<_`xHu!Tow;Q1NPO~Zd__?K8UH0?a?H28JdO2*94G#|y z3Hak<9JBqAa_)Z)m*9nW%K2uX|2D2Cj=(LaYV6<6FVr_L)s|%69((o`5k(GHD@R5u zx%(!E;I_-&!C>#NVjo_ZPX{mD<^i6tBKxOhM$^st!-j467Xu`1IC#F`x#H0ZIazTPs z6szD!m5{w@Hx2TpLV}h3nDB(}u&KCP7Qd&+ldh_`R)or+2^d@BRG(Be!C>%Vp z0WnT`Olr<6)g?W;sE>mqtDPA;UTu7%&3ep;AO=sEwVN`(;~?ltiLFX-O)ONSf0beY zV@2b8Z_ZH#YS_H_-#r=? z<+)Yju?~m`(h=;pZ~rv>)<@rW^Oft1+1TA_zV>RF-EI#=79U}jpKG_{l2WuTv}!FJcZ)V-1`}0#^A3h)lQuvSf>rx+8WZuYb)p2|V>`1dlxN0^D=g-SEsmJs|*p zTFu_$Q;RHKjoV=vUd`gmtlnh!LCynnrXmrlrv3>K*KzpsFaLLV^}s$65QtzeUIZR3 zijOrXpp+9}ABp>-GouF-(d}+E6jxmW@89wvxPI$3@W~sl{NxquOLu0w-08m#OhXO< zU*uZTGkvi)2O|5=VUmJd4z}6G#zwf#XWT075uLT+=3UBhs0u6|7nwaW^oI(| z$;5J)YZ2JBzX!XXd>-!p(OvNDGtWTOm{;JATet*ts{8OAfecC`U4ea3m-1uJ)koLT znP%ntwQ)Ir4_c_l6XnsfP?xeSUS-;Pb?Ax<&B|v!v zTyXjO;fr7V9r*1V-&a0winOvF?wzx`ks|MPdJv#fUboxHwIpM|MH@)oTdD``RvQBW z%HlW>nLQsLA0wk=X&=Ch>99@sOBlhY3 zD;o8o=RG>(4VO?So#_7kGClk@fyZCz!6Un#gP+}dFFgPJ&mn5n|9|%01j?@KEEE0r zKIh!|-kPg4PnKm{vaL9FaFoGGlm#Tej7u&OK*;|M30ar~Bumht6a?dc>N!kJ+3ef)NgN{U#%lLbvyPx*v ztuRdDG`5Y^%{k!dxr=&JvOXV>K4Lf%2f$iJ3!Q^&GQC^Uw>5{%spqmmmDUdsBY{y== znK6#F(dFNhS($>(f~3se)M_RP;~!uHiG=hYbTF376=`G?3O?|Np6luK=-DCs>id2d zzWO&G11OY0#vS}34~(pBoNCFC2z47X)H#ye20!;EPJR_}7)Z zeCoPQ(AsFnehu_r!i@lbak+Ev^2KE!-R5eo3R5$aFf~@Vf7=-Rr+wdqb?rvl_HTwG zk3ExvA_6}xyq!)5Xe^P=MSoag^*jQ7dXOf65+`Xt8SgpBFCxkNuKznGjT;aG8Yae;%_oOwbae-P~COA;3Ewge0flEkzP9*_caUJ7t zpD0J$UI=ih5c<89W9e%G5TWPvg#mwhO>8PH{IC=P)@u-Hz(tx+<-o0O2=-X`;2(Sj z{`S)!$Aj*G>?|=6PxbI?e;K^7y?7o&h%a`SXQ7Cw=jUMG!9(z`|IORrr~bEBTw~*J z)GR;dEdR&C2uNth8w`fQa6kmU9;xs7xHd7VkA!$ILGeoEqMVwX00jP+K)+g)j~>_o zM>pcJUjzM@X!|OW_SOb(TfVpg?RJMpuqG$RVP?E=9|Hc*ZnP1+Z+0u>bMwVwaT|^8 z(RrZp#CE$4l}d#{pY`@5UFKJbUi=C0IkPX(Low*n$kpZSa9y}PwF>ai6Ak$LFMSO@ z_nE(er;i^)Odo2MJ+65d^o%|A?ums>Qn*Ca^YqNME@>wjni;KqhW$BA`&W2#J^K?8gfz)-6Sn^Vdl%}YJaDoP-GT z91nw${Y=4L_x!DwdoMcDqdG3x`8L3?q>*_@uTc#>dALty85^{^ON`IJ!}f{~GAO1ltL+ zziq1@s@EIER;$JKw&N4yFi|Uga&ryd|8fC*+DZlg(PF8%jqH89%geB`Qiqv(1B0L% ze_VJF4j3qFwM3m^25a=gZBV9qs7g@>oG8@^Q9$QlI$k7Y%g)jU)eBtw-hqI?o z;i5h;d1k~WC^Ty?NY6gT%s)0IeeU0z*=t*}XSDFLAiy9Q_u*4(SDAU&GMUT*Z{oB7 z9OQJ^`RTt4Gs2d{h&AJI!~XrSb=wvgtL8ahjZAF8V4vupQ&=`VdvK(Q-O{>6ecKX9 z)ad-Z+YY$Yh89u)&jfceL!zkU$ToH@-Smn^wV{s}Z| zpPS|0elo;JtF{lSoAwCZNfj8ee_RluLeRlLb9Bg;hp>{7i)E|WR4rw$t zq)C|wgX+leWRmoAv;h}caFciz`+49!n#%qpv}D=m8%3 zzltzsjN+Ke_dY#Hg^y%+dp(xf4TdbW3qAt99G^hIuU4U4F2)G>kKed;<5p#_f&NRd z)q8MHz1ch5SZnf1H8xg*v0CN$Yz;ne!}P|#iT)v5IWLYBi>12}_(^~WE?l?(Q&Uqw zVi#n_Lp^^z!yhql&`iI80<xzHNd_ zlhr1v3*SinLD|tfnUT*@pIuWyz`wt3?|wLN-~epeG|dD)TfTSu_^v6DBYrpXoV1y_ z%qj(jQ|PMYUQ%dqvujUYTDI35i_zjm8X!QXK&+g7Q^tue1$QFMndfY_&NKBUaDa95 z_?j3f&HftFqv_?-^aR;8Csvj@NkH2;$I$O}p`G{OLNkCO29Nbt0#6@52@ikyYY2cL ze(V#F;PoK99R6Jl2Afaeb+rOuWX+D`X(X>pTt+$7Ke`y(PYO%z|=2vR4$8%=D9`d9BS}Ytc6pDxOetmnX zkb7{Ym3y#O@gBT+>&8$5y=)aw2fcy}D=EvT^8OIB`~mg!djnSEBO#tJ90p{UJ3cU2ErCN@wrTp*L3gYV`Y*xO?x|N(DH|^)R-~hdu~zmTe8p8ZlK0{=eK zh_`px>|{rPPwILk zt4o=lZECxzuyg=<#PLn8>*cGoGq3De+Im!U>-Qi=-xD-K2bCGP^%bvxUAwo#WUZKL z05Ral>ANx*yMUec&%p@d( zE(knWy08MrkDY*Ka}DO^HownAY z*IDMx%6uwwjAN|k!7(GGvp&tuh;O6m1sETB69=T4^eQXA^WTxM`=(pq=9`JYH_Mr+ z>p+;eF^K_T>rs$o!h1TSmYFe6O5#fy^bUQ{@h_0;#_TNUkFfq7=UnIT(ikZVBy?*g zEpVjoFGfUrXarLwmjm{7%6sddH;#I2%p|qo5iZsUW;%#SSj0zgpoCc)KiBE@82IQu zB$vw5&zxfNrtk}p&GwryKz%H-gepDn-R&RtjTDD7kOaCog5 z-`!~S-a#$IwY3J&NboWS)vGJ3u!`R|8x0Nwy1g!h!yzkTQmNm{PV17sw&yMu%gj3> zvhi501{0GLfEh2hCCA39hbooIp>D5wus6tm_>Mi|{*AN-nHb%}K+#K**o&gr#|M%5 zNSp@)fFb@I;WFcSc$}hAs}SHPr9$v$r93>n(bwQ>p#Lr2dLbMf45EWEtL&K}&}*$iJZSKYy-fND2%%=^lU6?UYKitm<5-m46LF8U^ogO* z>Tss!ZDerSCC{4FI2N&*#joq-O1MpJr_b#g+^6=pNh-&iO35l`-kr8Mg7NJ)z-wN2 z7wo%XFHDaYxtd`!=h#XUo4===?Am4I0D(Y$zYC?E_EC&jyW&%%b#DWFWBZjmHWK^!N397j?!^@kV$L>^uv9$r6Q zA)k{};iy(BlG>5DZa;nF7C3ti^sjBtyWv_>48xd#iZWFq@s;!NrI+(L$>+Rz0{vpK z1UbwuR+d-c+``5bK_g!&|TjNx4rUK*t%(o8T)CLpSY^NnHiBvb>~$U zK!}W~?keV_9K`gHgaKqLt1D9QcC#Y;OPa>|M{S@8uMOYRuczzC{=Vf2Q0qt<$!4km%+1Zhov*nQ zXngjmqel?|23)&=%1$VZ&GP;%oIT5BZ7Of)a=}3iDE^~@pm^I>xFSmZ#LTaE)IH7C z;JwXO2LogblrOHpMLec+=N54P7x3#j1pTwnsn0{wJ7&U-U4%*XPF~__v5}eir$qZW2N1*@|_!D{V_d# zkK#fa$3x)HVNi(RA4~fcuPs?B7ctW>i$bv|FaS_^KVB95t81YDt-injN~XcdL^UR> z`7bZ>-ukVO_m1Zag@Z*F>M1bS;lkntF89+SO8+B|~jhOAA;qjv0OxukafC-V4fVh@sC(O^Fvf7UW5X%Vp{ar}J=QwBydz zgG+Z0!TQNvgjw3mT^%Vg;yQ~f1_8s;&|OkHoZEdi+nF1@!WvPwW~6orKx zl}56ofvz^cut7!wBg{jsp&vV0JUqwuTA7hDbrMHpWj>{KgsqG)YyNS&AkiKTX3jtJ z4piJKqQHRoBgAM=@Y+~fT85QK&q2n+J}fU^WG{?TxdN2s@o&fKP!x?%b^7^(vo&$w zzL{?ygZtQd*tgPB_cYqQUu-oyT+S!JCw|Q0xkWgA`ZSz5a|Tw<9fz=SjAex{oAZ+T zB#*F4M=QZ8^CS&CM|o(pm!P>k2Fr_^@LX+!ZOhxC!#pKznuTZj-p@ZduI}0|e{utW zeoisyD-W*`$-o~m;0I)OhS#GX_`WO^OO)ZuLV;|}y+1_IKXWy#zt=$jTf7lh4X+>W zm(k)wv*k1o`*J=frJOiYDCX}emP)v&mU%I*uU=#V5uGDijM*a945L&3F&W?~3o(-q zo0@!==$<^y+_U)!SK$e~N}vJ+`rIS}|ClyNp=_L#))?9HnmKQK_@+Ov^Iez<0joJK?7NdtrJE zgF|CBLr!<;NL@<6QzjTOH3yaT`K^|{&BE7{>(a#B@%gc&NIMM>8?dy2M(n&cQ5l)f z$lmk5j!x*=mWJE*7ng|pWSW23&RHT~`djJw6sbL~Fx8mE>NpU`L&e5MS92{mFfi{c zm`fnRYAoae4QSK~xbx0CV0?TGKL5Edz*nLnG?o@&c=jtWR6S^o?a?g@3?i8LhS%X> zIM_GnkH4$aEgf2I2cMiM!>6ca^-|tHPh*C^+*0>8n!R^5noYcS8r-`-f9^b-n_qzW zv-9xm=~GZ&cnnnc*t`pk^>*V zCv%HJp@^U#;mDh?!!QPMhz-?XtHZ2(}u~3@x$$E?eJQ;c=t+EJ~&>MpCrY} zm*W0eZDWSt>c5M4FDuJ+?%z{}fA;h|0{&?@d-e>h%|8qitucthTxC1_S z!gx{Ohlkf8W%^z&$jKn^Rp5IG-V=?hW&OPd`rqR1z#KeuZcQG~7jpZCeJX_|FbHAW z%Nq1^FrPzkFAz%@v;AD5%q;uf#iOv|`AoJVlAmYn^76Sn4DuxiqcP0j5yUYl;J!G` z+cPUaufO6$S#cd=ViOQkKoC?7Vb5gO!e;EYq_1;QWdK#3l6vUOu@QbrM;dO`K!eDdrf$L!w0iO=pYU{i1f~nnb_BNMCwH_+HHX z3H(2G^OkSj7~8|oz`c$3@NgRep9p)zNjQHV0UxvbGtZu4&~Gh1c3Hq@J7Z~-Ch>mY z`vJ$yhnYMTNeJAj zm#=IFqWCLkD>Q;f&joo6^!&3hqj#|(=S6IZYa0Bzyid$!#JtIhCf|Mi){HLa;4zMn<4)*&{aLuD-U{z-HrsdCF%TgF?Be1DID6&{kE)(M{VcQ>zXoc!cq!PE zmxQGIC$Gh+@V-c-u8?JBNf|j+uq<_`xiidJ8JPPgF`g8}f?I>$Y78fyic+oxeH@r1 zPx+qrZy)x`%eU_le{jWtKBf(VsUN&y5|1EH%soPVyb$prasLtgg`%L4S$&dDz%|gn zw!O%0ya1o7lneLv`-6i-dTIBPLl4i(dvD(c_rDy^$L?w99eLI#2LCn!{!*y`5`qxdtLag>(x)sYFu?D^n4>{!{qB_& z-Erk{CDD1)UcW8%Gc(@$%cnDJ_KQr*{I(L1!lNbfflb>1a$|FF%d1`kue<9mxb@%x z*tTT~YDGv#^V|`)*o@o>5F^>V>*?oa@?ssK&IkAB0ZSC5!(= zv97b|kJRo{#tG2DgfNo?*$L34e|-Wh@FzytM;IC5m~DO$CiA3D7eH;S3R^dAGPclN zo-iR9X_|wl-gd28!2n?5V5eL<*lHIKH@mq{PGIJL;2$CLKXMu{n27Fawe(mX0shj` z1!m_jES!V$3umFd^!NzibCAW>&{Z}P5*W-RvWVv?&?ZwHC}#vdkzK7?H-Wq;lm>r^ zK{g~^O_b$V#-`BKfnj3-PM-=`#gAGsM9$3@3fBiY|K8*03!mG!85XXj^#?Dx(Bn%* zFzySD_dbEWeTY>4kuR&{YFdA5DR(od^rWJOhT=il1knb1kmp zWhGz`21Hak&+pWA9deyN;&Trfao?e^XYZM1(IR`HNK$YG!^XEF^$HTFA1@)OPQs4s zZh}|6<~4Bp9k;>Gom*jcqR7(1DOg(ZowS6VWw93V6Bt#}O99IOxpW2ogqvmSVum!0 z3_5HcaWlsmxv`NNts2-2KXhIE%zL|zeA1~bNT+RJ#|slvC2(UgXvUdl2x4><8sB*s}lvE zvZ~2qU=$q110gP_HQ4SRaOUh;s4sj2gX9y=6(Kph7r`tj5*zYMtXOEJj_tie z=Oq=2O23M<{hCeyzHAyq)a)H2r1s{P3!%$HEkHL=6qE0b&g~qOd z{y)NYVif|so{D&n7V-WHFx#jA@O_vB5}No~ba0{Q>>l6v{SkZ-lILQ~+0PYzM zhENys?HELsdJ%l;N)h~csWvv=DHQH0u@?a@5akkx{3Is&^BU%O?!LsTVUibF&y-z_ zQHz7+PPKgmp|XB1WEQ#B35F^J)U#AhjT>Z^+9qPO9uA%Z?!rQ`L2BV3rw_Tx7);D= zhF!a_hZ_;-_ua4$cJ9~;lap1b6luiF8I7|o1hAqs>(p`FB85u->Lm_$l(px4J>r+Z z==lh|(N=&}7ADfQYq=|&%w5Wioo}D>ZD+(#7j4JHB@J3)pbZ?XK%ua$29W7KC#Iy3 z5+{{1eR@bo3S;NrO|d7Pl=SS_qO?K5sD!Vs6v#AikU}_rFX3Yhqr_Y*Hds*FGXOJI zI+r}YX(~FjyZJyn_mMLoCin5PSQBU?Q zn{|0l%6zZUmiP7tH0~1L+a2Z(Hhbbt<0bfugIiu6COl-klVekl5@!Wv1b;7Ag-GTR z?7Q0Tloa%6M2HAkJPU8izP8M+GSZ#v{Gx2u=Lo#G3BLvFR6AcezOllYxle-%ku{|g z^RqH`yIv9UcnoFCZYCzDVC#-u2==>ivEK$;w^Ft@4z+5LGkaTJHy$TxMxG_sV&uD# zvbkN*4e;73ciNj5dR)(z;N2=ZWux{zv<{9)v+Tr%Gil%6klvhjg2e*s?k7bC_;E6N zS{00P3_Oud9awJwJKvv`*fX_0dM+|=M_K*G^^9oE!Ligsi@sc!?0eU3RiJ1(K zfd1Xu>}J6mjEERmfgj57w2)Ao?sJZeo_Kss@OWpA45G$;4uI&~#A6glPQmod3_SGr z4`F7$2E*Y&Ci_iJPLO83Hm)g`?1Pd)rIXV1X1r_aE}`KKUhk*#}_wxPf;V|G7-J3EcnTaL4N8hhpA zCsjf-t-zo!?br(BFq>I?8$BVlF8suqxA<`_ZOGMYs@mB@8K?1or zgnRMkE8>ev_(A>ES`WTFQG~zPGeOPYjS2iuEJ81k!Aia3y`$UfL!;R~*zFPU`-j)M z-uFyb;P($~+PK!0FJ`Oc;Gsf3w}Ok`6gzogwjUJAxO@@lw{T$%b-5igej*{c?6A~y zMQGi19{myqEX~-K_NGr#FFs1eSB_8FYXnLYKnP5iwl>vsc^ttM960AQ!q_jGaHctd77OY(2-7$ z-7~RAI&i46-?3ap>6Gd@YfiH9IvcyV8~{4>z~KPI;7q!yb>@SR;ib4NSd1D7I<0uk z;5QPy9GE4}WPvBrf{YC)%;YAY1J~x4k4Ge&%`2mtEKDCDF(rE2pSQ$38w5(jy@+W7 z1V0?#GYW}HYX^p;(NA++RCeSpli;d=k3U!P5(3VeF|#j_9j&Q+V89solW^p*5)4?? zZ;6Gb$Zum3ua}8QYgj|0ei-PMD~C(P;^814u;ZX5EE2%dcwi4fzwMOuiLiGLv->lr z&%y-+{CMp#t*B?uKauwQSxE9zcpmet{z(8$?=4N1Psi<hp3B`b;QpnVxV;p7$3 zUi4uZPy4S1f&9537mx^#qA_7i#MEFI3Pq+wcoB5EU9Zz_CzzDPtwQkX$LFDb^EPuVCAy%qe3H$j zu_AAX3wwYUi05Fx%9z~@PKKf;gboCpF*gbg5^xqYl_3`^CBlTSuQA6sxXcj z{LJ(W%x>BQv$L}>J*&+}NXd<$+Q7!}fq z)rg$^NPv*`*=_&Z>Gdl$8r#@jzjPS+HV{ah>>M1j9vJf6`uYA5^Bk4U%-epuyT3M* z2j!3grOD*^xrE7KTxwR9pqEMg+VX}ykEtr47%jjgQdc)fMUi^$448=q=2DKxiTYR) z6KM%cZm`Bpu@=kHRg%O^3kbu3kZj@;Cn~LqfS$reJQU4&b*&>cX+%M_oYxM zL95w-vu94TV;z;`DKMO#nMUBBFu-4fDh9j-%rI#@m9+}E?Gmv-6|D)Rr%xUfWS&E$ zz4?U&1pMO=H@<T5W(?KLtjbw87J?2>i{pIxL<)2aB6GG5A-QRJHi+RkzTd9yP~6fTdjD!T zh~!EH@9c&CK@7(4yLHpXEVr<3_YA!6>kDFjB`Ez+y(#bM-~~qWzrAk%P^VWq)b8hB z-3j6SH(#Y$e>o3F^2Nd-?b%&{0s?=dFbOc2*Q+$Kg{iMk*-TQvMa?s1Sq;|0(8xt9 zQ!Ae1FKHRpkxa%l#Ss~!&dV2IYIY8`Y}o=^w{M3nTerX_%;d>hl(RDoP>RJoF48{B zxe_o1UIwgsR$XPvc`6h6wZ8JMpS|^{cV%+zVZ`P&zGK=q;_~Y-=hI(zO8z1($7@3# z>9h@`$Q<%)1|ON{t(uAqyf zK=zC#coHJq|9qfF{wf6l)sp1TB8Pv6#w>Gwk{&bRb(H7>C%^jo>Iz?Tjm8=RaE`O( zr=LCsi;IiQ?kAhtF?v*MCg9EMjM}syDAOn332l+P3QPEVG#PO5+|v*>j_|$V0zQ%U zl3<2SrU>Z0z|-$%0pIhSmY7q#Hy4}B>UV+PRvz5f20jKTGD)X6SW|+7Mc;TygsR`| zuuCSn7|zbj3c7#RYSr(2YO(O~8#lqJD`EX9=HL`2l83oFs7EtKVcP0-T<`7%{9-Zr$0i?epad?ApBt z_T6v;?B2Tvwr$(Web`F13?gekjbtgWhMaVf4DpE4H5D1@ zW5jJ(tGBuL&Za-O1Km~|-^YioTW^8J+A^Fv@f2LVI0eLTr%Dl(zA50P768djOXD9v znSQsU34HaH6AMD@|Di|Dh^>{Jcyiw+Sb152{;?GZFrfB{OM?MsQo(HghUsq(=$~u5aT=b*FV7xX zgr<~U)b5HOZTF+^S@!(KF&`Fgn1ZJ_D)>>k|D+Gc@g_pxufDCmssAsHmsjp9>Jf@6m zZDfUTvtzq>Cz;Sl+AwCDowU!-3m9fF`C=LN?70pO9J~eg-*gjZ_M2g1yoUQyfFO{p zgCBS!#<>072~IN22uNP9tgrcy!!^m86ZX$`{Fx0xH z)HfC~E2ZOOfWJ>|56@)Nu^qKDfr+J3q?L(vF2<~%sIn;n&o{kzBK%Q{z?kq@VIKQ; zsL${F^lv@~4&6ZlPn=`l3*H}B`HxxrVUh(k=0o$fx*U@*dw3b{n3PnV!c1TPUZS!} z4eb_HAx=HJ1V_I9D6|paZGK)dw6qL$Unr&y> zZD}H-7|(YX*MN4r3C*=t=+_bOyU%3)5cYE=7s+4>FVY&G8!e7QfX`n|hOc8=;{o9S zy$1Vil+RXiTxCPzOxT}e(*jYBKY}I-25A6H6Cts}6Bc(>uhW9HwG~)dSy8L2^<;Lg z1&wy;bx$uAK6?EoSiBO}Aj;H_oPn7*A?{v5(0xFajhJL3@qDy9fX_uye=v~sdXspa zias0SGlXIBU-ZNLU|8^e^RcsVs+@youbUI?D}CMde*Wiw{+s^gf1SqBV@v?YL;&=KJF4)*3vrkpXbB1ic*-@VWL-t|&jh z2N$YM5y|#q#y=cHW5dKdyxj9Q;lgrcs>BtL4ZqD)VCmUa@%^oKf4e3ut-&N=}qvaHy?&O z?sz5a-MbU!rfX0u2VBmHszRq(H@^awcoH#Jt$ariEBHe=f2TyA^U@#;?D^9Qd$H4wkd7!!N;t%Q3Jkr1D+BKN zGT+B$OhJpL#HN%ljq09Z?Sso}FnwzUhP7}1zRu*SwZL2gvoCfkfxQO4a}dJN+J zSp@$jh&l_p{5io(Fp22DQ6g@O68T#Ex>)ZC+3BnHL|G(P73e>WV1E(8o;Wag(I*J> zLjwAV!b`K$2>d6PyD%Ll^81ESjQ6TsMKFBiY5>D6V{oJwiFx4{YD&l(hJ#R$-#qzN z<3fGMQ04dGu|7Oq-ZScFO|yh$~*3WHz45O`RZ38*zbnf=_=HyXX|C&?;p8_n+budCZ zmLHIe22F8d)$|fWCKM)1wV#jC^iND?n>O}!HKJU^EFZ6lT0zi#$>&Wc;)bkg{x1FQ z0N?K;pL`Pj$8Y=!%hi^u6VR?NF@Od+n*EL#V0-lwdLo6(I@G>u^9q% zMy2r5drW2;8J^6P9UV;syL*WZuoQwMRnrQEq*ARWH3a=ir5xw-#ewkrzn&<+IBwUs zJmD(CpwY)fHGwCT=e>qT6le}e=uO8mx-XUx;FBacts_aoz>nE~LeqVCpGg`&e{GzI z)6Kq$r>ml~;Xxn4K1X0rw=0qI_D#WXs`%~EC0@h(pdUgJlZ{*O(|AQbfWO^T-MA(G zk)Wmu$NLdH3o;kP;2lKZ2LgU7qeijVH&nSha8>;D)ez)dY{6Wkll%b9BNOPa)mNd} z>fxfd0wQi{^A9!!3D_}DJL`F)%6#j<=l_1f3J9`1U>U9kV=n_%na z8O&~dUeGg=TL$jJ0c7Ef^JgP+CIEoZEE7yGT{^&RflSCz(;G{^vxdHwh40SDYra4> zlb^N;oN9p(y1%Te4FZOd2K!;8_hr1KU=Bfj7Bl%B>YXTMyGsTe{n=24Y<2rRt1AG8lqg&!K1Y67 z85X|@6cQ^|#Ef{6N&CWR6@W5t?&HU%bznX;&CIvu>@2#{EgpT0!nBL*EWd7B;Q1){ zFkSPYmKU&fLSW!yS|{sV|7>;OnF|U0?035jDCF(eMtZyGqOq6s$rEsO)X*H1l|3oT$rqlE7e+38yk-i^pirdxFeS@oZK=Y zp1M-jq3H^=)-*Trq!QkD;IYOQ@rl64u_0&t$|JBR!XIHiJ|zf+stH@oOZ;`*zp-%Wjf zj|4kJi7vQ%SC&@=nS4-56{E{TQjUN4`e}IcMnBF{9*z`Pq^HbdOr&LAu8w2qJ%<_4 zGL!gd5mfB@HDHB4p@OtzY0H<=%pL3JRT>bu4CJ{@Ti`XXeGPmEX7@XH?|=zJJ6gI&jd8Lr zh!t!$CA=~yImVg3l4S(?oX+lj9dPMBe%7DovOEF4$>Oz@uyoZe=?(wx&`Hjz9%>Cu= znJY(ab^jJPee^uv(C-sa{69fgHv;nH(XM+E*Wf;)dq~%b>h=Z<_;D1=FpT`+aF~Qq z=;Qea2Vwq)2VpQA7Ub_8Kd+AO+bkLz0`yPRA&6`lT| zw%s@b$MF*Ur9_pAxH#QI@{k1lJR%eXhd+O^{NB5+gLiJ^V=M-6ypZ>f6pMv}1pKwy z7*xlr(7ZSfvCMM`R8jVWH=1Gwf2&!K)6r_6iX@;mqH0*8m8zt-Z z1v1Opk$yj9B0IK~Ff@#HJu9!c2fZ1=ert`ykklpIhs$k?nAJadx&x=qEW!NwWjKFf z4bGiggc1g3Teoh4{nu}Yy}M_DdbFz@VHEXz7Ps-z8FzgwfuEg6&nO&6DwFu7pND4j z&K2E(w9lW7(-Coxh}weOQFH6>DaK6`Hvv5hJyf$wX=C*7x%7>9|V@x!&XRk6Cd3ahJiF)=YNFu;H7 zYCHE?1pQB3N$b%~o8in8=OB-V^y><8KW=Pz^OX5hv_u9y{eF*;MVHn9I>3Vp5 z`J~W~&wJr8%+p#OMI|+igMS$(-X9)afM;&n>Yck{LI2bmer5?1jA`7nzi0egN6h>G zweu2Ig-I<)(C5S|OzoY#I(pqH@Xx~WVGO?=MwKbNnBGh!ekz6M)&f{5=I%XqA-L~` z*^O)1LpHn5EFz6SMHpB3g>XTAn;50jMA9LS&mrKxSOZTn8R9fPOaUwII= z@7ThubC1WvG_lQf(zEit*2PbHFrr6bTPe1>LF{jLdMt@;+26S1nKC?;@~PA=%{io= zs%^O(wO))lLNz^3fQ!)}sfJXOFrub zN(z86?prJqp}d%8+eNF@LeQ@hlOLw0Ct1}GPoXsC-v*2iNXtprQg1Oa2K|9hVU9^OMN_^U1BpR2+% z^&XT4NpL8P;$pAc6ErvL`9Y~rEH-yc{=+RhucU3M3A;Oe_1!e4$Uf!xXtul1#oz{p z7{jr?x8Mv%kL}@o=mmyEWynV^>CG%qT+-jX1>XGTH^XaQ`)b&?cMD9{1UOnZsgj+` zmKTPtpR(}{sHcH})S0?Ps@QSKbG2ww0iJap^R|C&i_n(cubh2RkSXY`nO|Lvpjfe(HdKJ%A<1;@YkIapgdg^P9t!u}e> z&3VXA?txrw6Q1`xkWtjdrE_rX$z%8#wPE+}T`)N{&RKolBcO4n2OQ8(?5w?Gm}6)e z90Bl> z`TTcF1qtIN30rFl#)=~KHn92+>uWGyKGuSt`VYSZ=bri--dV3W$=dfx=LCq{l-^GS zdLo|&g&M@2vv?^tUPQfRT@RnGd*-r~5%9;DwNFfXChmFE&zBqkWaW9So~Qfxei{tO zb)XN1i?RN`S)bYKiayrEM(XMxu=nPbMvLeH8JLsRNL%!Yz|GEhnP8P4s%>EM4@4zPfaQ=4!{ZdZ+ z##kQydZKh?Fhc*ax2#b+3k-uHTH= zTb99RDs!3Cewv+|EGJQ!W1TGMqpfa}` zDzn#dk2qH-L4N8w$dxB_`(QZaEfE0^JynPQ<0pO@jz0EP2qcxa@fr>BTJ7dJ%wMVwFAc##mxk1XZ5LXTZl`MbcO4XLiK~$Sv4QXC{Ar z0JuK$cT4@FugTg0U@HUZnGvb{ux*!Ui)t%ZrL=_x4YuL?6bmH;{YqS^RtDvAsfgFu z#ho+aD_7c@G*O1QHQ-6tNAXg4t?;}E_n#0yA=_PQ+Z2j2>>o!1Q!?pjzK9;P>u*$Itr+_7cH9+$dmgw+oc%58%h>aw_HEa|gG;XW%N{ z*7^{%`tSqH;twNU^a`cYrXcV?G*#ZXO#bc=7TZI)uRn+m^m~1tR3PB*P!P~*>TKWE z-Z|qbaP}jd`DzOW!it+9K-_Zct#J6wZ-N6i?t)!2nvfMI8BnJTe8aSllWdlp=eWV? zNt=?sa;}(AaL3?reN2Ef^Fjz z0LbU<+n=o`@Sgj>06+DA-v=N2^H0LknP(vGW9AvIAyBp1p@2s7sAoRJ&mbOlA?(zl z*KPCU2(*_#bk5_s9k3^YKww$EuuOegxEarNt(s>LCcw0IzIv=nq@+Y@LD*3~TOA?w zGvAX&E;u{?(g73t9p5Ua69B!lcn+5+>_9-C#t*28KwO2SzrfE0lQ(1V zIR^b6nMf6Q{FDM$-K+QbIwnsEYNbdTNu{qQvlj^T;Nu7DjbnyyM)OEmx!37s&Jkv|LRm_`;!!vAe?{}{D#+!MVyTo= zYL$qX{KaB91TXmVR0XcM@wUk_3~{~f;~{>9fnRz`dOm&;)Y@k{qa>EU9wp)nOgZP2 zK;HyJLKFY_UchKU9K>Hd-5;veiL!jjN%8)kv5lJ8GvuSfwU=(EmScF}FCT%Ae*8iB z`q#b!s&PRp9b(3=x(MV^*AzN%!CF0`t%>6vM8P=s@&%>r{S^@Xi`;4vy?F$?Ie_96 z#Dy6+a^whn{gH3Lmbbo^LEJavZ6ekgznxT|2?jk?pr;JL95;b113zWpR8a`^5Tp(s zgboyhCMR000&T9NXu^$KEz&Rn?aaNk;MM0=a6ezS7IbC64+P|Jf693UlNFDNdlMyi z&fa|*pyJ>Ah4=mu{O!j-0=~dNDVM{)<>RHPIc^feHf?!7HHafcNWk1AUw4h%dm;C6-=jH>9diH;L&YWZFNlI%Ve9&%pn zO6uC5-O)T&wzPAqHp@@1Uu{WE?HrOZrhU?c)|h(Q9Fa-fVM&tp_;ZYTayT4{wfd@9 zU0xRTmAY)swnclQd)r#4a3{XuC$7Y`Y40qwpT5Ac?0>@3{|gvY;xQEz=KKXSqUuwr zAJ=5jAM|C&W<7C0Kp#c%&@3cE_xckf`&`14mj5vc{%_+y9(~C{ev~h(8(Jtfy$BeYn~UfM;|=`hYsBiJLd|i84&9Tc)B+q8|QRicTkFr^MX51T1 zV`WHw{Q1Os9E`1RL1*|vsZ3`-*4IGJlovR-O7zr*%|=y{ktXSDfZt41h=(9x8qZ}p zmuc-k*VgDJ@H7AQ<8c3nKY~He(*T7DJbxsTgTWI5c`{tZ1btTfMqtpCpV*JDnTD{} zWp8^9N;sP@YVQcX2qPx~G~mlXOVN@PG?QH1k%J9&{msGr3{{x28^A?W7?9#kF!Rw48S zoag{kdIN9bwXXP7XRLatJ2eTdc849t$fc}N-ws{MG>41Ye1{axJeu7v zIA$ppJasRB&z{||W%C@2m5l|gwRUxS%r=Aez?SvRf|!UAt629N+t*jpDYvW31HJ;s z9LISND@J4YORSrwqkW8&?o-o05J|3#Sg~V5kz6yBUc~s_!>3yC{tx{H{P9OW4&jAo z5ZD(H?3Wpg82*AP0u}+Z9*N}a(~Mzpr4qADLD_4!t%+p02@v_s_&zIkXc52fFfmOQ z=iuDJc{qRm0&JPx!3URCFpP$MtTNqyyZA*8^HEAGpp=+0y+|i4Y#>HiC;dBvv-toL zBgjMk_Hm*ma#M|eGff{G$zI!zA@bg)aSzX>U>*HZ4qg!OY5Tu^@x$=j|Mk}(s1^{* zZ^9s`2N99;h~3T?0SPu2pftS`_W|EHm;|z*$>nmITfo}&zE%YU>t2|c>t}?Cnr7#m zxl55|_rezp_FU2z8F;7v&e^|6xhX=3^;hyGC44skSRX)Jb1ESmDM-kI2(8s%jEOv+ z&ll8MAnkgIz@K20;$ard699=6!@)qbnhm+Sx+d`c79_vj=??ZkvEbi$U@JUzrLIrc z%|QFqG7Rz5|3}gq!jIt>v|Vw5O8p7_r{{6qpHu(gU>JpA7?|plilUG&TG6Nf5IaB) z@mhUr&daYoeLm`3zuAAu=J+=>=tl`m+JzSH+0~Z==u>rrf!^`B7UJqSwwVgtM|Q&f ziHW=02>RqO*1|`l-hgx6y%5z02t-Yg1YBe-8WkZii(Ptt5Cp2#8f@CU879XoEWX2n zFhTSqiXj`j)BrE_xLsm1evy8j`bczXUz#!w!Cf3BX8uAe z>?Ousj>_YuKtKUOKF<=w%9!Pdk@EKCwh#T;*Wsgo`e~5m0>r(GAoDed@f>Ktj9G+- zWtlKA9rmhF-E;s5&;l|gk$TKcDm^j4%(g^1u624}Z7;~~15ZI1GM*mG^NdoWE-NKT zl9uOF6CM72ZHgq;x#q3U*w;UIN&6HaCHJMz88IWXgT@M3-x0Rmz@Q)b5XPa>l?qep zmsIADC5;?68x7f5Tl1Q&mg;tTyPKWT?YLJ@UCHay9&IAGbm9VZ@D%)KNx(1sm_Zy5 z&-dvlh3HePqeXqL`rWG? z@K0QXsX+jeKyAMS*GF;0y~`k{i8`1G&R-43w|5p+S_8Ph+bh3fdU|Rb0SSSBtJ%VA zpa*M71abW_?Ili@yB;a@!8T9p$#+$F%ZW4Rm{r)>(E&Di^%cM16}eV8ntOY&AUDpeVH?tsP>>KO(6%z((6 zOj#GpY#&AHUyu?8Wt{6 z72Y?*I@LaT5f(A#c?TZ)Z!+YIe9XD0BAy=iaOe{b=u{1dVa%VI(Dwid`wRxdq~9ZB zuRQbuZ|>N+aOQ?B!NqH!|2*3>t5768jYN$qs$I=ndkBXHgYXcU@6i0GzPTjzdgrf} zW4vuUJkSrleNjB|u3oQS91I4a8T|v!Y#O-es@4gRQ6DoX{9fv8pBGN!U_$^zHodu= zCc{yHWJkL!>6kIW%e>w#AcHf4>=s4s@7mW{z_&`goWvR!Uz8Nf5M0F|0tY)>~8_Wa}4;LQSuJuH6e@uI=>r4 z=Na8o79_5MOF$HACOIEq%yO^nEf`GV7u=cLnEqV?Pmi>G^ZYZ5v?RJGz5k{gVRB+D z)y?@|B;H|D=%5UBI`!2KvvNq;v%> z>Oc3E5D_}M#LvoL9{FPNB9tQo5(G2$_l_+&&P)xPtRFOwxfwi% z5j(f3{5XrsP`atOe=K#TFEhzO&fvoc#;2#@z^w1gcJbxlu)9wmfKG#(lIyXUi8$0FIrf-8>aU43WdMXobjeIm~ zTk8BzW_=+6qx1UAmRDL#NI2yvrQF$2Thf;!S^njE@!ARUQlhJy`Co2q&#ewfrwt(7 z8B-^yu&suy&A>qjfxXh5$b=``s7;X!Bhl-0RAY_%`m)(<5utCk(Jj9U-{G;1vQF)p zf#IoTSU@EIcX%E?sQA;(c{aDe^XB!sJh;d+D^VOH;PdDn|2M>i0N1u8pAS?&@6R1u zz-)i(w?5n7u%Pd@qFxS({)rWsYIT#tBwEAPvp}WI0162DyC<(c665wscxQiD-4{o5 zhqV|{$e>S;Bo3jw8t4%+1U41sAu_#B>N%1rkygU8*NU0Jclz&|1)g0;F^Aw;7NahM z_{uQ$t>ms;&SDW88WE!s{>7Gn%?R|HDln3TKHv7}vt9U| z2fhgZ??*ol7tfqvAsk`}0ZG5g090ukMv0Guo@v8B5_LHyke~4gq|5C+<*1 ziyBcGpP1%mzED|E;sddyGYdrer0zd(fF~`e>SQM*VjDz(?wMP`qC{w*x5|8^4L~G3 z0(U!8uWXQ(h%}JmUO1KW13k|ln%7fhB1%;1kSC0yU%4Qeoljyr6hP2Op3D7spCM>{)vbsX1SE*d-ZzVBSIgw@LJ=weJ7R*<-K#z z*(mE2_4!X+5G}kCejJhf1CXOnA+NDDtBOcoG6bFq1bXfJknj);u4f4*G^#(${{UI4 zzZBX2#sz)QjCG~fEz(!%w%meyTb=&FRWFWN}y+v&m%B3ml50s%b0;R5bHb$%_7w8cA(cEaz<_ODwAJ@)ab^F^C**P z#_PxDwElyx1Q@_K9fTCb4Hk{e=iBc!5h{DX$dLAE^o~G?xK3VK5O%X4$La4mKAGd*^W{x3S}0++Bh}VGJtOX}<0>aHdvB z*}L0_kVi-WF0CaQ-h)vNRCcD(*gOGTDy$=9rjW-0uMyo>>stn<6r#Y+-jA01pFg?E zR132>;?m&3gl56!fiNG(LjV7MI$^G?io@Vwp zl&tvPS!g2g+ayClKp$TqxQovMJxn;I$p!r41+3Rkro2A+63C=K2o?4C2cb82aw&Y~ zy1C$68uV;f(8o)ymlzhidXW+QM%_*=LvgjE?$M0)79TV9tShDB%6JJrd9@xljqxE^ z{A3i5|6UYE`)oEs3kg*@<`D!MD@9y*FEE=N0|YL&5^I`R|0MDfCsGUV7=W_kF7{`L zGtdUe*!O9vKgn8|uF;Nt&U2P+TmI*10GXAEZAHK{0yD9xJQQ;XP!%HVjZO_b*Y>5S z+wg1u{m501G;U{{)|k9k-G^Cy1ypaD)$~+p zE8hJD4hldx`s-kU+68|z_`a@>W*2_)NFZi?5NK9CC`Ve?1XGErv~c;J*!2nUcwK)$ zDu8;5Lhzh@f}fkvlDkaWW8E|IWrsM?PI*JhmOv}#k)qyAMVFa#_iW`-FJRE7m=&!s(OnBpSn+47KZ1e(nFo(16~>oEuuHHynre=^`VZhTHqc1c#x zz+*3F<(M9c=bc*6#M4Xv%}x(p4)|@h?=fSa$&92&2UX_*_ znoSSaH___ig$n+L^Af@PeSiVxzr@4*1B7##52T2bfDT;Jb&L0h#Op&~P#5Vc51I1B z%J+P-=1qv~7l!$N9>(Hve7kF)|6G}VrulqzXZaV}@OI4d4^fs+<1WmUu2!H{2_D=( z2S={vW50O|Jk%e`cSq60dvP(HO4v=!c!VSPpYsE#uNENeu0axZxpcj{vI>jmmsq=h zx>n3e_@N#j6PB?pM|JhBU9BBqOB|6IGb*04#xI%4R~cb1?Z%4??9w&>Nxx!NzhhF7 zk&=Y^)P{Yw9u~P-P;pC>@Cd|}t%_)}9!%T; zqPC5yi+Zj-&e{Nw>dV{gFUbx_2*(Y`4C19NU31^D)0+?dUXNQA);%yxvKS_c^m!z& zb;`V{3D6zJJl;j7K+2qTBI%I=Ut%&-?Xah~^DWi|+^T#J95Zrf6>T@2&0?((O z;g{lt`4A(EAilvLe(DMMz5D+Njz9ca@N#7kgJ*SXBR39eunLlbrl7>8I&rrEN#`Ww z%6G!p#0>QN81&#lj*P%L#tzESX;w)V5P%Zt$X;e#V_qp;Vx4ihGc}SC);|BNmvJe@ zb5}ft9YXb-+56FqUalYO)1o_R#l;O0)(0QvIVSUE;7`{^gh3L5f5J32q5J$8KH-<) zU?^Mdrbi5Z%=AUO(}rFz-0|djf7|}e8;hL0dm08OE~r+5$A$NSN7JLZ01rFyFtrcF z|Hs~&fXjB4<$~Y;uepXj4`(FgBsn1=BqWRhnY}G7aJdT6_Ijb)z7A2lZ;SnOKP~F* z=edgZwN>oC4xoTu#H&{ZK@3VWL}W++5i>x@IXOelwD;M2*F3N3@9+Ene@#`jcLqqv zIjIFJRePV>RjXF5`rq&UhWE8>a^16m>i9Iei7}7lt5o_Ru|5oP3Hxy~p70TdOBwVt z`BNd_a;@w?umv}5x1-xTtqzci6>SR(^I~D4T3@Zg`{8M@J^z{T{!m!UjII14E{4m* z@*UTad&w)o#)b#AdKLPe7KDM1EWZWEjy(vsJntqruzE-~%q5JSM#j?Sx`pMMZv2f@X^pgPE%bp)ghIWi_0egfXIvp$fHZ+!7ah@BOP>fZ#`Kckqhy$XUl z@MBv8d8`C@fMstcThViiI@7gj&_JZbWoWe0b#1AMK=L%PE@B3{q~SSgKAoP&C&n(+ z_!-wCJOf{yb(wh44SDo;R9c~uhmQe*hljU-=ZsSSWt(etLKUP?a~=s8arW3Vew5Dt zlaJg3@BY2tgNIK%h{ugVRR1A}C`UmJj|_o+`3S_r76y$bM6Hvm8P8q;$D5OYPYgd9 zS<8c{$U(5Oc+lPZ04cLiHU3!sibzU|%eJvJcq7!Lj zYbMc~f4=eelQgL?mQ5ru9XupLNa(2upL; z2X8uX`KI>Aw-;Xt@4Oo?R{=}E$PHteYRHb`$gD@XT7l}ti_)vR-E6^dG=#GcpMle- z&cM}I?uXKnk*49JxLBf21IHZD^PJ>vQi_%9JkMlxWp6>Qwx8UWcCakV6iCN6eDS4{ zK(I$PIwvHXeWW1uLJQ!1AN@M~{vW&-HtxL(zp0@D{GcHPazxNmsS9HFB1-cUX?mW< z?n+nUegIhWn*g0-DF`u|D@Q;Ru%~9bOe&X4#!g_JsN>4oe57jlOlJqyF(_*Hn6$Q~wEOZLol}E)SHQ*dMl!^n zDbfbPL|XUpY+pOxf&cUWdJp{F$3F&fe;conu2d!@TikefQR*77>I!goRf0bAx8*E8 zUpxwxxn*!27Y4mPaFZ9naayWeb|sLoj$jkxZsV!@f|_1hqEL0GR8L>K3@W8UU5+Va z1E5fsVrj~s7ZOW(2Cu+dI{dcXaVf4-T02Q(gB9}4(>bv4eMj2(iA;$Cd?3cR zG{h(!iSTP7BD|e}{;p9KK#dngP`t|x=)QUeZm+e2+X(P!cU>2jSC-iFQuUrg3-C+u zG}{RHzYJtNviS3kZ69**d{inWCC0O`0JWVR*v7rxYRNR(=~JiS;?DI591BwOJpm;q z#%Ae7ZjM|J;mi7c(zMPp2A`S7s1E#Om5Xz8{)wF~1puV{wpvAYkKnc7W%KyEZGHTk zzy0Dl_<#TCui(pH_zaA8PT;W&6uYFcJAX$DFl;teLn0-`CRF{?(IYHngdb0 z4`6sf{Y~uaH$0T%ju4UR4=n+<0{x_x&k~`PaWR%D0yYAf_{djdbu<|mXl;BgltTf| z&{qKo@*D8<*h5)P1FG(I0(8&JlnfWjOpYyfMl@fqf{3y$pk#sk90B;0;Q!HY$2W%X z=O6nDy!UkOD?5QccrjloR&O;JI4?YvEcv#Ut>0O*O7Z?t<>s7-%lbaarFV zNq5Hr8{Q2Jat=#Hupig8FM_ZFPp;GVe4@Lb71%!4peiYY2yzG8Kv$V?!^zXRZab@+=2t^3$QY$ zn&^_+dz6^3Xu$WQ40KYxmt^!#Tfx$vaO%WrSFg3Q{v0MUy87=ZC^#@L;EF|%>FG!M zK0kONfM5OHzlINg@V~;~%-8WrTS&fzX7gHf#jN6wJ-u=hl-N=g5A6LQEL^Oed9dd8 z;{kf$H%}wrpOf|b0vyp8m~@5nmD`?_64W#JiMx-;y3TjAT}{BmwjJ4LK^rl5KVs51 zK&s;jH8QtYp)|gllc&$Zz}FzNowX_l7n%DKetQQYrA0|8Pi0*eJ*8JbQp8y^+2dOi zDcrg1z8d`19bbgM{nVG>p?kjsar+!Ni_gH%-+_39J6Sk82a(w?qY76bcLnD6T?K3V4?xLtVPj(xw)+h^jtAl9*wRF$T_1QfgqSh}lF?DO zovEw<^T@CZ;OFmC_JVZx2Z8bupmQ;z+C61D@LZ9suw$t4{}H}amBtedRfArw3MqC( zwS78o23O;KmXWy#ibu8Fim842CpHG~wFfrgb6>g-KK$ViL!&XkVCWR^(RuvreF&T1 z#J5f+L`s!VgcwlKL_`#Vu=nA48YxA*@;X#k4oDCSMyiIN$rn!}B^e;*JK)pPm)B>W zc7AnQX*W?F4W_xYve3t4W(gblI5TDRY4<)T-viDwTjrGX3)Nl0plH;S2=GXO9X7p; zk%<1XTqC7Q@=G-=+Nh=<%XGI%-R(@~{X^g9joP-cwRO>`)%KaIYpZ5=Y4ON6E|`a( zeE`m0GLSF8#cLYDUdTNn;Ex5q&lvB=6zmw(suxAEMgOj(q%f?<4+&3?jeCUGzdr;0 zy$;@lIyFsDa}Y9&r4u`_e5o_wlQra5w!RMgmdo#Y>6K5v zwEk|}^RJMNjPL*YIp?-k-+6VXH}~q^VD)GZfqu{*Ncmn9(YjB%{XG{}kX6zscdQHf zQnW`eRwmP3;Ch@YVfLVJ(<}hbtYKAINsXilUB|B=hOSfu?33wy_J~T6pS`yM@BY(I z!bkt}JHg-n3O>K1E4ZQ5w-Qgr zjWeep=w46_j&T6I{~&(QWOrsMbwa!)4+1KWK(M1xw5)F2MZ6r!;FK2deZ^8tNY-V? zLXq9rejzxbGtWh;yI<_kAIqvtF#D`?pO4w*CaGmff0F47;04)fb%u=WxRW$Jo6i2n z=ke8uo)WqOC@T4>^N|F>v91g;A;pvAoSqR;CP>R=Gs^2n(hd-xG2jS{fzj@?`Oen1 zv5ouM+M2Ptx^l4DEnSCCbxDB!sU6|qqx*~U!DK#GnU}zXHY-6-F!%9K0Zj7^F8Oy*LR1d7xzcvCf|<_kHY9s5X8$p zq@k|uK-E=?Q{vSgij4iM&T*F3JT0#3&O)$MbcZ$?K~rgLy}WAKdQ#JS<`Rj+B+Yue zZ^t)%`27$31N`UrybBt~KaXGgt%QTgu|qYl7U;QqOC2=Lj8ke}dfp>~mam4zXFd;} z|KgXx(QB`f?}-|r`h6EF)hc-9GWgwPnd(<_`;Y+yS?b0EWcwII$S!q!t=P(%_{LKF z<4m)NcF5oZABIEagh#9&^k}7&MMhAccT{%7wUoZTXQ_#X@#o`@Lr?p`^L^OfX~BuJ zHTdd155e7E{U#hg_7Jqse+v)n0x;9Yz-JRrqou%{jE97B90cb|3FPtcyy|tJb5H*k zHu1Bk?!iT{99J61C}Ac&su=5YlxBw}1$6Qy5DC^&vp`IC=)>-P6XWFq#_~;r<3XjN z$27B)LJYY%{Y3GPWk)RXfndHSEyl_dED`n5{T?hEl~$7(S{^wUsL6mqHXnkt0}eT7 zERiHcz~{*HDFlcO1jW(FAlJQ}ogJrMubHjpy4hY_IC^}`zWbUrXg}50pfF~080>y9 zKz5IS&wN~1{6H`Q{812cr7G$(1b!Zcp;XUMDSp}D7u&WO+XjCRen)1Ce0y!S3FmPC z!$H7*l2VGeu3v+{zGM~ZzHkzLWvf1TE7kDp^@en&T3uZeYpV;#4lcqk9a+Bo!E?%bYoqaf)IOmHy%?#!uiR9o-Bi1siMKd`ef# zAOKVkK&ZR;sjHu6#`jf~Gu~dKV>?JDKX&Is@P~i$G5E^gycUAOo z{1iaMTF^&!??>8*fKLUdiA~z#hH@QmG}=(DVxWPHh74#(|DMiG$)tctHTqFD#pW!{ zoMi5Ydw;HNAD~YPhInf3Kh=P*eC=D%=?q|}(Sy%@@oTWXy@P>A0KMi8VtN~FcMdGE z4Z-MPe1#>|&=%s8ST3^GKxRo~&09JT2HH~CmL(K!S23Wv7MQyxZF?QBgjZ5xVI8Y$ zAkrgrOr$=_*;JdDQhv|@(}ccWmKe{c4ASm+P|lISdD;Y;1xj(+qoTl6D?tdJ*cgqy z1d~jh>HqO@Wj-c~ngWT>fgS@a3P|x(peNI9$hq&y&i@z;>DOSIF^7;Dgo2DkQWHS_ z&lJ)t0&!A=e9-SY%|_F2)LTxw-8Oo?{?S(7z7n7CDXT?tY6omwHwf_O5$qkGSbii- z1brt6LSr-vNRNPxMk6Mr#QlIF=nK;{?Kl=AVF<&rxQXA{$g)}I$eKM%@9(u8U4e6r zAsp-boKlIb@3Wh}aS@I`d;QV_{<}}Z+cq1cpKml8tWj^uFVEWAD(v6CQaiM4{L&5k z;I0{@KlbfP43uzxzhzqI?myN2Os$11eA(6Vu8_{&$H^F;?#idJYvp53ELJ^+zKx_P zDlKDGrb%|5lgJM3j{n>!{^RhuPkj=Co%`_#&*Jl!5O3!YkXp(vm>8KH z8(TtvUsJm2l*V_~@$m@U<^6E@>KowM&$$U!SC$cw9BD$7=UC)tPFe=#l7}p{3cgXn z-|kG-#wnAKWE13^zo|tAB3aW&>&K8xD2NFkc89A9*p>+vzP@KT zfD0Ox;k1IDGRdKicM77coc=)yjG!_oXD*K5#Q7F@HiLWaKLKC8_cUC%a1p=f0qoS< zaN>cl;pgW_#_8ev9MsQ%=$)2eM!NAM`h-FRa0GILH1k;>;!%w(&QuA70xCQ&vQ%P{ z!q2?inI)v^o?TwU_h3sPHI%zfAq&J5R~t*?Yr)?!?R}PWrW=nn#h7v)%bDaPY4`+j zV>uNOPZ-=Jss9B0W$ivMDV^#_a$Q1+fNPh;%!aqvD4CThAT{<$%Lal?yzjz%zwQe( zI2T+S4JG4-`XV4R8nWHPQ!0HH4YHsg`95#ATO0`wZ#G+2uh%m>{p!{DM^8!6Kd}u} z1o}B7oPUJZtQ&-kkHXj-`2ycdzy`w+9}Y%rI2iH~-j}9fzMotMp%AfT`L632u45UV z#U6Sxj@!J{7xk(GcOnD$)82@^6`B6eb$vK@yawm4S-x}>oxXMs-n!Wc-qxr!z1mI# zf-r!Ul@-{xe+>>STfcVm)4Xx-JF!voU#;c7AA#hpq`Mt$LL)o*TRJP*8kCxUzlKuHrr+?0xjf=U3^A_(t*oQ@!Xr1M7~w84!cTno*XleBx1=Fb;T z@=bhsH#^8phQwN^XUrK-3gl=L2r+g|jXUFw|9(8nko_)9)Pa;kpe)-&>1bve9*BH$ zKF*aAino&y>_-q(=XQRM9j{W|%aY9^q+YCMQi^Db&v}G-N>( z#jM-y5!)ZNS}nWV?K-`IfB5)CZ|<7)$DiUqSyKmpWcfQ|(Sl%KCh^E1f|Vc^zY&CB zBKRY_r@$pPeBZZ5L*E$m2gLCCU^q0$Dbz={Pdyj-juG&MjC(xSFn$N(r=21ECSH>R{Gi`|DWt>y={($ap%J~k-e@1H)u>Z{C>C(h zM8IbUR@`^I=n8n}46?s7+pDfO|NDnG`CF;}YuYPNby=#j&$RhVGGEWMNzW)yth6`E zM)#;M;EH7d%jLZt@xF0x1i$mX&%lR2@Lp&f|FrC+XE8EMGQ~j_%mQ4;1T~K}l_H+C zf?!jH*j|#LC8Uswhrn&a3vYcXyyWHI1M~B9vN4eWQOFMYNcm6T%4;e2uGF7^c2d4m zR=U$bKg8qlReE2JRf$8^!13Id zo`J8o43=94(^3-8X@}-$ zmQrU^1A(N`FAF*#73@*WJw#3RA!Wu`Hj;7?341ge_?=FhocHWjt7G+hqa&?>cLbmEagXom5=ix- zE!kE<(WBIyVk#5(r~(1R6AMqhiC?)2?fA9(Wd!^(0>14>%nHKT@`KP0Mm{oqpFrLq zu=jDtHJ$mRAtwh=rFW$KlO5X@m5LXYJcoNWJ9cE<8qGleQEu}td}0{DuXjf9_7SdM zjXwMy`I!XU@QG_z;n-94xc?Cu{)Jlj_FAoVbbD)?Bq(uFufl-?`{CeP>7CzmWY($w z9S;((tp4;@?%)1{MxzVvT2+mO36Xl4ah8|tRpV#G@P|m*=SoZ}#_g{Pm@n-P_7^(< zANlkH@VoE&Gx+A`KMXK9u2P^RghQiX)U=C0BSK`IWZr^+&+L5?oMYKdPAYkhOf6q~ z!wvBASG^K$zU3w<2-A{oWCJK@2gk8I){)kAm%t$HTMflnxv|S)s7LkmeI^424fvGe z=jMcZ+_a4(UBVC}Z)E!~eBle>;>HCD@C*UkbxM-)`v~?ldfIB%r9Ey3nY$Qvq#du! zR7XPy2TfTnh(>*I7Lm1I{4xdt)Qf<@%hHVy)V~Er^&rqxQ%vKFw1SQ=JmW@aKD66OOwU9KUMmsnOYw7nFCQ1#jPK2DjI1&1GWv1o(5v;;1R>;ClI8FFP{p z)PEwj7hY+;tKD6C^*2xK+-6$_tS*(*$e3P6Lk;*wT(sULz(24+{@EgR&>P3mY&I2#6!mTfRC0u#c zmGXsO@WSU|5V#L0JxHDTzfIv+tkso}FA@F|%jPmeY<5;iV4NbdN;!n|3ncz;s$_+3}8Tg@5hKUM~}2KRpR zqB1>b4dFkKt!gt6KiBh(WG496>H|1$8*t7u;T~!N{B9iQJsa@)tv38*qcwaziO5jX z9x*pc+wR-H&JL_q-~WoM;Adv={KReF`yA(oE^NEv%$W^b0S>~-qATTH4W<}BjpIdn zVI+b@v;EIp1~{}Rrl#}hvG<+s!=HcrYw%w_@E36I{x2v)oS-JHZzV&NUHFEqqYHma zf{|?C!{3uIjF7_r4%~3lEpYo!{}^0xcoDjNwQiE6@Mr`D!4w90r!_U2C3JI_ng)kU&H{p5x<4KL6Jx;wOq3;(QbD2bU`&Qr>G@NGYozP_Og0=Q&4#-4K`fUUh9xXZ zm}Dx4|8D94fF_k}8kC9s*d7cAQM=i;YPFhEuQ&X)Zf{?+TSm73*g>DZ0SE<$sD*;E z>q(mq4Zz?b+Jehqfa+g1zC#!P{Z-PzH721Q1bl(49>E?#-}S@T3&O}jR$mT+$O^*1 z^#k7vMu92o_#@v4{1M%E{ZU9W`Xo0jn--Hij_p|H!s2|ixU|UT=E@(NFB_k^;h^=k zCv*KXFQ>))`gOSXcn#{ffS+v-`KxK7>rWhJnC&$AV*? z1;?*jePYK#{`msDzTSg3H#`38+MVuluhWCJZd6)aT7Z4~*5JTu>76r%|Kx0Mef2W? zPao@vb7wCg`#cB>bB<*EBm+w}t)oEstdr;a6{`S;m&DW=@?#qT{LXtn2_OCNhhgKv zy8!%)Qomj3g^*P9B;$`m9K>#`O(|p=#fRq z@B;d$5lBIg1XxKOj?$#e&^1!LA4#Sks%~<;Pd2Y~KbFEiF-)r*7i-8`txY+BD8Q2e zL!v2cOm|&_q6a)3&(8K1-17YABjewMW&?vBYPO?eq47tnB+r2{YT%pe;C*D=)MOZq zq}Y%gr86oj>p_o^+9kFOpg12wgn} zYW&IwP^$r^K}FVkko7mDQxDQ<&X6OfF;i^cplN+N4+b^$#X%IdS`BY&Yb##cUia4< z%@|qnv%k6NeChgqu<=;F=lC5qf{1yclF8n$uLv=GM<{nY7r*i@zLgT0 zL&l+SF)~4xAC-~Wy9D-r5V#mrJAqGtk1Rh3EPpsEjeH-$KD6*LP8bD-?hhvS0cmPL z=eksO1+MjCX>ozi&z1jbp<;gOxzDivzbAX`GcUKrTzBpN=>uDEPse6=w+80#^+yqP z2(!UJvH)^=x{b?5C$(^5AaLwVji1Lw{}=`V=WGkkS_a-4aNgojd%R_V`#0g%_5fbp z9m0z`eg8GxZr|&5yE2tej(LV@!1C%ctl@rm)%jmvJZsu}Qn%N<@X&KVe&>mQK6~Z@ zm{&dnF+zb`EG=}4mk?AE71K!OXB7sc>Hxzhwl6iTC$U9G1TIpwL)tdPo454gj3q5-1eF$5##3(&_l({ zX{iiaS}w6Hg>&d{Rnw(V<9F_U`AM+KRR9zuke7g6k&R)za!|?18vF1ZmB4gt6*#f1 zp)pNk%aVDRXLf{!`;@l4II$o|Lc@Y4W)@BWR6K!Rnu)x3}ih;roz7#sal*N|yilI`PH zj4TX<2<8E(nRT{PZVs&Nt+IrW1K0eFGAMN-1_!iisfO&oh zB@)aDg&fu~XwU`!*}{*?!q45tW3%x?cVpT`w+8o~s>5;Dgkx>Xcva6gez89cWVi4LXRsNOIW^;1Dj>%cCH^W-tnl4hH`6 za4>>?zYl}KK-!Sf;_Z1JEUhfT`s&iLgUiM*-!dD^d-5|w`}sY`uUb3z)qg&Ds9Y{1 zt6v4rQS;=qcw2ZaJYxy82E5vO2*#iP`X+qfLw^rdSEboS zA3>|B(&W^r=Nyvban!sg%yoRy1z6a30Dj;He*oV6FJFGw_un%A5}7&JhC`%mC&vRL z#qvqgHtEn$0Gt*{nuW(T2e|Iwmwxqu6aXRhFL|v|nm<+5o2C)3`js@WsNMpRQ*=ul zVaA!g81L}XHGgDj@bKwVaP`q^@fvqv=q&-GUWW2PsW(8`R1qynwl17CsnjNef`y|X z$l!(mp8_buRpkY{q(&FXe%z`^=1tcI*$F0>GAqA83i*q-h*s(r))e7_;MJ=BXBPb7j zxRETIN0F=mkp{jIYjDQ*>0p3o<1GSyY)5n(MJ@)|$nc{QUdsgRo@VytfLOjCQc9nG zCYEnw)Z#^y#s^_B1@(q<)HS&4*t}9IF$8?suT`yHz!lEEIzPb4-vS&}$@acnn<{E>QYQ~bufBo10(?{V`pZ+|wPyZ9H zBqvl_nU=GDO9DP$eHs340HS^`E(6FqVL{5>0;TcEwT#Vyvwl6i_KiOTKl}r)fggG0 zfx=3Rm*P=hyY(s7F15P#XkMaq&SX$ZnIal5Gb1w%3TOs8K)?@Z6b^4AnJyTnUHapR zeQgAsrS_#Jf2>-bpvd&cQ^0x96gf87sMX=@nKO8;mtb+(gywJ?NjL&TFu<^aMzjKH z?MuQ$VSgJJ`%nUU%nUiQ$Y_cowt#tuWs_YrXySYDWu^oy3zC z&`oUtD^ur2#_IP1JgFT+-S&pMjdh-y<$-@pkcP4~RJIT-^OTRJ1QE|poAfZ?x?h6m zY^+lIF$XBxuqwdSz+X643H)rAk-6!1$6`#_XVRgMPt@+m<$&`-K}Dd?K5VY7e3Rxy zkv1~soBWc7z(i0;^_B=z7LhC@`$WR=N;aegjet-@F?rO)ZnxKEJKNjg_V#wEQD5Ur z%S$)bx(hEt(EsdS-|15|FnS|c>iY0KB+(v(BKGk=_+2uPjZ;Wr;dhA~@bL8`2X`xy zO?jb5fKT9#kHtMK<9EoB4Brn(Vb8M2+SLCKRWPBKZk4_ z*?*uI65gk@D1NvStdp+jWZg(pc-mGv|1D5yER_};6`cG>^KfoFydQSn1_|+ z`D5$z=DTMz_)m@Pb>H)h(nmgfvPYiYrIN>_ARPk0GnUoo-5vpa^mAw69l!BMaP02S zAOImyA=wb3qi4OT4~^{fRzY-5A@i@}Hw*vRS;G4*T*phe*pqkt60AP^Cb<1)e;oe9 zk3Wx1VJ9kEq*;Ct#}f1j{AGPUVfr~U6dL2B05jjoAK)MNheOhQzyM$bj4}|@EKmzt z@yT@@r$Iob@j8x@TEu7-p2sq3;yAWi;Gh+A}qS2;XjCKmMG%1x86&BD7JJ(%I)@8UidgF_2tOJUth=Y=IdYBBXK@wa2SD{g`10 zK-qAnZn#OuPS-uM{cvk*3+nX)u-5Lxt%d4~PVE?4BO>q*BP)zTTLL};cz|Gz>ox&ArR?oc{cI!XS1=&3@Oy}XLR`Xg;mV;( z#vHt^OoN1lOpD|CZhD^QR4XN3sZ@;WT!qp7a>@Asg8i2(Hr#dHK7Q|0VZAe-PK*1I zMale0&h{>3|I5P=J~RldtA~Mg6c^gVejwg5BEZIlX5=SnQe^4AV(tXy7?}zQ=uw=S zSQHz2)Xy}A;*@MD<%vK7coD$-T>0Gcoc+P|Ie6!HYkFX|O}Q>s`QW+N?fc;8zk2dE z*R|pBp%w5P4pk4}8)tp^fBxj};gf&+DL8ZA7w|(yh8k@sn_FH2B`^!p$VHBM(fmD0 zx(1ubY`1WUI4GU)%(+!~)xY>};K$$kdibGN9GtqkVvKkgnaN+$^gxiZ`xua&NK=!f zt}k+KYn-!mj7u)Q_!zoY2MGGUKZH2w>5;Wv>cSFXGOYs8iUk6S)~|)}vPWTx6H|r) zpK}-wB_pH^myZERFzib(5E`}l;?>aaA;5=y;3W*2(zr7EvQog%;%=GXj1EZB z4tk!=wI|=jaVNV;wmg@{&ne=`-oi;Y*ASHqIGsxqYBYSa7%>3#v}Ibn&nkYYPb^+2#()1L}{Vo+I7 zLk0mduo-JI1bH5W9zTr1G%RG6Nug z`ECULJEy(h2e)9kGlHvnBe5_T`0;Qw5+mFx>lOGRM{-AwcLuKQCK5CPcggmtAuj`b zO5KNc9K{mwsnW;DGJ-RQMhx*d9m}u`$F&_|_2qKes8q^Exr`u>%)U}~S=qDytm+wG zE<14d^-mG7e_De66!w3Y-sSB4C}O`himYq=$U5W)?x7Jb!nl6Eg@ORwMHtX+$O7Fg zMT@ZNnAWKPy$DM+G}DkOWUgb^%C33WT#4PeRE7`E!2YSZeeaExA3k<^@wPK(H=t7S zFhDDb_x#N%_P#&wbdPif)QfN_ilh4J zr2nXNwquT~>&K8f(J7!SRNf0FK)GDIV(L0opQz120-jW=8;^Cy-isbkRL2l2wl6a) z9MU=cltJrrl?4Qef?h!?Uy2sd=$gnW>`88)%=;yufqZdoSR=AA%%ohB7~Ckf9ZhBY z>HCP|2|&+SKA+V2&%LjtFJ$8LP2!rID`FzMn>H?{wR@)RceB7Li!ZsZp6ZDaVaSG5 z&I75Ih(B3I6tTSWASpQ3>f1oBqx<*oH`mrXyfx>&{A7)P@yK$~d;U}ntkw{Ywg=*k z{eD00_lD7MI1ps9Js6Gz1^{d{q>(zBs}DHY-bPU%S-fQSVQAy`&B5=Of$z(qc3bJV zZ5WPa;%?cN>$wgFutvG$S(R!T0lsXM2<%Iq?UfMhUGu#akAJyj!M)e5vwNS4Yn?e; z?hEz*V|rKV)&_V;?td+ajO8FU4hAtSu=tbr{1Ke{D)m=3Ae+C&h0Q&zELekWi2WVC zKw45pmm#Z;sS6#dz$@$Uve$ec{Leq}gM&A{Y+q@w*FL$8*IK}q!$`a8QvF|A`^6IU zWqn^}m_iBenXIZ>v=hLOWKT(ucJhl+0|SuhYSdYSm2%b-+C@%D%s&E~SE!cd^z&8f zJaB-Tf#)pGXhkYsldwm~Ik-*hCLag;ydVxFjca*Y4mpi`4ZP!EpWK%vIK~SNZ*k%` z0FyfR$+L5oh~)`sYRmL{)Y^2q6r+^+gl6g@VfRc4+GMC5=@CL+tf%V$NGQu98JdXX zTGYof4glalAHUX62pFJ{C5Yok?#|Djf01hH>(FEDF{;-ot3^y0GAZgWnEnGL%}e!f z9?|Eb<)Y0f%(D0>l!`xZdis-=8wNQgqxdv z_^EEUANIOk+gFkC$I04`8nrJzUScM|hmH9{725bzshhYifTLOSC~8C`on zvimArf$aW=-uycFu{Xc;xz`;uA2I0b25@UHfWIVt0NJ=FyY@rbxlg?z36Rqs>k+;L z=tr_)bOgh}Ku(Cr)IKsKF>C@OrMulWxr&<^@JO^WGqg4MRA!u{zh(J9H=C8Fa&wsj zF;-ZZ0Gu4aup9`=2DuzSCAIma_MHR)nTd`5+r%z0tv4s-0Fea;$!o@H#ys(tk8^Ph zH}bN$AlZK*<;`>#KV|krA-bzGmeq)ek~`8@T3(6fLli^L$!Vq}Uy zTs2&>$)IF>mVcbh=O-BQSplxg32Atg>yIe*06@y*(}rf%$e2WI={c4y`bma^5rNl| z#wwd(=nO=t)N2fC?F$V&nUSFRePQb37Sxy0Y&6`9+dJWbdV_RLjAqGs&HbC~{0;ly zetO(J8}Oo97hchBcjsHJR?um6pw;fg?RFahzaRJd$oNSXcjQxgpW*k13)w9yNFc~I zO^aJd=WWY&9oII?r4liC1p1Omw+QkKe@9H;_B@y24MU*+eb45nJxko@nC#p&D{%f& zSmS1(Kig(oZoBS)dC$$)@4xGTZymqY@ya3~a~#Q2NY-%$0D&Gl-&6}58RHP^C()gF z0I|6QW@QP!{|#@1xBcWB-u22G7k>JYUhl-VtU=z|9m0#r)Q9u|sQyTerM@4^eTa+R zNYx}|lPR%%Ig5{vA-xA=FmfiIb{Y+(+hKnoSw4*siak*ulEgOTRB2QyI1%dEC3U}R zjycCd6R=3V;q&8TQyFL0Enk=%NE*ht2G+!-PFEjP%RNk_;S-tQyrNz57?CI&Ccy*O znFGkC=cHa?PBb07&vr{vdmllVfS9(3;W&f@roFdE0-Vm;7 zG`lZv)apUKUKfpKJ7_iAqSI*$a-$@BTl`K544^rNcib>dVI#`BUdb+%JdV4GY@Wd0 z^hzGp=go4Zgbd%a5$Kugx~At?3_<=~i1(*F6YjT7ICpfFfSz4aYupUUAWgkY2Q)!;U9T3y!~fh zw{rCw+f&f#_?GmAxV1lmn}$C8V&9Kt(`Kp&dHp3}St*a?Xpd$2m90Qhi*5{;hbu_{?3oiz1 zV%IWY~+bMO#}t;r8|pH0lim{I1_0 z4Dh?+i!j1~f^mV5N1%5AL7h>GzFMssl}g1bmpx8E?|GhqAPQb2#{ZZpuIZL@94_PX!6qWo7kzqGe~aR>0*Pws8PziCcr#r4oae$%{ts`4pZ}5P>>Bo;*g;l5RII-5!%d?gdVN63f0UxvS`Nv? z$cTOyjHH;93(3E(Ob8@jKUd&=td7%hN+qJjWd zploF6eBfhI2w^+^GNQVFBGr)`i#EG4@)H0&HwGAwqvSMz6sd3#FRpE z>XDRXlsG*vJRdCP1p3n+0M3fRfh>y{Dq+DRVHy_R_tl67iTFtQh%n^bLbe~uQdh0E z%`RNH0CRJ5G#?*yyFIG8Q*hvnMt<0AHp8v0ZJ`XzdI5>*;CYEl$nG`!i@aIt+#$@$~Z=~Pv zv-9W9gJs!r1aDz!!E{|WqzM2F48j4jeF~Uu+m0Nf>Xu22UAV3Tp63d$YFoJCd!eO5+?z<9hyyf}uZ{PYxc+2-5*p2He z_-lLA^2ZzVv>*Cd*L>cRcPdzogMYkxMqwJ@PcmJ|qAUradZ=3Ud%`7E*LV=WJpVB8gsU!+f@val;|}vG6-Tp zN_P=Hi%I9Z*=&f-O&3hlkmD0`b6`2H9Z-#+R4#|O3;Z|3v28}o-Lfn}+V?gBKmJU5 z5tJPO*EVtI?<21j*ML)0pGQW2>c}z-F86h92KuvYw(XVX|K3~f_{86R>UE7qokiW6 z1dRjNJr{oIf4d!C`n+ep=Ef_Wsgj`I*nnF%8t}G8XLMV;)qzH%A=B`kPDeG`Nzfmq zTKQ3|y76N@j;H3Pg`Uli(oTKF_I>Ch;Exda$(ES_KOD3{40nJJ&Pt;i0nsD8Go8Ap zQA0T<#?!X8l($MpKsFtmr?CBe>s_I?J;wZ}*7W%p@JLyDo*C1mOgsUxLGy_ zWpik-dB1IxcxpSP19=38EqJgM~qaX&Hbq0GJjRw#n(&@1{{|4fLDWuEO!B z+nP25{n<9#_SmjDSpDJauX}cPXS)tiorjmaqTyy-#R)Up_5BVKAvw$g_06 z(ga|tE-o^FFPyvdJxpn&+of4j1x!LRePLuXeOwLFt4sq=5-mbY6vyhEFwOE=5|NAr zVq*L<=DJ595oe;yL!aX;kVx4*HOB#)VE7_6I+8Q`kQ(=3A6;i%a06zu1Xe=R7KZ- zCm=TuFVg4ak8pfxlVXm!v!wnX#RZWf36dfMZI%OC4zR1{eR__^M;a5|0>jA8w^qiR zP}pNpakidX6~}{^G|itIEKCC=?VP8ERaL@AvvhL4m4L2?JD3vQNmKZ_+CQ=TWTYY{ z=B@>Ilq^9kYZpn+1ta4qWajdek#gQ(&}XC32(dqupg+H`AZ2);dE^QN{zI^~wnCsE zR?6;2$}ZgJ*>I0*!bzLM*{4H_e#Z1?+iZIRx2yNtwX63Zyk)P){NrhO>-l>4j_sYs zAu?DoBC4BWEs%M`MiF1SLD0U_dbD&$>$k=Do~UKCdo_Y z%sGmEhEq@LlrhNUJS2~y^gRJ6G3M0SFW*e40t1P^ER*|HPs?&+cuD~<5BNImFS3FA zSn2iC`!%@GlLZNT7wUd0B9L4|LInYMra6dwFr!lW1~uEouImErj_YvOb(rnC6dMrO zQwdDy-5@cYa=8*NEG_c+`FSxvS7i%}3$VK6{>RlSy!YtxOxk<~`m=4eJ&D`rkHc?o z)P`@X?bKo8!UZ^g?gE@WcOEXBzW_V68nha973OBlRtqRz_OZuv0WgO03MrfD|}*UGa$g!J_LZI z@-W^(00rPr8}{Y02s^q)NGr9{%o6VPr`PpCcKAt*l%st`nO*| zus?g|oCN%nCr=^M-+awP_C1zXWdw}RyBD<%lF_?~ zL4urs&!mx>coI?_#+JSW9F7HuejAE9&*c&5OJj9wY$$bVLc z#&|4}?ny3d^@3BKpYxc;;}E=KH3wggtCg~-&Q%2o;8d#e7N`T?MbLL#o4}qr>zQpC z%(eM>$6*gz9KJR5;l-^%^pbL=93!izQ^hwicJBB4oHQxs<|@W~Zvna$>qU6*cg$9! z8R*Zp+4h8Q1o#^}z1z1ox8TgfXT^yVCmAvPGY_AE?$$97o#VjBh8ICT8;6Twaw2;V zMm{Z_{%yg&q5B3Lo!VFB1Xa5?GF85UFc0jS!k>E7W6f_9o$2`*_g&cj6oNe6w1?$< z-g8Neye?k~y5o(8kgIL8oY7yDsr|9MLLX$}KB_vPd2n6{kc!wzia$3~z}S>GmKg7V zO7|Q2ecN+o8sD=GD7);=k^^@l$Upe3 zb@TlBs>yT`5hdv(;hpgFbL$%rxi_1&AGhey&fo*=%b*nQM(;4W` zw%PWCF?{eIuEB3^*84xTy|oSJ&!0zze;Q7mItgb^pMlPWdx7;H#Km`{9qVGn>V=X` z6*7hY=o;=O+5a9aej*VprogDsAWtr$79`5;@^83yZqdM>G@_*;z#eLR6RGq>rgoR~ z{%$~D0Q5wcCeQXKjAe>InhNfTY)(F9+y&6oXCqEK_!M)GbU+g6Id?A7>_D25*Os_k z>ilT1PK4+P$YZS+AhPcG!ucD^gd|GCS*Bj3R<_fEpYijQ&nC$3_+(tL5Ex|rANea| zVj2Tdn_j8RoHkK1QUGQ`*5(~oIIa_WUP*#Evhk48_6YQm0{T)^D!Y;E62RlF=OO!d zM7dz0Qt_B^6O}P0ziW5? zquElu7?ES9+OIzCz|VW-B;$LN@s7w3AjBHr^KqBRWeF0yJzhK%o&*{q)7_^ALNV@C zmj*`3R0B()c0#v6A2(-NYJb9V`852yddq)Pr_~Y2 z^4Z3PO*nh@ESx)c0lJ&t5UleJR%GR(!0a9kPk%gHUbB7LjJ}#vH?^Z4pNtroku%y! z0swP5=;uszrXEN9NXH0!X9@CUfM{={9sy%xaSW!+>5q-R<^DNom82)(+Pj`o`Y}G% zWGcfVK~n>_;8}xR@&d8W1n|Pd!Srm)G;FvB;KbpaW3j--V{u*T{`U+DK*&zIgTUYG_1R#w@SOX%*o$vigS)@2 z3|2sg=Q7I@-H4UeWMe)06+dEVF!}nrYg>x#*lLGlG!S&E-_T88N`+4u zoa=%1oIs4&OGR#6TR%CTcuKeaw2uENzmtDY6JjwR%Z-Ra%3h?FypSu*kNN841acHx zXG-E0SV0P*FxD4q*2@9LPix}rC)4ve0i}E!U?w}9$OIQHd^24INROT6?x*Klclv30 z+lg~F-mI9FGV=cQeClJ95&-$#AfpGbAN`ZVv+6#^ZBn62JorLyAopLu)nxX2ufkGU7ZYH7(edxXv^%1Ek z&3M*;rUZ!H%h%&x5$xpyZT0U`ZO_u+PmkBPiTDm1(@f6`^5l8#9ws`egWg`+`@8+F zprgZb1~LhNXEpPjM81-!P5w$0Q~a4$PSH(HGIpWr>2f4JeN7FXaWPSnx&aD35|{(^ zq-E1c#E)1afi%5FpIF$ApNE9;=cS4BcC~p0$6~O@$9gd{qaiM}=uJ=z+683n64+&J zey$3Ya+y;2)Ql%e%ktKPe!nvpt|*cg!ast83`Qtm*3~ z**5{Nsr}NqW_mCQ^aMvS1p-5)A~f$GDiEdsAkC{A^0^d{>p&vy%2)rM1p}6RoC10y z?dDgI>YQBOV$QOk`Am7M0EsZ@9JTR6%K8|yZi6Y0M z^>MH`KSG(yUKk?%Yzj8IT3>-{_dk)R_KZ)>))WPDG%#y1p8UDb1AhA6cljKWASaRP zrN1{2>}}~ZM~vRn48AI7=q1=!%Ea!e8IP=JNiC18X9d;hU59|ztRtiUxzZZDdh9e&nCk=Fr=@GxA5iC-V6LH!Y$O!liUxSYBLZjcyT0GaT zaGLAN)NZKL_ofOq$W%vzzO3JCt$j$c15+BqrgiKW8R_l~d}-%|iS1rNj zeVcIJG+~Ix<4~YNWe40jg1(^fy`AkEtIkp1f%ko1+c55Z-hTMNYlwi7SGLEd((f@B?p(y{h^o$Tr4g?rcayOz1sckEkFo&j zHcaJulacGZQBNY>CXxVz>G^!h1n{J>&(!IDRd(QGu6ny!;wGjv)4+ck`%m=mNqA=h z@N?Sng>*GnUGjx^iUJD*(hh#5Aeav6kBu1S)3wRZ0YaxwI8wUn38lo z*Mfn{UO?N^ihLs-Q%!wip^H@U)8zo!G$^vRjmdKx>mY~g>t@NP{Al6JC!|y9Q@E3^t_g=RT{_eZ^ zoy7Cov<(=k2?9@07NUa3-EMnUyWM5mJ3FjgEmIldD%)E6(fbW}=<^X-`o^O`T;u{gzUg5gtvt;IAJJkKZxQ{5QxEGAf53#ole|owRx}8 z6@yNP!QkTVtbyzCI0@>iiB6a$l~R|W@2K>?v=hzO+gak5qSM$>HeF5ftFpbEP$$e9 z{DjtfPwM-!6p%>6>GU)=($WFV=nF%$`XuFVm<6_(2mE}xJ`eKK8ufNd_2=*`t*47I z0isxliIjKJIX~WeFXDvJvK-6aC9MxySx<}!-l$nT{69}U=96e3PJHFL%1Efp0L#Z6 z^0ASCDJDItFC&h#MuKF@kh9#pJS(Q@r#y>R$z_>RUwVxCF}f*{0txbwrxZ8=I)UTd z+?-0^OIEMJpZ=}vBG4x(eA2?V5a`V_B?mrH@!-#&wGY1dRQYb=*JIN$VPIRFksNQS z2V3*~3Hv|3I_O#tj)xmD|;rZPW zdp3gozxE^W!Z0RX@0h$lLqz`J$QPr*Fdp>#+#ii#I2=;K`yg-X%D8^K zHr(O5d5}#Cy^J&bJjhQ=FjO9|4|Ps`h~+(aUQcN{}1;4?mU8S5+r&&?5XF(nvcP?$!@XFG)c zm?WD|%z+>i(PKK`qVzpA>+@vb6O~KO zEBTHGSz@uWI<@;Kuc; zl6H}+)jmb5Z2UfV-%ubK$7UgY4|#SX^5cJrXbn&ErKy!FV^c@I1Y?i5*5z4$3jR~Z z!uARP#FWBF`ZthS)pFpIf;&?5$_9wDYmoY$RMO}GF9N9oj1@>v+p9gv&rVA1k<>#lU)8&kL@_PA6&;z+N z|Fpl&G9b#)`B*;(*8z%@$;tg2PpP`fxKIGVcMEV5Ro~RO zkLdwTmWuCymfvN9WuKR3__D=N13ro85VI$sC%|7?T7vln#qcHA&#A6_nroNod)!?F zOwR_|e*yP9j_!MEgMG4Hxdi)SDnj_nK{JwpzSatJA0< z^Ge>2c(!!{|NJq5{+07EIMGmJdm?8rd1PTWvNzji+aXRygcpe7BAs-AzxDVo;oqAB2t71S<#`nDVvU@JFdv98YPdtv7BzC`(TsJ41 z;9X9@KLh>Q_O#lDp;!q*_GUi<5rz@5c)Sf1;4920wjYswC^3BmdjfsjM;ILVJRsnY z)XcmX6RB5%IF>ZDi6z5#5tK?YrJn%3yw$0FIn-saBKtNHmXVWzOK4@3)!lilrC|+` z1`IOopLCqZ>fcz3wo`z!kU{`?T+_gpG7@4+J$jm<&Th(mnF?N(+NX06$=3PlDszxB zY~3>ukIBsfn>bbmFtxWJ0rhMufI(hQr{LT-7C132lS@VRm`Az`A11OI$xM8#yZJ27wJMh#W>G3uN`YKN#?SuLt#p5A9CJ zsn_ZeO(Q3G@SE`GOce-WO3E$wggr;v9eGTsG)2SJ(1gHG_`~ zpHWIb0e#waa+#T2DXvXrx<;1r)-&DA%xe2mxFuGKbh6}~8p6boOnaqDzPaa_r0bBf z%4k)JX|Z@r45dS*P4_@m;hIi4}PZqSvva0 zRqdVYa~rcU=|s(2gasa-Hr!E)6QF3o|y9aP#{K(oznQrD=V$*JwK4k!0M0blMYi*jbXW&`@7OwCXhx-)ZU%DHfh8hMg|8Zo(|KXUNM1!bbfn%V< zd;Kcw_Xlh^@_Dn_ViXvaD`i$LyZ@8ta7y$4(PMcnj0gL8HIzu9@5zplPSqkeSyb@G zNxr(cC|N=<3$MwM&IQqB8sM=8M^^1%2KuvYwoTcBSj+`6dvk~jI#K#a@p^ebj4%oi z5n-lG>(fRle+2pncay*$e-HRau^i~qig#*GK9(wYphxk*^i$qR*J0n@`wVre>dtRuH-~P{q^LGM353ZwZo!UV5^xZQmLXemBm)Vl zID#eQMWhN@flc2gqxy8G28tLxr(Ydm#ouWwl2T8+_)RP$RwL?X2v<(cdc~`d)s|dN|7TXg<>ya+A|CVL=PaW7D4j>17zNNLLf68af zj8Bg#?@xFQ_<6=>Aqa&z3Gh1xd{ywN^D|$3VP5h_K8>`ROAv4)t=6EwUh9SGxK*)m z@EF)pqGu3SNaus}oq)WoT5zBL&e?s%xAUw%CpV?QyVE9A%(Z0K&}CI>pwPz`roMoG zBGRV@S-w{OqC5jztJS6S1>=+z;IRxMoy**kc+D#Ixa$kK^gxgno#UF@wHCB(4P3XQ zg>FIrjTXw;n)HH_o;S1U)kMICx9-A7p6d0qJ&8?)$%Q^4aM@@kXzjJ+zYusVR>~KG zlm+{q5Ll>QprS<&L3z^^9V#C^gPf+HZ&feGaTm#xtA4-CW1#t)Mbv4n2qYz(y>D%8 z3)tVd$$)=tPXHfeJpevR{xHfB!yMs@7zrdJ?d2aB?EhS9=nJpLQM}(R@PB!qzEWD6 z=Td>pH~KgZzj81(B%+uCUL55M%>Y!*jq z{`Omg^EK$N*8{!yOB0ox%$J<8B+j zo>u6mnVx9wrn)h`3p|4*;HO11T=`q=T12;AoL6-EJ=iPJ2p9( zS%(-@*!f`Qqkq54+5J}N-48uMFP6;Sh!w7hd>|<^`+N!}k^4-Vs83~y`^;N!sApeK z-{B;p7cxtq%xn6u^E5VDHi$;!k=fYT(DUic%=1FQdiUt)*lccYRv1|vq}%_|=kC%I zkKOoPk@~)w+5Ik`Q-iXm-{dW)-E5`s#e3Y0)Y<=ea_xFov($+ z=ezs<3kKk~a*?rp{DT!m9R5ye7i>tKiieKOfaB|VFsq5YtgQ(ud?xZ4ePHVgX-{>I zX|A8u!#-BPDp<5Ek;(d?rLJzDKauBIntOFj^23LDF1^W&Z7UgQ_uop$|fZhN6GtrSnIU*MMv>j;ItpfMPwNKBmH>H*GXim)X>j=>31gQ ze11&dc6*qwL4Um-i1pP&m(5GHS4i0&qjm&?}MWS^g3 z>{^@KS=TYqmmY6nHojj9Z@uPSxbB(VDA(E3x)lLLPhGGvw0XG-#;U1+WvO0IGF$>q zMJtb!>j8T^hu=PyUI<{?(Y%$FkJYbPNPG=zUy1{Zf<%{*_bvr}-*S?&J+$+U^yguN z8}ml)`}GJ20*%X$3d(tftX~tvcD6?JiFe#oUwA!#m*2iicfNR!zC0-CkIvIn4YGko znSV4M>gjA4<$11W)44uAKGqwU+vlKQkS6~{YRps59MhAJ+($M(??Zb4{ED-CeB31p ziu^UrE3_RQ6-DJdak!MEgux$61wN6J#K3vt3j%qgILy^@aVAnK;%pyd!5kPWfPNks zm&eg}#*r?0+xk~uetvSW2L1JVFtU70!@|Xl_PbI;gbaZp`aPwtZ}-};L* z_pN;4Y;dX9Mhzm~gn470#~b`@z1tf`)4bb9s_#@Mqj^Rx%x5=9(v+&(EViwsy9*{a zS1H}C%J?r3*c$M&bZH=QVYXa%CHVICp~vsSW3BXn@0sPO1@ZZd!O2yXj3x_L0i>N> zFsogBj9!VpW9^53w4SK9U}?iI-fQlM(z=)zb@hLB;h6MV5q%AQYT6mpmipZ?De`5q zeFSHoV^XzM3i%8}Ri+CfdaV|;nHcPo2nIP3ZD#b-TO;?=Z@=;S2K;7m_WE>|(l5?y z^(TrnF%0a{Xf)K5$0VejCi^_Qo`@dtdugZ)U5V1o;54?6Y04`4(P67ei4_u#L#i^05r^c+E)QlDGZW+tXhK_y|I=@N>}x zrSf|C48-OyPa+~ckfY5qz8KmW(T{Eo>8D?7qC3Br^|oC);cWlOc}yS72dU164EpmC zjYd;FInSaZFF4`P&B6WwXZa~g{5pOgQ$%HH@|_%EN2ialFj%K8!t*vbRHWch(N z3%En?Eb{7TIvzP|Ql)B4&|t%^)p9+!`_aR~s&c$i&6pZ>Zfee54QNY1DYSznFzI{H zw-WruYr41cy6O_48STg4EZN?3b@IFmXm`cxDjDj6gzj?H!mVJyudE`p^2F-Wlz&UJu0LeLCwZ>!A%VCDhvY@0};b z)=q$4M)?|sYy(D3b{EC5lAdcaA{%Wo-kY8xnoSwE~mLVjKtNnI9j)&O|Z%WcOlDeN7`0T0yyfX6Pi)FexPvK{a$XZ0{qK} zjcr9`MK9ep^1DlIf`$y)=wr59)WCv;EUAAJD%qEIm|Y>3fTE zsK>LpW}r9o`P^`}Z;G-|r>AEs8y@L+keHYwgf!myk;JGMzIsH5P~iJUfIWnK@Yy|e zpn|~XSSjNGNNm=i zzh1BV^_6|MX~D1yWW07}-uJ`AlwO$oVI)TCX|kg;jyu7A+ice8qsB?%#KdGYrZT(f zs5l5Ui4-(X(H;OaG1&wa5Z@rNoy=*(-?rdC^`l-A!n|T?%Z(b(w z7_pj9_BH6Q*Xw@qcP-*C;2)RdO+a7f=Fy+W&o1oIHk84HwJ-D8QWNtGJ{JUhu!Hk` zt@H`gR82kUp?PCZ9Y#PO*?qxTepxWs zqnuw6difv~MGW{62YPADfWJ9%TjR`*2j*9|QuR;YaWj3z9s+N>kwKW}{F%G6IFHrc zv^2Z(*t`oH+8XrN>j40L6^BYYvP5Mf2Kz``RW!;n&Dgw`=vo&%8v+0w*z?YF`#GCtQB^alneIzRV%QQ7-Othesa>2DvbIn=4LA$Q3 z>gare{{E@qz^O8fu1fE?*rea}`Fk||_UrUZzbn9(EZ=|3wSat=?c+ZT_{symjOBTj zeu+yd?wvVj-$kCgx+)p$IiZM*<-o*^Him9%BeUC?`MEZY-GK9-<8?DC*EFF&R+z?MY-H%AYA2bfAQZM zE84ErZEeTxZ;5}65zkf1ef{9Xt}e$*6@iuj5e1f-F3s3i1pyaI_phL}(bw8*Y=V(Z zF9%Mp2}V?yFwjAww|RsnNYOp70D!maqy4H9w9`^@?qy|~`FN6$WSkA6M3>b>(~WXgGIig{t?d7c)G zu(h4e%A(Y#C+7;&HyVTN(6!M!-|r}K4E*%F0se*`ia@RoRUv;~2wjLO0e;?hP}=7o ziaB43Qb95}&r6rj=a|y4;Mbz^h?dT1oVm^M&@teD`uz_N{=qlm_&jo5!2ghFt;n}t z4+h|uD7G``y9lLyZ5-$OPKQw!FKq2c^gMq`ym*2QU!ZFF^0<`t`O9hW>IG{1t818g$>gRN-c#6 zp+vu+Z9pyX<5GvnrOozj7u?xp9tJHM9yJ*vh*o7CF7|H*kx|KBW&A1}v40KOUXCC_ut^h?9YKQD^hoS#i<{{Gfzs~`YS zYV$8Diq+Qx{Lh?tVlbaNnf28~2>`A2**;4B0{C_4<(CeEU;un6*}u<8Q`sT7&+2z3x|RXjT~d`~1E7UKo)u*xN2!reLG%Z1Z2} z@(15tQRhRy-%Ics=Vf(eY|o)An^&R&xH z(WRA&Hp=Tw6V%0o<`a@~emk3w&)E1<11b)f)^B>o{CMlq{)+YJHqDDe`pvwiM;Y|r z#tD8@ltofih0gOrPo`7DpF=sD%{b9F3M20PUsUp{+HU?pU8lp}sOjNxLcjLT-IpKd ztKou&EZ=%yuLIzR>|VeFIF#6Zq z1N9Fcy`D_hpub-0^}ASa-KE)=?$XQyzRa~si<$w$N(Ss{Xx`CEY<25}F+D%(Ed)R( zoB&9pMzM=bd&=Co~}zww;ym*-^TF<*>Vf9rv#2LXF&slSg8%cQl1 zjPn(gxR+=7m+b4?Amp<9Ts9%l=>qil25!akuXy~H5a;O9jDD41(86od)LGmST}cLP z`u1Hv-z~g8l=~MdBd}7a1MyD#*J(q&Ui<|_;SZV*bipHG`L!&+Ch6&u_d@WM8!H+Q z#q5yIPKT1!r-Pg`KnS#yGOO>iLx}a%oG}{8EBYYc`RCT(?2GGNyYwt)?Ek9D)Wc;t zGG$qqinILrtTa_!BkPwQKLfu)#g13WpF+gvv#~6F1w)i=)ArKc-5?;{(%qec2uewV zbmxLdgEUBYOPACxNOyNE-LP~l^>IJ%_ZzNj=A1cdJdY>#ZZ;iTXSJhUv+%2AMKq1*nxxH;rD!6?$4gJ>q{5EWP~X% zHkHU);Pu^5EUMkD!xR!F+QV9=tShrG* zH3>=sHOt&*>U(iZ#|}t3(Vx%YB)1)fV870*qb@2yB!vVj6uz{GM5{y_flB9V2YVZFDlx#nTwy>dJ%4W(%6=LyJfbhnp?dHwwBCD1_L$M^`} zw{gCY5^->1=8%11Ia8(Ux}@6SYpVG#ECpaOxgFo1L$0@`ouh^+J|LLMU&^fl!-Rq9 ziyz|;?+^fRFUz8y0*nDeCnGXE2bBe*ee+);|CJ`%(E&l8VxxozZ+CdtGl#hRKi>Vj zVW~I9`6pwNOW^L@lvlCe7^BE@uh{RalWTWUNp}7$!0FpD)<~@!3GwZU!z;e(&(h%` zofOL+8Pt>LP;jgtnRrW9@sJas`Dlskja|2-H*(*?+k+*w&H1L39i4yVtt07v-6~t# zT3ok;>;DJoc}^Yjj&^`Eq;0K=K>hJA_ltAel@6#o9Dwc1Z#22!B#LGzrzD~%UJ%+0 zhh)21*|t{o?D*Jzc8Getf?i?`Jzl}%)Pm`8S+*>Li90VF>a$z9S!!>2dK$;f_H#e9_ax5-f!i>j zSkd>f5IUU2E$drYpbG{0nn)#{!aX%?$gpKLHsa|X6c;W<0Ii+R{Z65h*@rj<3d~!| zSqH4qS5SHd@M%m!;{OH9L9wgR6TPD(!ZiM#HSZTF*@#FhX0hG$@KLUH$aU0LLF81+3sdt;Bt zdd1!4WCCHLKy96O#iS}q*CxTDOvy-OVg7msiA_CjlJpPIXsu-7n@$8i><4?T4cyP~ z5^vJ*xM#cPA48gDMPGTw5!o{?+t;BbD@I5Q~4bvr`JJNYVVHI#Ifk zrxgBo&{I*whNNk|?>4#O@G9}tFTCH8^`CyJ+GFeImJ2fpq!yw4r`~p_a*uMLZD&CE z8SlaC@wYPSiX$_`bIV$!1A7qZ;MJuIVwY$_`48N*rfSnJu3_GOf8bD;Bn7t6-#F&& ztHfY1QNwq__Q`f9DU%>DzARS-+--`}6rpgCA`;- z1Ixdxg$CszyadMA4idHhQK@}$I?_2_49(S7BV|u|nvD_w+?bQAJACRq7m)!P^KW!A zAn%|#bVkXjDxEWCA=QL94mt);{vE|QhzJz1c}v>Izmc(&3hydH3aruxYH&;0|BTkn z{cYPx<@C6UiA%b+&2AEcvV|_eqM8ojIvPY!){A=h)uM2_WNALAo8a?NeJWhjO{BF| z8Vq_#<*KHT^*uDz*d9I%=OA+_V8l5a>`L*kA(H2=?!m`5HnMdx$B-%3+vw2Mnrs+$ z@y-)U&_@EE=EqD(hsv9sg z{KLOm_@2EWeta*XPJJ#0Z)1o!u00dIpO?%EWs0O#s8J>9c@?tH{MNrIpn)#t32_k4 zH=Gx0Rqds@x}9Ru<2iCnQ#jyd6Y!KVkT45I=(JTq$oMPZ7rJXOdMOI^y=*ghP{?U` zIL)%~NGGi`TF~TlXTd7lkn8$}oB*{faT&4L={SE4NDg%Qt?6DRK1Ggjozg=GaK z6^~yb(hN%JB~PHOfZLFtyPl!w^d4AjCMIUDY?K-^NZc93f!N>v@JPR|2BQc5|S zX55BT%5F=8o0L3Hd7KQe^1)olS~^_g@{n$Qln--rs|5FXQ{x*vxf4iAy+J7H7L&&{ z*<{HAu=7pb&X9}UTxbll32>#Izw&?)G;HTU{f=sAK~sX3(DqMkS-RB)1CF-Z?XU1A z;-10^oy67!=e@>?G9KUkuYF~?X`f!I6lb@OSpj07VXg7Eu96wyb^4=QAMq6(xs^_C zZxjyvxMa5mj>2zic7v ze941ylC%0B8?r!72aJQ)B?M5f4f^U`waWjD+L()ZE@oX_aOjPhykl%`XDYhFo5O=W zCNQ~8C2ER##N0=dwH1z7LerLRNJ9NMaTq?eAiy{x=2(B&mCHL{EKzyvdRfjQMVJ_% zeYTBgKs_i*rB-G${B!Q*dxy2yomS)RHlocVk)HSXAzBIWw@eT0gK%XYLqldNhNZ4DI<;e<29+hDb;$vD>aLt( z5TdGxy=kuEnpxV(PV**rfBo234{@(GJLE=>C)3955rVNK&ZpPCMf&%khkUyOYAm+=OMTvM1HJz^LjR+cw}ZT#hM+Xo-V_rb&AUe%5jvLHx%40rx4QMK7U zpM3KGNpYk`fr;}k!>xleq;rG8VGW;(bzK-T|02ka6~)k(%RP~NT~RVJa5T{%6vwSl zg)^x^Wl#NrK=OceJ)HG8TR&QD>_1N3y}4wy?>TYZYQra&@4>?3rL4Yn`Z`k`#d0N+;KCaxPZiI%t)a#v_i;>C^aqcdYNh68m$jHgC9W;qt9|hdT*X-ec^{(VN!0@t8UK8UA{e}a^~N^@Oe3&d*%$kQjvJG+ zjS~~9!@7uGJ@s%mZEj|}b`4)fr2AB)K=21OcEVqg@7*nN8$UPUu7w)ULk;e-i=5rm z+EgNJfp_MSB}kqHdNtr0vBjr6;@_{&p7Q3PLcYX)<~&Yn9HC2-ray zuaAu%X^vJM^OVW)9{#?egSddys*BAmTNJ_yI2UcuTR!j`Cp&O-tX_J~p9M-(9vDbW zHwb+yk4#i2U}B9l$Li*A>Zku_B$738-i-26`1-9IuD2DLsPjF8qr=U8f5K(++N3V( zGCH;|H7;anbs4t{GB)~p|FSX_(4b)ae?O(SMi|01)BS*CUIymc!=Qx4W4@eI@t+B8 ze+1au6Fm2M+sg=V|Koa@YH($!6R7zTnn;EEG@IHGV6CgCTNEV=shq2;eW+_K9EI3C z+;#i$Gqr9M69`}T0J+*{TU z!srwsYp>xds*)|7cLb-{Hi3R>Ch5A36Oo{3`YUI`V&Xl6L)sMHjvxV6*Zzojl9Rvc zy{6b>u}Z8$TTv)MicPdpF|k_z;+_L8ghJp#p1BKS$9NphV%E<3yG|{qOw77o%O4+J z7Eaz6Zd&5&JFu%1p4=L3F1By%CRaywes>Lf*4@3TeIY}=3;u#_;;f$DeAsI#o1WXZ zU!5N=tB*y{slM9BR22TcLQ0GH7Kg6u{C!Sdk0tr_Xv?hPQr2bj<1WvVzfzM%Su zNx7?Y69z>-n$H?P?9ZqVflIcY;%^`BcY-%1(>1z;(o_IH0QNN(51@<9<-^hdPHTf^b#n3Y@FzE9Q!hW?x-CJrYAF3-^C zdHu8B7q({{J6IedGxs0A4?Zn9{Mo~ zF766)>z{WntNL5yTH1a zci_wvhe+v5lOCa%Q(t!+n|b|iGUVTA+*PDM9r86sjZFl} z2#<{sk-MvVTogLvYnI%t$62H$5lxz*lI0hgr#b7<8vl(1{&T@&hcEw*Ueh$GX7=kN zUY^B1K{K(YB_+o2l`iHRI!Fn9&Z6E~uhy6=9ksXhhm-o8`rCMsQe6OjUZt9yI=p^p z_ed8hM83?q6ue9^7XYshssr`@(pUf2yBQ|A$Q)n7m_APdM;@C(vxK2dpOjn2o#(0b zvJTUf@zay}0uNjklsWKMh;+S34ZJ`0W24jM8V{A6Em)?9CeTb2?m|V3T6T%jy#N_(Tc)r4zehP}lR-TfoF^=JWdN|Kj znk}Y=r5Fv(Ux)Vxzp-&}Y{m_$64q_sU0oU;VnBg-Pnk!`om~!p4>WO=l1fHyxmK|ztR7SMTE)Q>$Wl$LV17fQ-D-fawTIybn$Rwj6W z#fwM^0GTVm*Hc695Xs-Q&UGvxlmXGm&;fY9kUN+A6yj7s^A(CJehwi%f0aiDe!hC~ zO(<*G^>}JFAOe<^h0S$TBo;_v1Egz2!jM|jw%|_4E(l)!4b<`4T2PulrwO&bhO&PG zi$tt~eJoUSK^g1E|3m%^;?8iP@fH6@C7?CAJ9398s^6zn8gJML4>p>Hy4!ZYgIUR* zLX;Kh!~@FQqtr^{VL~h6q#{u;UA}SIY?9L_k-=+`b?>!Qn*iB@B!ZtuV;^#G`v?AAUJ0Ud#;`fEM0JS{0^9JlA4vq@1UaJT1t3*H z{1NWo*+(5uH;f)<#QE}*ILFlUV1%U^hORt{=}Gzdv?#^FLPhtXwA3k*z5Wb6>av*q#UC<%9{vq&wL4|QN@~jx)3;?o1~2V8o>vA@#Dw6ptg8cS&hV1 z)00?~T8K1J6V9F5d|AVd|6GF@siLz}$>P#@aly5oKhbeV9AMYU_7(6N0D=*H%@HeU zasK_PIcx|Y)I#F%#QE}^O*C+c`EW35ra4(>Rx5b4|8YBqviBOQqyBn3<>2AFbm#S^ z7Hl$xY~9RLWr+Jo@w_i-Y*AB`Uk_c+;@8%drv$wPkHg&@i&T5NRRdruVKru1ELYD; z4VY(Pfi(Dh;Xh2YP73S1@-Nb>iR$8>m%fxQOJ03{d5XwlzG0+AN76BY@Ic=MJCVh6 z@hut<_Zp<^-VH3KN(Z#c*NT`D@z8F?64 zvUU=ii{eJ9#(y5HJmQ0_;^S6wFBWaEB6<%gtrQ6o>eW&FO&U;-Flr3=J70_yAQq=v z1*Q7b7*xD3yQbw>lZM^YKrzk(nrrwV1$=q{(ML=8SO2W5 znCZGM&-qFP?pUD2Z;5Rb?P4Fu)BT1NCFRM;$7tO64jhgF;@$@7#DGMnR^(^4`IVMK z$#WvkS7NZFhnnDhA*sH`T6I<1*#78GZ6LYr&9|bp=(z9Y4GaGs|6_2(Yl{QJ;=ny7 zi?6&^wd0+{X%n;j*3Vg2itj6g3;zT?HvdvFyGkN>el|?4{aZ0vnt}$n^awm2`+;j;_+|@PojgmrxeWwF}f_;~lyns_JZmo!3 ze8SK49I@zOVwR&!`YgO%oE?I%v^hHwpN22G%|=L+`OX=`C@C5JF}JHA-kh)<8gFl- zy;qS6fY$?hS}B*+#S#CN#Q#(|R?T451}y9%m*nBW=t)svL?OCR!Njr{V0Aytrx{Ljdh9oasOyGL)TbI|>B@6$js+50`R#e(!bf+zyo!cbegz%Lj5rEN- zu0=1Wo2#GE_T4Tp$x4?749NT#$YeeVRbnCuHj2(wf#lPAU*A@e533%w<-AsrJTzcX zh9U2?d&bxo2ld!I>qMI^(bKJtT$l3s4hS{kbclSNX}%aB>#9-ZuzaofRXn^|p);7U ziGZGh_>>*|dapGMD~!c+`0nUho2;C<<6L`l0RbuI`tEzcMtv2%o#+48o{io(GdsqA zHl#y6dxlrWMv-2eHm$Ck{*t`IGL}8j1%(4~yg;-w8bwTgAA1cdz#NXHPm2cL9ckRa z@QTNL^&kd+?!;Q)1@oNO1YvzZw)IY;I;(6L`ni+zyl{aYJa?mzJ{Yxs?XL-V6#V;; zEAFwJQFvpH-U|aP>#5c?=o^9;ByM3QJt;c@%Ha!>K}bm8SldO&9uhJpWWwd3lY~%? z@RyLjdk`dGwJw0AC z{a-(=d1S19leN;CbJb@ee|%s*J03>mBY~|(ZjLo~%~C^)aF2;mIFldc&EI12er%jjp3OOIRx=lkd{9TvC3ZxDFZVUyIwSm(l*IcjC+ z2~wP!qMLdOLO)%Bdsl(aREh8#15Q0@jtiZr$t>Yx=h8E%sKy@4tD4;4>r2btl|vR0 z2^-gDgMGh1Z0=dDncU>Cb@)+u$}QSGj)&!rw~{DQfda-=4g=rQBTD#(b^plbmKIwt zuW(aXqNOPG@rml@!U-%d*}0DQKQG4(Ej!*y*JKsyxibtq7|WjCa?3DtnHW=IITI>W z>w)pv?GlRAY(BNBC}R1Q=>4r71fu9#MwHz4?Yb%!5%C=XAg}kcUII9B{L;MGY9fhK zV{p%$HFm-iE+Xf=7+z?$8?mgPajZH0hoW; zp1=K$)5W~^mK0zZQ-KWy3HBOYE40diB}p~T^mgn>kASw(S`<0O zcAvp(bt&{CG&*kUG)!OLoYU$lI@idA#YHb@&i7qB6D$GkQ}u?aR2l#d?(+*J!1Sbs z75*OM{EJ;E+Cw$17&T4qBwWbr#Rbo4_SxkH_0-{qXCcTpEZBb#+`^Ub(a&2}Rlg3f z1#xOppn%x6y45^XW*Ce&)>x~17<88sq9|Z{>nns@yNtAfkooQ9eXmU{IdX~N@FQYk z`T+TFha&0#(snj%ETwarKOCP+M3pit+K|r+O#!zc{Ac51?st0mA8FgxYZtEZyHZ)d zXs3gt_q^B?ILCFaWGmDZsfu)A-3`v*Bj zzR$9=*!?H7@pf{#o(guRB?zBJr}53!a?vVza%dIwH=5tiE?nW#^By&VYe!~iI-~wsReyoz%WPR97!$5@;2qvo`$YduJ0Os15e3yjHHL*3TQr)W^q3uQd;2YFex_KTs7zA6KKVA>y8y5_Rij z|7i?rLT-u?e7}Esv$?4|jjH-88Z509cslKfKk-1=+^e{}WVt=*jxVejRD6q&b0(Ml z&)87h<4K>temn50|1BXHali&$DxT;}{WYYIV{2+ww5@o1ACRE#jl&_tSjEV<3l37q z9^Pp!{h^8iaHTAMI?KLI7CO0rGA6p1-Lb_36JaTS6X-g`hkW2P`s7kUZ~!2n2Z!qkLM$v)!TLiReDY-504kQ{qX%L@AZ z^z1Ao1vbW#Ll8&HgZhW}a3$C3Y3p*T{a0YmcE zDQ)&26?HtiABybC5eGwoBrFh>5r$CQXBi~aTr=aH51Hz=BH0hBJO#?s0l#TH|9@#5 z!JZ_<12bl}lU4&vMQUiaM{VK+RkRNhV?`rMP&d9nm`-?yrO1ztLE*d(gy{ov8$F^* zLr?DH0}Z861rsvt>wV-%*zkPNOP`=Pa+ zq4b7((YoDEvW8=^thdmZ>5d5%UCkla@$3Zw+>W^w8g)E`cK>*|JqG=%=U}}eKz?BX z{@x&Gz?U*WbRGM>U4Y?i|AoC1%96SMbunOe{fLup43M;lwdOwDR5LY{ zqj}n*g5@-sPW(5f@Hc{7<#1@m4-1(-!UmT*?z?vUGu|Ma43`ga_SX`j?nI;NKZA%D z7cTu4JHDaIs%2C7n8k)&d5(a4LIp~SbJsC7A?thi1HkR*#BAk7 z{~*sI8*;z^cp=2BL#)^Q)t`W;CUGNvLp*vH4FUpO$3O~ri$h@~kH&g3k zWwprr@8R$a;jb|C`X;?ZZA2Fek|Tb**46d8!^|L4I&7Vhe<;-{^Tmv~P9RB;cixIf zw<{SKje-2c5z$W<;Ga%|wO>{&uaj?Qh`l`0y;)1Dje>d-5SY~TPxzD9M0t;kY-Dat zUo01wg$aP<+qh(!K%tL1P0|1VSaaaF)ifN(>Uydt^6}u%;wAX10WCWxYx?0q7}&kp zOf+2oc2ZUYV`EcpJc-!Cv~Fnro2d+jqm8;0ZNQiBVp|bbB2$E)m1QIY?62riGBasf zy+oc!TAB}>#5}VDZ|Bku1PQD;Y=;Z7ImfH@C7aBW_nZ13&y~Nh9>eyluucCg*R_WYdS7h#%sL=? zbR^~;m*0M6KW(`ydLpjLL-l#Qu7uSUU%_n(R8?C z&Uc{4Y@WOer-#s{Ecfh8EYKfxbKg0%F@xh!mg|4FURiiYlh_8H;CgH?rlvwKUwlXA zCd60T26!>$tl-h5w`+&Zzkw~5sM*pc$Ac*F#%U0UN;FdGrFlTb-o5n6bUu7u1k<1T}^ppN%oq%HI$LQ9%c&LSeO8v`LshdJia*pMFvlR3br5oh%Q2aaOQt*S* z^_H{L$AE){?~R63i;=6<(+(+l#68qVYc@+eO@A5Y%?9J;h+COe6OK9ZtF%Tc-&7g@ zb;G%~9Etps@t=V^XUflYAwApSn_`~+?yMyYS~8VvB*OvJwS@|pNW0&bK0oX)eyx@4 zV>TGPT?R?|w%VZO5uQfsg5YTpY!>BwDNNG!-3_y*+<6NN3uQ%wgz`E&sYKRS-paOV zZ6NMy$H{*K>pJP}N^Pe{+MWqWkp-RH8z*?AOooVbzP;^DO|6~9M@BNodfsTS;QEAR z={HhVnGmV)sS@7;5OW*q&aFdz-&q3I&U#po;x2EReOK{~Zn@BZq!_*b13#6%aQRdG z*Fc$KGzDJ3^WfJ(^5Vbk-*o@r+^cShz~4Wwe0EYk)=C@@#{d39c}v9h@$&_q0+Q6; zRh5IvOD$nF+!6O!f=-}_)**MLR4>ALG_`~z^`K9BZl_{U-c*C;{lhng%Wr{sg-WUz z-FI3$;yneQQG=za)4#o5sxxFeN40_ZYCESgq~Y#5P}3v9Vz@)`fya&IFKw)1Uvwbp37L zqljDM-;;3=aZaE&FgMuaHE4YNJ?7um@2>SsS7{Wy#eYpdQo_^?lyrDsW4;fkX?G@9 z{O%W^r4a~m#wsAY2lyB(8Q^jtu;3JsFspojk=POOeR5{i#x0 z?VJ=#)tpkP<`+S$(n5&>H=8t45X}snwn%|%B4U5eLa}~e=rrgol7fFgCmhskyHRv`YVmrv?? zobm8e+KI*>T?9K@qTmmhAG3`#{WN3+aL5 z+`J<<@kJ9wVUfvT8BWNn7zyrOn$HI2JupcMuo}#&1}~Hgr(Q}xLrF-KymH^P{nCV71WrRL-ly9BSISzPnpIK zb+#cweZ4z|xJPwxH0-r(0CN5%Pg)caG>m_HXK{Qe$|#xyMAlF5P_iyErE)&7u{)NJ zO{c1R_*SKFc(05BqwTZ*qDQ?CwpY1P+6!?4SYfhD)bDw?rG9oP!KQy#dusoA>yqF1 z+T*=tfTUgcg#sz$ z{V!MTV|U_GAQxBV^!E@ek?w)KqBLke$V-hA{(kGi@a6HFL7*P)dME34=>t{zZ3{Z>h+vCji)63a5KYKi_~4X{OnZq zztV%is$_jnLiu19q9{pmXAp7RdTOZ_VtGz^gCisj0k38oYriCcHyydf(aiSGmnCGA z^)`7gMvcB?&Yb~YO8mZ*BeV2hMj)~GV=99Kfx(Zq0 zr*~^%x;)kS`{pd3$SdWn54Suh$dm!XpU*xi?O2ej`jnfnFwqlM*yEKa#QqKmVUE(H z486rbs5|L;>YBK$x(caDV0&}keB=_KKY1;qD4nhPY!p|TpSstZVlTG!RF)lM=$i9g zPKEXdbFg(CLLS^%En%}x=jL6Ck|lFR5koEmk@c0wzo0nkfW&XTobsM=V7`q3En39I z_I{~BeH2V;imp=`G;lg9S}5)V8KTnlt+`}bc(AhVnV{g+FoOR{_5!~`rS#R~lmYUz z>HCVnzm(wQOQ!T_;IGSPrqbo|5l6!6@GdF<=fr$CuTNprYRv2*@}JCy=X0NXVH}*< z=BbZ1&_a>;yM#iIetP?ztcJ;Qb3_@t<1hV$q` zI(fzM*=|F*-t}#|&F&|IjZbtkj!cO_dv%tjzA!9Jih=N6#&+5`hW@967(;Pkl zJ2w{_;q_n*;mK?~Di0y(g590yy`sfK8*{!sj;1@6FIXb)@*gi9J*L!jgG*CRi4wkU zR|EA=QO)U(zdOA!p_jfg4Am&lm^?NE;6saBHr(S_8I*g^d#iAfowB9K&I5 zUu%TFEkp>pOBj29OTNZIWK-i@UMJCAP%ACo$rRCbcuBtthI@~wl~Ie{*nn84#z7yO zfXIvaL;_6f^P(6a-e2X&$LY=lVjLoL;^^Jyr`!2bFNqV6OwkX#8J?{I4D-#;;tdW8JV5(01S7joV%Vjn ztx%&Bexgtye1LiYo~*(kNC7DEqzPLK__<0kbYO~d88*m~qRqBs-RGnT05_5&JeqPR z|HMr1o$e&20>=wK4hR20qLI>6S=;JDu?PoA=*}dPzg#iLRtoXx*xA(c&}q4*0`FR_ z9|Vw6(CVKv)C#zQw0m}LCE3EKITx?awNNSpy3&QaNOz{kpGfErHw$qg*egVpoK)lJhe>NKxD_?I(Ns8SvS${YNx1?80KIch$9UPOd^~Yy> z#jTX1+#1W%QhWA-cI~x)^t!8`%BTI{vtT}b`*+S?7j~cjTOyy0y_l}+{Frue%%2>l z5&Zv}8-ZQ29U+UtK$|bmT`lk0fvqNWQ^|rmR`8Na79`9E@i2iUPz?RV@hP*zM@rxV#WgUt5eE_ zz%^9nOoU!&Kg5g;`@*8_VatQ}g{WIkaL5}`R%WOBU&-{);Z;6onlnY&ZrHE3d3==c z`aT=}=q2A7$McEZ-17ZO+Xn6eEqFgJ-;Va1&^A^==k9l^PS4A}U_+I+tA8u?%nW{U z+r8Mxw)~W_C$tEYIIbXZl}F|^5*NbVm@2JJw)m>dK|(+Pwz10iJNvNvL^zeaA}n7m znyHG+m^{x8sV8*!JcVI>z&psyUC=~Ve^3oN0F1+YZ)2;X1meeIp8Njm%ecb4!oab z$otMahQ&bse9d=X<#)d3@OC}^{7d}al{_J*Err(e^cp@Qz5q4|q#=DH{RWKQsOhzV z8w#$eyG{nTd&R8?BunwP$s_Q3{xsA55jLMK=uj#7ppk0}wwrG;Dg@pds5-G#o;=I9 zlJ!6O`+%ohQSK*5XQOl)iMP-^urK5D*GH~6!b zJ4RnGU;drZ_1v(863J3dVNAe|V{x@OcVel+`=%K08Fw3c)xkCK@TsRj2S+pdzV1*B zII3D~Xz|BRWW?6qI@3|o{fmH83_(^7WpvYbT|Y?}G9Q4N*2xS3vcBy4md^_hE2o)| zc`zFELzSqgXuf*Dw9yLo;@-i4onziw3Xl``xNE)J-hWJaBHjbQn0XmPfMOYOufwZjL*4#U-hD!~Pa&v0%^GqSgBi zohvJ)MP7ADmW2%9#*0N^4bW7WXbD%LUM^gW3IkMU;$klK+pG#t9tjV@k4{cv*e~W3BzbHmR0Vy~uAI?|h zL*j5{b4+&-T^Q8Fi+uu64 z)lLwfZGp}s0N8-c8mpsJ$|Y7Vonu7ES(t(=zJJ+ zD(UPLKis6>uz?L4`abYC9%YkmI)C~j*NA25(<7BjxD*5@sqFgVXW5v(;32-h&rG_w zFW!YRrBS`&3e=ykDGE8ux+w$(a!UQ)GE^Xb^LG&hO`VT@1Ic58=-=|_BFC^WXH^A|L?e@S4T&S>zQMt|MWE;x${m`ljh9FG}&qr8wRjq?u~&bB&3bP zqSyDxPhOoWa5T|yXG2O;r9Qb2%+1x@h3Yf59PfCU`RT7nHn>hjjaBVT<4%6;){Nf| zG%(#A+I*UZjI#Nbl^t;9=Y6H?Yodyz9tEyj1EacM4#(i0FAM!h9x$No>aUjzAceT> z5hde6nm(7lv>zX#(p(akmI)&f42W*-S`H!1A1&}(8X8mu9i6qjABj(mR#Gk<^z^WA z8?JmDg$L{Pj8>M1FAbYE7(ZvyoA2+l+&4%oNFsDyLH3>mkpsldoMmlkq^BtJXsV@0 zlZ=6rjLdy&V-s&y6Cr%0S|`4MpuoXv9(*$4i(Z#<0BD|trdgObPy#n(^1bvPSCI-s z|3PWjy^zpa`SM{z_vm|N!;s^50ngpI1ImK)9dw`0cQ27AS5n*CxvNWkf833AfR4~$ z&Ac7zXdshnoB$t4sZ&lmr^ViLbC5e*YD6%GB%7i8D}5U-X=97iDv8k=-^gVWHW|t$ zH`6lVB+Yb$=IEIF|4}}V^*ItHC+o>C|6VRm3Yi9&bdVK=DJy&h9oO>&S9dUh(J!NK zhRHhWwUVo}5_e8|nT`uWy+cMRpP36@P+$zk^K(H3tPXaaGrxFN*f7p-iPIi9Y^4GA@*~FoJcs(1MCb$> z5UyoYu{&W!4vpC`ObA!$UFE#UT?9 z0q0!q^X=P@Uvo$S`}24%$Uqrar--7Toz5iZdTk-8cER@_P-YkDMI ztxE@7a3@@(1K<=#K5%*u^J}!yeJshzpuQ=k`)6ZPqY3%7%ullR`bF?&;a}&G3ZjwJ zW`JT)A#KJk}^7$!5~)mS(_{zxZ^n zkGr*ab<5j=*2Z;=>gZEChtng3BFAabGZX@`0z2pYuyj&%fKPHu(NcGyhZVaxqx73`it(DFs5p23=W#>#2Zf9g2$}(Fc zFrEkz7g%WPeanJx*G1IRG8&l4kGfTBrlxiC;E1nC?t*_{ivQye z=ocxYcsT2d*mPN)V981{lq|rr^5Bv6iy{?NRz? zDcrL{GShn}G#pN(`j;3@ET6B5E=qdHhxfdTbj*+ZGg8eZWz*NNHhSRUep~8r-E%0l3vVB1*M2ZBk95yO#Q9a?Fk}IB=EYNo3imlXBml6xKiRn8~jiKo{_(_NA_;Cusot4(D(@yWM@iPqa5r z6D2&{-PK>Ml-AYtHm+jGS!nNSv#pHlTcKj~&d$MNwzHP=-I)<+b({SaYw*a{kKRR8 z*46)hZRu+(f_UvgLQ)2tRAuWtARzgcZDawHSvVy2&BO)$hzR#|M;5a5QxeQF{5*I~ zrnrYGPRXDo48FDyA3CqJ(&Y&X%-j{!=`rMo_Y0K6neM|Zsmtvn$>|CL(ww*I@cvGd z5o4l*N-qxh+8TB{;qC1*cO^HGz=HiuQn4@zVFI*6qDn+4${HDm4wXi{d#0K=m2zvA zTaNs;)oc&P&5BT1i=L6zWWtm0^HZ46UqWv7x4W0Vwk~cPzsIp- z?)AX|6xtkp)?YvCat{{Q*6_|yd|?#nB~IIom8vn6gUxU8YiErs&k!#QJeir-^IcvzNofP z)Vnhvhx)`M@VV0Zfa#2Smqt`fsIA|$#@K%o8{tLudRmpMe0!T-#9~rXR1~j#cWjKK z&F7iU_aI-;nf5P-7+Q=ob*|L<--4?l;Wg2}swM$P%FD~kK|}b~ps;D1H;+l;%8(pV zYnj8h%{&BQ345}WriyRom&@~6o0YZ)`AA;QqilSLD$!5x zt{uhq*p`w!`@ss*gQs7%vIHjxR{OI82<7}N61d0q zbu4@ACSRsQrA^H(WP%|ra3Mf*H(fK|U}+i_zQxB+e{c|@C3j}$5!_}DpmI*+of5_E zhMh+&iyp=IflwnaJ8v!g>FBQjO&eX3z}tq$fdALiSBFIvHgD4iQX<_gjRMjkUD72D z(%rd)NGaVYv2=I$QsUB!bT1(tyL2xfzVG|{_TRm(bI!~>bI(1`dCuH%Pl%>3`cH>) zG|unyDv7)nd*&^wWc(%D%qg}ax~_cWh8zLDVb|%ej&WuaYJ8#p>3~=dcP};y8xJg5 zVRP9nc~lZqI7L+Tz<<}A52Y(H_ltqhoN#D&v@}4{n zhl2w41}(2M%tU@5;0VO?=O8KZTB{pYyPrp zo2n?zjZ*T+mN^w6aY}Y=LPCN)uXyQhZpehc!XR>(MD{t&W}Kw^GC69YyAJ_}5sSM? z`n!?Sy?s);Gr6K@jfPxgIJtcZarwDWbO|1F@Gb#Po~(wDvC&H{T3*2L1!_|5?=BE2 z<0iDbJpQn0i}Lb*E>vUZJZK#WL(=AyIja`==J)lnJMO1+s(IVHwKlvSL$2*$bpEK1 z@2IYSZ{^dtI(;dAo(FlZMgHR6?zQ~f$DtvU6s^h@k6dh&))!1x9&%oR>HXA_8ODE zgCuX7TA4La>(oET>bmdL<^mEWV36()A!ifykNJT6Qm8-d!~|ts^8U#40tFS(*C#E>F) zVzmzr)3fUbWZOAejOJbqh+jnN3>%1j3*6f;RF||}_>u3}3z6K${cI`>m{Btp z{*XaPRO7?pyj8ZRtz%eC9ISS9JD^(XDbxhacQ-U#bi>*p0C9S=w6s=o2r%+>iQNaA zjl$vtw?zA9aYyWrcOsEKaA$vKISoU;Gg~cPB~{1$1d{IR`;h+m_0d+o|$ zJfMn*O1?hZnVTb7?eZSAy>4|qm+$6aer!Sx%;U@Dnbdsl0G)L3saeENRvF2U0jCk9 z){RiI1Y^#CM^U{vTz=FQx*csURVHnorsqwPQ66as5P1#DGgq?uyB0V8QBd8X)KQiS zY;B3k<1x87rackkMuj{_vm0;Tg2goI;}RC3zoZEob{)Gs$waHSX+xXtxhI1?PLS0u z`4>VQKT=9i`Jc}&NQahOp$)ni$z5SmIPNq9V7cStqq40qnUQmHAXO3Q_YhdXMJQhj zrc*gvsW)-Znn#5aVIyJ2BSguabWz6m)Sk8&G!4){{?T*Le#{kr=#9Xh5xP$5q#In3 zke_5C!@=l(*%7=&VMYe`72bmCzA%u_HvotFTRC5b>9#6#>5M>*fl5cheac_s;9mgvxp0^h?EpMoux^MRDktH%ES7 z{E$D>q8jq03r4-g9|G*b!qzcuf`;J5O$i1Mlhdy9R}^50ca#nR^U6D;MMbq=Rcp>7 zMGI7S`!9?=>zC9)O2V|N&earQmapc+LV>A|^mX7@7-%n5onqCtWS>X>x;i^eU9O4; zwRwNIzEUwU;^1?)2>c?8m}j(383weu++D=U@?1)FP4~EdFc`rTCjlM&Jo0k~#(#kh z!77Rmq)E-ZKGYfkPz=p)eXq5Tw*<6NO;1FKD20S%<(!+|m8^C^3Z`&A`xrUh|uopqi{Ywf7w48Sg2nEt(ps}jy2=slz2tzKF zrtek4j@B_&J5nYl0}J?kDUxPJj@3pCB(?nmU)jZovinKNo?(eZE!*>;VLZaRgnKzsZgC&^$Hm6h%*Y zebbJ0NI50g_U`64uUH%T5N*Q13oEr9J3?X;>Jp>1MIT&=W>Qne69XC5Gru471-5DI zQz_kE-^?D=L-3OkjWO`0G~_N{PqH3w%kGeG0Vf%!EqT<5;9vOh<7e?`RIi-1Ci^&r@`i$57leLqOMqgwOCLL%GP4#zOx9Dxx)~A5r#&C zxB0iPYp8jd!WpjJw&;6sqzx|JI5PE%Q)G>469)czyhIkbl1eJ(otnMJnTuB)01ofx z8bmCn(UWspyFwSJ)?$>`OifLeo4sFZrYCl^0~bcG4C}eY6r+@qgNQtC6JlP>%gI zzd#SveEI&zCx`yOOzgo>ZQ!!b`-I`lm*_v48op5-$pNi-6^`TnI%~Sq>Yk-&=jvTr z^@jaQu&O-<3`e(VU1f5PYI9JdXhbr;RAKU0ib{Pa72QzhiZfW*hm^{)FkyfAeSmy9 z)4%W{^vl8hzGX~?-eqwo{y4m_zUyNymy;L?E2V7y8)lIL)=a(Rk1^&=x%o?^cW+af zvR5!qyDU8Eb%v8Zo*ggxIPE?J{5H=(ho#5CtOo(i?XD^Cx$CnEc&##V?D>;XbwGyd zW>}8@Lq#0y>_z_sI3Z1f{B#d8yi7|v+}|Bu!lBk$>SdSPe|H@DIEH%P+q6gioHVce zY{+R&689+)IdnZ%FUQ!akspXj}c=70^7=@Pkjsrq& z86N(g*&q;?aT|vMf_GO3BNfeUO=B4(8N$huFTZ{nEIYDfqG9s#flt!=Jlwn!3S5?= z4t7>mvkQ65RPe^bspxZk1K(;a8_Dgml>~fOA7~`Cctv~Nho(y%#8VtOl$PKGDF2Z# zBUusDTn~~eN0F;GvHAo83TfC&MCWAt~XFHjPf^)KtB%YKntGO~6X6+3di+ooG-u>%iiS)`T)@rZQZ= z-YbW2{bL^lXO-?qX$$xjfjHR=jNGz>*uk)B^sSd#f_4Q$E5e!-yCEZ)v_@t znDj@k*&^t;sXLgh?Z9Psme56uxrW5n;V?(XEnmvlMSUak(UBSv3Xz3<^j zqq~V0=s$QTia=aQ6lg97tZ2O-i(+t?Nl}-D?tACOvG<7Yr;G^t2cpW{31Um3;Ky$s zNmb01>QRj>tEt`erMCLM2;um}lXxL#(5pa6=rUnl3tG!_33>yvCEWl$!JBZ`yz3AJZ@OG=!-f`N(J!19FOJ=ADYFnx)ksIm^s(pnq6#M!IRic; zeW-QE0j#~JCU%<5!L2b-!+2hBx`pb-1Zu|tKAYY5Z;L`u;nl=#Jl|$1&p5dN4yU*( z8!PD$8h|Rk+EMd-3=faF^*6)&l4yrb(p9Gk(>7hR`SZ&4>Tvip2j#wcb?r6Gz+_t1 zm5Yljrg>IZVh>-AD1s`D89YFJE*7;RKjtDD_+y+p(~^%*y!v-0E-hAW_W6)tP7qZF zE8N)UU}6!r+Fm~yG3Z+4HZm$TkHqBN6`#yPH=HzOYoArdz^=px#=*b8atzYHbB>2!J@%P>_OxV#oPB%};YJXhC6Sfpwp9BVSOdV7 zb%6$-!1j8Rde37pR{~6l5pgkGt$5uT#i%3qT74XP+h@ef%IHq&Fo3UF@hA5!+0eT@6Z`&g`mQ2Iy8sJCJF{Y8G^Rk~R5hkaH9 zMk_JwX08E9eL`KrEcaYfq;4va*H34n@c3Da)0#NM-uU6+;oQMl<|jkLdJIKde2r#&g}bYjJ1*% zI=#-3)1H|TX5T8%SQ`0V^I)oExP|)r6jrS_HWlEr0yIdU)3+-7-QTYBr!)3&X5kZv zcMVySFj%Tcef;63u~AFtFtyWgFSP>Ei99U%3yc_?=lMYT?}bJ6o;>)D=#;h*f65wC*j_AikORM`Y!l z03BFMt|XM*ZN&kF)suCW6z!7Dp)za=K2kfcvC(Q_(^ARh+xdEeuQrR%BIqAt{kWKY zG%(enSBqzdhGFH3y90K2XfgoA%CvsXKfk+E67jsJjWXisdKzQ)dkjEwHCo1jwzMz8 zs%l+581A==iRwX2Wh=!@MRDGt3wj}}e~k6M&B^czGIB`&?0Qh&p8F(b}^a3hi;i%ed+-ej`LdQ|;n zYPk7&T;yCV^v>To6a0lJG$+2Q%>3E52~`#F!}-+7%K*yE~n;Qr{^o3 zD8kR_u!rzHgOZH94em~I?6}lyflT+oc;;*VRU^kA6C9!IbwllC0&hT$^ZKnrjzZno zjgHSX!a1?48cMs`T@M=8)1Uh_GQw_VVEQU-V=}tn+phm_w(yVl?zRo%cr;?Y@tkAl z!d+ z37=T$rfBQW2of9k)fUVNdJhgnDjqR>jWd=DGPPG^H`mecoHxD;dB8v5wf>cE|Vx6bynrQq!k z_N1IXx_?|D&H6m#)t#dsFu7s%wEA1Fz8Fr#4+B>-5@lzkTVZEc{?g&AZKplP8JD5F)PijEmD%p* zoNLgb-0$_|GVJRMjEb0q)T?*}%_UIza4`CCFdA$P=PU|y0PgDI;#3zGCt+q_ATwn~ zJo6N%tf`^Y$t^HIy5~;=yX$?il| z=A(NZg+OxEU~sKce{TJwQpHtiF=my9a3UKw_D3tAaqC{%mg5MT*yY4K(}-UxgN7v8 zjl2XJ?|+3|t&l5(ej-0*!!pyK+EOQweNdi~LTj&{B*DMAGVuE;hPV!k;O5*o&QLd5 z-!qtfKyZHdG}lJ>x9cUI#o*>=5ubyP^dZ#H9evxGn$ zZ9YnZ{-J+-7psz5&+RGhM~k)0Mqey5jvx$V|BO8<30+uYLv&Vje?wO41*A5tm875X zaA5O|zdqIQYl zPI$gSU?l&Y34= z_a|h(hh-JFk;d+XnXWaX!)8N?KMoCu9ey+DLby4B+e2ps6N}&`P6Fki4+o7C>2e%C zr!_LoQKpAJ#fzglVyg^dc>OA)zi%#H1@Z@@!7$y@7_Jdy-Ii*Y_ur3h)$qg1%oYch zV#!sH{AqLA?q!01PR~MZqrczI0wTLKby#EjKOLC{k6R5^F1HN@%rAldDymvXWLJJ% zbfFOQd_`kOIh?yd#X>7v@WvY_tL#MZbZdNEqTGt+k6RI^442`agImu@<=!g<;3H-@p}&~DMRUGIrIYK zWQ+7v1owH~JYBBtU}oZm1W#rXXlrYGC8l`&i0S{)g{PBVR7JO&#Z_y{UcupYXnh$u zC(H9ZX*9L?yDs>-*Y5Ewo0tO!f?upg!<)|;K8F4;!me7?gk~B||>J1N9maEPB^a<`!wRCWp)E)~)n8Ai`I7)yy*P>KhD zASI=57DL+~k0$fOoP1iqODPE2=EEbwlkA8?pt{N4zH~1*H#mub?MQPUkoew#Q`L|F zjD5-_l~!Uc(57$^3=A?;4)*U8D~L+U^S{jMw$;Gmo3|j#_Xl z6tpT{6-M$9rN|i!)edI|28^JnI`nZEB#S)cd1cL71RdAut43IFNeJr(tLpqjuBqIg z6-f$Fx|t_Ar+Wdo@=%(ph%b>Y>yket+2{p&XPn&ihJ&4M3sbyl6x+ zCyUskl2}a%E8P`d8Y|yFFD-F^*Nb+Td)#0|UbwPP(dO=Wn{iDZpZgiDjMgr`cAN72 zl@fm_W@W%XoknHS?!yrK+CSTdU}ZI|cC`!&yTGPe__m%y8Mav+Mt5U@z3p1%s>}qK zQ|PC~LwO<3D3(_=YxkoeuQL=oz=t-jNBq~-ahApE{?7Dq$z?4}{O!atRA|P@58MC1 zj7Texw|bVGFvCvn^{tywd7J~>Q|n%ju$06$zqzHuX5IlbZ6~lI-@P+ya$WOo|8+d1 zZsVsldifW!?`G?{E_#!!W>^j8me(JOmyg3+b|QFF@V&V6NRh;8YNVSUe>c&`Nl7|72>?osK}mLx?ff-+^SQ*eA%oQ?f~Y1kmXG@BD5 zY*I_uBX6aKDcLYVlhU)q@NgC^HXqEvkXJDw`@RMQ)tv5KOy30&6!%SB$&T<+myB0e zooRfCvei!ked!ngRwBSeLnr8leGI$shvfC&PbZ;-nH>dj(_cb$lNWZ z|3q=BU1KRJORtosNPS#9{8cHLidJ@RpzYYqcPbn{|2lLsY@HhdYg62G-Ti5JF679U+l{KkEtoBDfQMA0%d zU;@Z8L|=gjP?pO4N=?*WqfOtlcKYqQOKjoblc4aefpSbx;?|git)-^1PoBP1ZG#*& zt&@S1`8#Ie&fszC8xbCj@Nk!1J@fbxJT3cfmhox;Jkb;X46#x5B`hL*;Mdm7mcl?h zT&+i_%w{hRvp16eg10?yAT{`WQuHh(S_%VoIMWfcyOstgZI2YWH@GG zAJg==5n{I2pW$AyyHipt1RxZ>CP@|P(8vH_2x5{HCx~L1Nz!7JZU`?NsEYfJk(IOG zx3P>jaO9NXUAn>p+7Li^3T|c2Q|a6jB3?BdyKb{$Cfy7YRXl16Z5F*#f|xYS zjh{2nqBG)~`O-w>)Bb8+lyd5RmAk`?msEDAp!h&k;>)M?SK6HdF2CCrU1G;Tb9=3A zXqp}lVK*Z$23&la{Q+X^P#rjCD}sVi>&2#Q1go-M<0EY$Yy2g--9BiGpO15(-*0tO z#V1at?pG;{c!08xd%#Vd)q4j>SGAIx-AoXmi5MNsuqo}HShORrlVzIPPLsvjL#h_> z=#ba0K`VTBE#}bEL^!F4{Ng_Vz9r2bF#LJ1V^k=t=`Il8WT9U9*n#@S0Z1$qzdDq7 zG|V4~W2z|UdKGq01vvYYLW(X{_cVLXAry!0@}sQhwd~ntnC8_6-HW94sMK0a_Nl_` zpbxJP5|7xTRI+MyiFN#em^l;t+b2m!w&o?P56ZRHk5eZ1E^88YBSwtEA;hyglB43M zi=4HiJF;V?{fhK`F?K|TH<>T3sCbtfPm$JR<@0GVEMD<5khjGNW*dA>0o#~5kcF#A zZ)Ccz69?9=2QcyQc zY>gDe_pZc;S~zb2!Me@xu!O155A1VGBZr==9SgNDKnZ5{8-yF;(@`&2N%660?)>cR z;<8ATlWlEY|JyjJOp;iW_~NkRTQRc()+$fjTNv(s=txj&9Nf%U&bw^qWI1MV}F zQNa`xyAHD@8LS(xnvJP)FBU>N8!^?*VsZgC#5?lk9g-i{L9Dvh@dbZZ6|ZCiJ^(Ki zZydf@Nm9gJc!^L%%lxs;3dlcYboic`nfdo`O3zcT#QSOcoGhRl2rh`%z_WsVsP=dd z1)<^U6!&D`U)3^=V@#t5Dc)I-3H!CNmHqyTaY&@4Y#fDxj}qLiIU1HJIFElE1-Cc# zAdo?cPMkSHfy0V=J;+A)944@LNU*OsGDix3JLF=VPVSkuy#Jo?b!BNxL4BR$<;@;l z*W|WGt?{{nh*5bG;>u#(`cEyQ`e|xlVB3uE?XzDTlgzTJ#XYf1$FLX9rYAhSy=qe= z^0!alWWIlru}`&A_cM8=nqFUagZW5LEGJGSw>BUH4H~#p6f^PN2$`q$IrxNW8fYzB zyVH+zg0J1i6B`5AYV%W%#f*C!?G+!)k3&WX!d6HsxZ-4z47#Bc@dz*O-sA#*#lYp> z_ul9Y4XT>AN6%4$P1lP5a&7Np_C2yJ1-VO2%nYgboGcqGeN3^-ocmCuv^iIX9R4|<6iarB6-PMBp)py+EY<=i#J^&ysO7LTRlOVOf7d- z$`IlKDYS>B7DBb|3&fBnEzHr`EosCB=X-m56A`9imIE<9H4=$RH`F6b#pqPxjV19k zj*a50wNIJkKA(fEa$YdPz;;NnvQrtn^VKW-DCt*$*pCYNk3*B5H08H=GsgFlRZ$O3 zwgcq)z4r5;dB)UT?=N$W^p6XWBvX#e4a?ev!nWMCs1meq?Xs=du`T7^&9l z6wk^I3<$xTD$O5eXD5p@gvS}K$^A19-y%L@cBCLkMO3fsby{1UGSK~{)}_vO9ciAN zv?^otI3mmUNo3uvZ2fD>*s0}OnV<-=dD{hAl1sxlK?)kC@*qlyL9?viWUoQ-NL~id zl!cS&W;eW`BFJ0R;1czghrRl$`166>gV7<3zQJq{-hYIR@ys!&bMyO4C@@E02`_iQD2n`j>p{i)_U_wp+qzJ? zz_mNt{VJ^L5X(VC=c|q`2lg$iJBb{QhgFM^DxE5CfP_4gy0S#{XWl~13(tK5jl@~@ zU`dHLl-F|FYrzfSrb5F|(je0hX&2VYp;d1=Ua|qnK?3nynk^7%VJ0Po#slmGXH zV20*ZOx2U%8EnO*uqnCfSf8)tN1XmDWQAuXAC-_uhSIBM}zWaOWhqUC{|xuWTDU z^Q?37EQhH0Sm|)VX7KaCy(oP$1z|iN8PJVaJxt=22wzUQOwm@|J->#Wf`bWaIz2}n zd{WBl?Qm_e)+%>uK>UQ+()P=BPxlf@#81!4qhHdtu!wuu;u~OM z@_RCViTGR^+@z!LGs8YQ-=-=uUKsE7$)s)E4ycHKmPEmc5t+bHzfg!rfkDf#lC7<@?ZoL|ROZ@!XZ1%nM z&ABF-hp{V0Jzma2EZ^OSUz%entc30>1ez=elHgAIAXL=C3)~uv-Fa+U;i|ZmOX*a0 z>Vx^U)iN(?WXa`=#n*uMkdOoE)BH54t8#Oqae0e^mv<~-OJfC}&SNhd9~M~iVaWUW9as)5y0^;_7bo`l zeWLVOtDIM`Ne%tHw-}{fVJbz|s78ok?=Hrx_F>{T@xFsV$NkQyFMdad&l^>QwAjYB zl@+;)E9ofMOwQ~Rg~r{S*z11046|n6JYFd6yK=Waj4Lf>ydL5-iBq?NmfgSo16Sh@ zJp2_tn)_+*OwMyQEh4BL6Bcv022*WeiDtzirfK*@#f&!+8XNgRnOT?W`Rz~&liK60 zW`77-&!vjZCC-1I({QlI^k&GcnMvPM6Qh(rNowDTf$ZLE+FE_(9pjZ%DD>y{=AKPe zFw4lyqk-N7*;)lbu+oh`D5q5)T~0>vSVi?NK>1~%W>Ik%Fu}^K(qC%4HP@+aQ+Czj zO+4gV;|?}}ZGxM)kuvlSta3Qa!^u@$Hn>epjwYkK{&~5jnvW2}9v@ z{rrPzSx7SdpItw~5k3Rr-88jG{yI!{1(}gmqpyar8>M*?TgQ06Dc=Qcz~vXO>eKO; zw^1sU zSy=Q<;8(L3Y~`Qi?tH`8(0QMkr7QekbAtSy91_|n-76a5qHF8VvfU%K88Ui1+hw6Q zwC=DW3fEaBm8;%i1J|e4p%o&_5m^+3q8p@F@{byDZ{!(p{U`plyeB{0CnlZzC)P{t zh}d^46rb0TMai0-9{Bkh*gn5~f7v>KN}a&T>8gUJ8eFuf%rOk5D-tT6-WmV9#C+5Z zqyxp2AkU+O&NgSkm$LIU?UoYD<5#_iIK>`cFr_@ z&Xlo}X#dO-pz9rMyjha2FK;x>6AO?=i?p72CyL7}1lsN#N59t2iyiukLr0&bY<9&O zIV!R}+kP`p!SX_#ay?l55cZ`QrSi;`nP;D18-{9A`L zji0i$}6i||1O=}+{QoKwGe{Dy?_k!H#gdD&Al-*Q-+yE*px!JwN$B3oBI{`6}a zd2XH<+{I^O6=cR-a6<})Q+!SwbdLdHunEn$>)UpD5f78ao;F? z>ZCbxfqV?PVg>+01GCc>W#S z^2oL z*s@$IpKyqKQg7APN@&(QdkRpqC&?*Ae z=z|Gj-AAvTz`l$2|MRv>;uIzZtDV!Q2Tb^G6$)L1dIWrPrOBDQ6Yp&dg zH%RnOF89DslEHcPE_$Q?_4@ChgOe%PWkb=~(|@HQ_~Xx(MU41P86S_Hiy^UkjZ1j% zhW0)Yy;!cV>aguL|DRpBi$#5(mAkRN4D!QPs=oCR)6((CmYp$=Hi)I7|2(E2)i%$4 zxb^C!A;pDI%$n5O{r}tDZhsq<_E4z{554o8vHVRkyFOA=tn!K@5q>V+g3V@GR&`C3 z_%b*6MR{N-d&uJusH1)2zeUXTSGkwFBq%J5dp(Si&xTK+jkh22k~tCnCh3N+n8_Z% z9Bw{?7cH1G<2qMGpo{3O`tjdXtv&nst9x-L5i5U)V>bK>w}wnveN6jj#C)>lJJvR& z)LS~Kf))L-Yp%J9#R0~9$`a9Ez3U{upGeJ-oId^JqCw!7B0c|<52%>kQljtP+)qs(L&VdTMr_75S^_PJ=)gq z%=dl2bI%{=+&`}8@z{HrbFDS!9CM6!yyKm5I$Ej(4`?2spr8<_t10QBprAtj{o-JO zE5kf~G~f?4RM`ls?`{wEv+}Y-k+*fXwqsIvwR&ZzXJ=*W?>S&6je>&i>1bdCHPY0O zv~hRkv-;PD59aCtdZVC7%fURXY@F?&OxAX<9NlDC4qH1|m>g|oSPVrppJ;k0+BrC? z1$f!%2WT1C1UTDB*s{pUGD*WE!3|vPpjJ#UR~I*LNtg`Ff8AFSeExTtpM~kann0ap zSpNH^j5Kwa6y3e-m_+zQcx|2t3NVRD@Ck?rO9%)&W)gfNAjB{5gkMmCS3p2gSWHqt zl<9wdSisY~Z0#lWlvMubS>T%tivtwuA<570=jX@gC&cIO^@?9WLPCQ7i6FnAATMaa z>+SCbwSw`wd9(iK4oY_3HeQY%P)Bz+rhj*|vUc}@%CLYp{qG^TdT46?uN%90|Ib8$ zDdUG(dGHJHJ>hqC{Wq@vYV8fxv-^Kvwh|fx%>Zq z(7%S@Z6vk59KoVkxhT2Y__*4+LDiLHSipbyY#nVSB?PVP1noqGc%RrlvE#KD5q`oe zVQp>AD`77nA!;XVZ7m=w{-68&pZbdn3yBE`$g9YUhzbY@D2phFJQ0@{5)ly+P!SUo zQc(U+Uv)QcsFjdh&?bCdl4G}UXdrl zg1pue_M*IkwgUE|;=)fP#O#Gw{-?j~|KF+O2QS6{&rbd~yZO&0V2uAh{;ypCzWlF! zWakDpj~Cb_Rplk@C@4O9>Pqqku(`b)?4Wlq&M!t!)eqlB5kGqrKKA+IQ+@=~n+WF~ zK4()O&lkS;E#L=PIq%Z+#;Drblz68tT5Fq_De+Wt;Pfh2DwETHbAXM__Uhwu>~$vi zBy`byaeZ^pytTwrJL~e4B}I+xP+jB2zYiD?(l{lSqf|9E(zwp&|LXz?O#MF>*wFYv zi~q|7B?LRT*?+Z2!GVJ=|CbA-;TcLS|I^~XpZ339_#5^)_YR#U<+W4h^6mRciAW!=Ay=sH7`sZ?SIe^6T0uc+X=$`Y>u(0!iAwn@ z2$8)Qo!#(hN%BxOREy``TLVUff=2Q` zeEaiuqelxPngyv`sDntlm65Ok7f}lZ97>j;(SmvY%F@y&h+T@Px}tC2Cjb8AsUm)j z3&()y^>sUH3S<~oX#C+Blce9oy|io(Ua+KmUa=8-97(U$z!N`ZZ6z@G zxbSXp5q!CM&pm-j5&wu(C@vHIR{?;{{G`XQdoI#zhgkOgqta{QYR-Tl^&)4 zREtuAcUf98N21Q))X`NoaLQ_bc5?FDda+6nA8pp+T{W=b^Y&PDox{SQ$YekRuyxveXuM0ZB$ ztMy=4nBnyEGzw@JLsJ6PDr@LWC ziR~WFQXuH6GPDSOadW+V-_GcJhibHp-_S$+K<3DFXsT~@dd1*51Xta`n6QRb{}T%H z$HFNm?=R)$+M}65TQ|{ol#h`%zc(36Mo20Ou+ZG!eu2ZK(PEnh9uMQ~!k$F1q@_D_G4afr0w9NA;Yvv2Dx~6q&{S17=};lw|T56$Y5KcJqgd~ z+?7jIh5ni3GOmKORi->ES|k3JMo%af-Z=SQROzob`kv9bivp)vJc{g>>0Lj=7ccDY z_uWIKt_C>sw&|^Kyt*(TXjN6=@du@`HfXQJLnOLLS~UxrTsx&Kzp|<}5i`TJ%cmH4 zxVa@oohD1AvBSP%SOR;QjtA2bPe4SZ-BWT)@{NpcB}yYGp>PgYfybr(ca1X5b{LV9 za8{eqNUpf&>R-73i4)yXJ!#lKn;lh4&CBDDkB@&&fQLuRlcH8!=Mlkr@ls)mjI{QH zMseL^{PD4|YVvu-^B4l!H^<}1oszt)u+`3guNtWMVB6P7r5pBGzdE5eL!VwMXrL@c zfg7XC*JQ%@@q0m0lGp=3LtWkR_7qmt+^uM)AE;z7T(}`m!wfSkYawNXFaG;7mo9W+ zzO^EJOj11g$vUbhEeIQ@`hZvJ>I31)a(Bqp>%$IrCX|2u=nWhl9brL1L1GPK@+>LU z_|aU*AmXt%f_glQIE#nIkzLhzsBk>gk9E$|m7iYa1-~D}YdVUM?OlBeb(Eds;JARyXLHB^?Vfb+^OTNe%6TLiD`l-;o@No zh+nsji@x)@YyHV}17dh%7)T! z9Se*5=boO&BZ;(P5R+QlI2st9fC7Cd#?n}tS;>S?FEfj&l_)y>fs1b~`bxyQ8<^rj z!i(0k?r6MN;?5%XwzKz1=pK)HGCFBZC{3g2t<;Q+W?Ye{l0lAd*USWe_Ots(wY@BV zG01`VX0lHhb(n0^moO0CN0y~1dGi!OK!W%*xF2`m`%Q@@v;VIby;QU=UBcy(YbF-@ND&liCgre;qYD6Sbp`>o8;KIBVK7){L9 z@miKC=!_$ctFf}uO%qtoc|SwoUgzEI^_eshtNt47?94yAyKAg0EN-18-s2ld-vfT+ zhiLsZq)zNZi|q3FR$Oe)>(oQ0Ev>tQBV!an-3}f|GB~KrZqsbcoxT*F7b-rsPR&KU zS2b*}fWlby<;xWpC+DlPgT>b8OF<{YSU9Ug*d~H>7}M3j|48%kxnY>%FsG;;e2>q1 zHl^@@31{HpgWlKc>+5dMiUi5)f7=SuU)^0F?w*{S82_Q>mE!2%4K2WQsSqM=YLws@ zoAKOvILMCq`BEf%INjvydrkQ5%^-h=OUTtuiSc$9p@oBV@uNqQe9<&$7u}wL8zbMn zXd^PBDOk!5Q_;*_#xWcA*Xrx*%e8Z*n^*d1-KFt{2m=2QO4vEzD=+tkLhUMQYNLfcFbgL2=I&b6;Xd^ai63U#6~|dDonbg7v+AR`l!A zh=LjViWsWSyd7e<9mHAk`SXGt@Rsw_6~<})gS?GVQXi{6G~0M}7*cE;H&oTc5x2C> ziYDPKU?S~8^9=;_aQtwK^dy)B1at+0kRF&Jw-cjs_dzr?Ywge>Vu_`Z-6=y0a_9Ov zU7W>0`goSwBRk9~e6H`qugwZ{PUDl4J6ylNChL#+?J7j~-= zOT_q|osA7&b$e-)LIn(rZ8~*u!?C8OM(k{7Vk=iUo+6P>%#AMoQm+p^ym4(Mx}u_@ zW+tBs`by$guNs>kkM)i{h{V%phs*c5jY|Q}Xb~Uqq=^&l>t1O$Oru2} z;0NtJ8;(+P${Vuxei0meJF>8_P&MAUXVmDHLj!x&dTBZn?#p?CUc*aI(qeOLE&XQ9 zPW4nt|La>ddXzT?SyW_X-oYIqx9g#ICwZ>st-gyVAXt2%TW-*4K#!*R_|0jG8+ZN} z32h&`xQq2zkqo8U=W;x$DAu5ob1;&FScU)x0}~Sys%Ux~IPdqQZD2|x;+Y!0{CNC` z=i>%qY`>df41CXPDjM?Zvw8}K1zHt-i%j4--J7vC?1Dg{hRBD1_(0pJU>@8RDVxqPR6qFX zujkVmIg%m~2-jQhI^azraK{1fOG!mZLGgaP=y^tVe==j}Nk3!gN7TgDYjwpGMdpieXD6pmvmq@; zn`B`554#P^49?ZHv~q>q7MgY$LXcK>_J5e`b8OYZGt6gRzkZEtU4tYHlB9A##f@9v zmwhC^H801@>v{leON@lZ?+Q->`9^U&qE6^npL)@+*s=Yj{)~5%1Zr%IPgNhkS5;9- z`nMy^K@iPh3UgP}Xo$vu8P9!CDWvAh7@Qp-5jrlyak^tm)n1{cprw`anJm@C3%$GC zN&(T1s7$ynADh25?BC4AjkTrmzU|EDE}KnL3qiH8Gc#N8VO2?J3LgKY+&$2cALBk2 z*;r7(tXpQV^jhnJ1D@nLxuDK=p8^2CmWBr0_jG$)?6Gkz+Z2fx&Xq=N{+)+QqX4vJ z;%Fp5NuK(07_Koc^fEXA}iiY-!^-tJS z&7=g$3XQD*g585I`(n3}`kgC?joIT8;py;D%Z@+n} z${75O6GQinv5q*T*-Z99RhPkI-KW?v&}=n8nKX`#ML@uFXr{(SHOvxE-3u;DDkY}* z^(B$-$LzlI>7q#iQm!9JS}=S{)p{WS0@s+4(vQv$32cwv6SqD;)V=_)H zxc%StfpKC)a~moyM0LdNjS@>U!(j|MJ!LqUO=q|~TdE4Ml+%Mn+Qh?m2mjr03HZZD z7>D>#2Z=_@0+Wx`Kfm>8OW6+KH1}Kdnb;i4OhZA1XDD`tXK0oJD4r?Pfrhd_@4lDLU`S)(U&aHeybhr;kQZ;WSBhy&vvKX*Yo8g zKcP*XVLgP+a)=un8{4px4m^f8`xJ73d*wcSpiD`3re$7hi#vEo@Iw=dh6S%sAR{IH zMbgqJuJtY-SA>)cqnBgu)2B~Z`1F#eF_$M>7ZE5Q9q_1*7$l);Z)jo=cAU>1m0qT( zF%wuQTU)RGSm}u++5uUpIL6EyQO_`g+EVxBb{P`5{@A{K>O6ajg6R)bbtNSw{-}c) z5OU69Q0DuYnL1lt=SAZHe2#VVqX{X)Frm?4iH7eeBY(C+cLW1gzsD7}`0oE~UJ4VZ zSvp)se0fpM7Kugh^Xax$@0$a~{X``e&j)yT&kx57`)6L|`g5>?u!}of1L;`m?>g*~ za+-W(Y-`IlX!~zWaqBLD$}Em9E_SYGL`-`m?7#RE+)AQe4Kg+d1?vo;4 z_ui7gS!VO;YgKdU|>q-(H>V?xIv#^atGj)vS^Fm$DF*8Ax`e3_MM9Vk0f% zwO0e{KOrP2sB*JH6uONY!mxX0+D}VHCPY^t#Xxi73#h4`XO)JzA3nf_Pj@C_am@Im zX)4(OqVro0=1fy#o3>Qe<3Nv7a%yB@Vfm#Ksi&{sGlqJ-?B;}HJ{A@A?To@Diy>r`m7YU|ba=IephJ8) z6&mL;87sT^2li6|5_qq{5wE4GX%{FCjo!p052@2_v50(VEOn-)rqV6B%D;U1@`#_m>M<|x zS1xXDy^XD{X&YS-XK9?AoHUSY4N*}T#sL8>pI(jTlC%Y!z0rF9JYLz4ESa7+E-}mF zLna*=*@R|+&Uc;t7`N}tf`X*ks#U1LSEmE*9xD;KTLE7y=%b}!nP*j%l?S}(&#Jmg z1c<{*7}MtXFv7DCDVHjoCSE0ml6P<=0w;DTJC5Lv%?IGjr|GJ>+A;K7goXl{^Y_o;Fa#o z@~<++Sl*%}>>hgnL(O_s(HmjS2%&iR&>=7Qd{zc2on3z|wj7k^$}0W|#5Pt^VE8*u zm?bmMMB(H1D?UpR=#S}z`HQP1Ic9^ogh$!sUJ{6PB2xbq*z~S)7 z+1Xj_3_kM!#AKO1fpmV>{3AoOs{IED@_I~&>dLP-pFuRRLXi~?LLPmfv^|q^p{R{bqZ#A6`k^^tG96oE&A3wB5*7HHmJV*QnZ3MAqV>3!5<^ zN7CnyEmSqFrblJ`1p&=;wje-jcL2?|!>xL-c$d#&zO0egEUwLdrjg}rq|GP1*qg0u z4Y@s=&f$k2bqk>CG!Njj9yarAH*9)D^EL7wwRm-Wm9XSQO1`1UWvN)8;OcFmRz zzVe}_rk?nLirsE2Xlw?e3^oTR=OOl18*P*5st@vN;aEjgm6I7Z`%J`(3bhza9eOrM zpU$@nlMhJ5O>KChukX?o9`MP}&prMYAB8+eGeR47zT7bLUybARMXa?~b=(Cke~%+` z2QHUZ+fXXMi#GS&JK-lnLUni{#`q!CZ-z?{IdY-xR0Z>Ow@mcNaPe!P)xp>2 zuEucKaWO#hlP3$jJXop%Egmhd(PS>JUG==pNI6kT9XEn*6^1aoAe3eQt(=Y|Itjt+ z{l?{7DVLdQV+YcJ@hKwd8eKd{YwkbSTA=etiy9xRtg45gU1O27?d-RyI!uh_buepY zma648@Rz2?Ep2knzbo>HTk4Ud&+#TKb!{9ybZ0KUCFKd>Sh~pD*IL(0tRGxBJ5yZK z(jhe?Xrq^o8AQ4-Lbt~XYPs}_gRaI^8E^LijN2{4#3&|i!rj@~3Emveo-RuFQ2Y@_ z2?!#+@qPPoQmcDIMMcHg7N1?&OlkkWf$r^>o4D8&P&CAEDTXP+*E@7_{o%j&!oK!D zohKnyJi%bXwmuL#c4s>uJzek~wOe}?8a!QTehBC}QYVsd_J%0&e;Z!)2^Rv}RQYQ1 z*xIgIxb|-BW1;$AMf3Kc%k94#gL2kIVsG6u0L}MK63_~V-=Nedbdt1A)Ow(Qp%vDycou|d zVbKRO?%(D}Q40uT%mtBU5>Py1x3`C(_sjoyv@Mjh@Gbl^KBmFswT2z1%VR_6pc?{kenMXSPF2(b(?ZPc!C7O~??&hfH0_20QMC(cKDV?1je|;<~ zD@&avHiXN2)DGD8Re)0Z2W)G*jF>$!AopYuL#a7Aw`AQLvB1bmF%&)NiQrfsS|rY7 zO>{0K-_S|k*^pEg)>K!#FBof|_`HFv^TJLDT)nsJZ=2~Lp`hp^R2M1GVoFHfKD$x` z;PLwUY}YSqt6~1*4{taJM)eDv6_A(Z&H&cilriW?{tTeA1A9|+o$_P%a~AhcVDW$Z z0dVfw>bw8T>Uu0P`Pa{&Uq;0mnJg-UqYYt0D06W`hfz-r0HC^!rFCms!44msYCtu2 z`*A?(fZv2OkBV$9VSQ{IvS)iV)IKQqKKI8Pg#s8=Y)1V|hws|*BE-Ppn+OljF8&2X z0;dtnvR|fqb^9&vd(p$$x_&|1A8$hsmODCDvYacMlYLyA09hT-JHya2`ca~;f4oq& zyxKhK{o2$Hl+@+(-;I+ zOW-VIBK2A_q)h41V1zuGnVHHoiS~uhimpUJ@?gji_O;UN$;HQu;1G=_+)lvCUGleB zESBmPGQ1nym@K|E0xTEJygWZ0J$>vZu4qjoeHA~)w31W3Ndmz;%?e%CGokHDi;g=} zY-sZsnpoF&&5w@$h>e%I67m_@vkEgKjV520KegUc53;x`HY(dt#<#}C#>%}*P5t}z zW%+H(w{NFnV^m^pb8M}SFGrM-;goJqBD^1D{ezr&^dNg>h5nwJOuaF5K+Y@?ELQU# zt-){T4)Zbj+1S~+=+YjUmvJGrVc`;s{wJGX$)6gshE?jra)Iv#aAD0nNo$d5PpIOvS+X&jnYt01y4u5DG7P;4|N ziSaQrGq-_c&AD%#@bn9e%28>BC6So{%3Z9lw&^R zCeccFkm*-PMNKHX2?Bs0N+zHc-D^utO;tT&#~i(Fz_chYAM1Hd!YV5r zc)qtaS$p&Qi~|5TxZnNVZI6G_bb00UJc8V6E8*RtnRu{R6+h*!brk%k ztmHlU!-qE-yhHr%-)aF_`VI_BNnsFIw5oG@H%UxTP>@Crh7~@2Va@YvDdc)TkKVt9 z4qA`4E!pdR$v15)INZ5=sU4^E_aV}P?!t*ZF+M)fwmS;feMNIeMODhx1oFq4Q`l-@ znsAxdwBcRo$*>rsp`qbn;rq?dm6-3}zaNxRIrJ;M;i(A0$M274e?xz)cx=A>X20zS zjI84FbVB>2Q^GExW4-akHcet*G>m?^uS6)aCIleyO2C&M?gB(&0xKGe#6!;Qp7c^$ zNH>FhKk6g7Xs6v_QLcsk$8NCG%;cx_`FS@VwV~Q@w=a)PiB5liziN20=+Lq9OGUQ% z!f?7O_j&-;Eb{y}GjAi9YoBO0ifrF$ai`xA;Z?Y6^L~? zcVt`IX!S~INzTtiWrevzK^n^oz~dp!-Ix)|VsSJHUpF5A58K*lMLQmCmvVF9?ao!B z4!sHM#u$($FrUFB3KLyDy}xqWZK{M7Rz!06?^8)jL-zzqn|Czg%k*NF31N8vLZn>>b<3p(cJU)Q3kplI6- z6cfRyIR|;OrR?A7^k60?bJkIZ)(keLH9YClI!BkY z&%5bMP_kABtt!*dOU!R#OE`bXd4Amf1!XFV`EtW5ah$&cA}I<5YVXw8pjp*K-?h-~ zvGsFhgR?q%Sq+=;V<^U^cF(3+p?QUCnKaQpDeqEJj%NT7RfR1-)JTAwbBD^^p6XA5 zEI337v9qw(mo0VrnuLi)yn2J^#mk5tzYg@XLH@{s_N9Xm31kd+7zx}HEafpDox4si z%-D>bgcdh^8e0<3S|h3q{%aMVc$@*k z3Kk~Lx`261IYy_s#(<3ew(8R->#x`f%!$g}nBzmgg>EYDFNsRGMzI%nCNvK+@&YKV zrv>-~1X2!Rk%aICZ1sHl0XRQYi~ul|i#t^3G-l%Fe3iS<;qIQEJe=RsizD11^ZYxM zDa2^shdY<+f=;}S%mujo6*SxD0E>VA;nJP>_JfOo#a4MaX9|Y~ml`PxzEfhSqh1o2 zFn6ElVicDhLv)oPJ-;cLwg4orX|WB|0&c84WJ7YKDoc9r@RFJi6ag_I@TKi{bkAg~ zx0lxp8lD~Pk!wv=55S_0FJ8WMJBr%vb;kOY!ixH-aQ<%PkJFRFlNbCJOY1?i-%TGy z(|ZV0(t>3qA4;NpS!qU{l=z89l#t!W_z*WIAp}I}zykl&e#FoHzXjzl%VX7weyK9S z-lGQgslQfA1-1C)dh6Z?zAh;dlwQP*q+SkQZOzTi9Zf>N2cv2BRGEv4(T-|q=N#xP z&EZtSp?5;tJ}t!+u{z=Wf7KYs$jI_CGY7P}@G5nBw#N&NxvBR%cI|+bGTs327fPHZ zL>+~#-+&{4Al?gqx_s1U`X(WP4!U1Iy)@w6R?8Dbw|Be*u%dfedAYZ93_3O>kXo#A z@qYAtL@Gb{#&b+eILhp&F(8g^0NY0fn;zmhI?Gy9em=@E#Zp!tVE8YI!*I)BwDw5v z^&pcBzb@UJt8!axS*!(dE)xMSiNvXVYwdgacOx+ug&$8WpZstp6jJ{HibomI-ZIA! zfRI|YjNvy`8*g-9ZptSR$&a@tbAD)l^og5?XO!2x1u91bS1Fj^P^6?0(w>QHt}zIt zr>RvTqL+kLcAhn0Eptp?1DG2a`LbN*Pl^Y6wxzyrMQdDxixrQ|Qw!r+mObK%qh9Bd zZBWn|i^!n=Iz;C#?xTOWb8~spuk}&9fb{9~!2aJ*2IguM+Esc3Z+b%z0_@!YX$tP& z^2b86@*+)Jw(Lt;+3W`HG|&DlS-y5&(*6CO%M)oN)Ar9nMYQ%G?8ONRGNb>6d^fxV#GU=ghn|PFbE{ge? z3;O{zJ+qYhW>beV^>_)%(r7JTzT}Ud*(HgIii-AOLS-IUR7KNN3w%d$#oQ4|PfyPY z+9}G=!s*7p`Dk9k@Oj+9$mN3KOS4wCPQW9IrkeSCb z&brY>rKJuX^HQSExt<@~oYSlxwxi#gx`*?rodji4L@_U6#c+}7kPAIov=?_xV3u^or z?*req)PqH1N!=~;6}fxds~6>aBVseYqBco}d>N_{yGXarei${(SS2!{rFaW4(IExZ z)jFf-{LA})y9PCbvTA>D^J{6RHTd}l{kNHnB@ZzB`fBm0C^zzp)8QlUEX6E8v9&ZTN{qEG+^L-pbzNW zBSVOP5ioqiEZaI^VPQHy?@)A4nD}eb#X6BUYDH*9a4M*XhzrJ|!;sBd} z(8VKdt)6HwnGt(1m0ezBwy$&08xFx0f=wMO*bwp$X9XHit0vVh^VdBHZ+UFmv>^iKXX-V)bN+XdMyQP7ey| z8u3+$73}gJy`l4?_~~#IVZi<37&yOO7{Z5q-nB(kFmsRQi%4=5tsp(3Ep@Fv^5SwU zuc~|HTG>w$A{EBUvT)rsbF2`086RvcAh$&O<49T56G09s?94Mmf5v|D=Fgu$Kl3G2 zCx2nVl%u1gGiSDAbiOuQ0Aw6|cN8mUdqj7bUQ1hnQ-jv%C!Kj+7`Q6vVqMk#XFWgy ziS_BTUK##J&Z!9Q-<|W(OL*Dxqe4x0-9`N(8wZX9 zaAJPdJ9l{?J#?BN4B1LcSJ_Jm$9mWo5rBB(HuY{5-GX$TFYYUfY)beXF3Ff9V5Z_+ zAs-D(CdgZFHL37(!^tJhcP#Fm{Mr0~`1p9S^AcnJw{Lr`1!I&^S?hA-*Y+iEtv}nkPu%Ao9yPZSisDv1AF~x9 zhPCB`;(;Whm%tQH=;<0z&=}a{>KhmsWW4O$O-*sCZ|UB5|5V)P%}9*Ob3fgYW!)A| z<7Jsiu!L60-^uf-a@!xoka82xR#8fXW--ml$L{WKQWzrrn?ORnMIK;go&4^Czl~Y) z@?TVBOZpK$<}-5-lYms!J=0iZZF-lHQ9>aOG361H$6CVpA~336paXTtGwj!#(6pb# z`u+1+^$P>oop<{Q;r7%YOYth+N1W3xljLoyFdsg%%Hgv_$isgVH()EcQfcTKLvy}2 zTj;a3+_=7hx(&^}|2TBUAVX7~=CZJ3xO9`fgi)2*@@Xr&=LOm5@!XsjJSj0=jUiQu zMOOjaw+;CHjCnocy`;vb8Rxtg=V#NtM_ASn{&wy7#{1%#c*dm8-L{lyO=SJB4}boG zleRBkjnRWjLnVp0=Uj?9^9z&HH1zIP1=F(SUe~@)GTw=6)?z+u>Y{Y{Tf8QsYj_F= zNtf-|RaBOa3K(i!P9P_p-M6!of919L#J8xU-@HpeU$qkS`EYblt_sSN--nf@1u6#9`s9LU>2c?;i9-vZrR9@Xgl@Z!(bi%Q5M#?n*CLW1QIT(~s$ zhGu_x30NUJTU#Y)e&mx{t9vOa0fuP;r}_n+_A@qh$x zfIf8E%nZMeG303A)%*QrMjeEmM)!r&DF?I-7b03#iJCQZ+yv5bviyxK@Ar}%UIGvK z{#h9C2u1mdt$UM;uA*4TC}J;#5<+_6kuziP|Yt&TB2Ip&zT3C0!3M(Mryf<8U_ zRDK0UTdiXs85`X*#fSLVJ^5u)(*`U zD&_GeY^3VRBX^pMf2J(w>IYxt%`$BHgk|7~AccYe@REeIiS^(^2t*LrwqyiYf0A-v zXlQ6W5a-u-^@($`vRd(Pp$@22WEA(vC!TB6|7fmP_U+ZH1wQnTn~Q$Iw_T`C&e`4g zcZ86jWDdGZ$4&{XL(l15f}=S)Mx71o^SA5vU{FQof&2BIhyZU2&VDJtXP>|t<<#pp zL#BTJhFpOhH@@?X&y&~p&3v=>D>TU^Emw`I+bicPzAOjL)YVmvBdn(h)1?zTNZRNA z>?6CwI*RnXpN`<`UjBQ4vR$IBgbUy`UiuPFWnBa0>x*i_&^7rb?ay+@JyVJr^o212 zz7s_bp|E?~24$YPp5E#@Ok(?rH7Ij!%BkK7=NDDgu#2dEY1i|gKY#w&LWA=W8CR5- zODTwKh5&l`t^x(_>NY_QbgEOaNrL$z@MEkG+E@JuWxW?053P?*sN9_q1W6TG@H&GD zmIsHWAc4k*^J>W=ir$IjocLUw?nJr>E7WhwQYWgM^(E4dKHcS%5%Y24OV{8?BWN|* zrXiw7+Yh~46U(z$7#qWYgj$FWdBMhmCKcynu`nvvdRw27zidxxDcVYZ`*y6uq9bGl z4cRi}@6cTf)yB{C6`--oDi5!mvP7Ah(5~~2 zyxBadBk+zII};6x4sEQz2t!O68W>C}3{tu4XjIlr7SVt$_K==_aTi1}Ml3_w!@)l| zVtd5^GXV8r+8SER$2He3F8F04S$watA$mp&XC6jchFDKC3(UXs?B$2>>%ii8O8Jxh z#{8>}`^YR+#^^82-twWyYJGU-eaMHkUfLp_{$1Uz-Foy#vpbETf`%tfo8wXxco4GThl37xI$0%_@Slri>_yHz zq&fWzTPj7^2}aOo!r4UiMLIrV%3(YX>t3>L!u>(a&tToHft+p zb2qojqcEf7WiB`-WFD+YIp9(C<;^Fgo`FikW>dRfNK+Td)&@~YMdO0k;4Fw6UxASL zLT}hd3xI6N)8l@|Eh$T9uZJ098>_8e%|QyP;f2f1WHb<17yoYO7lQ_>gI3xmduYSl zVF&i&&vZ-K;FhVp^qU=R%eRB_PQta)j#4ho-Jf5UI}LHP`CIA5~$ zmx_vyQBOb2kZe^HBPuBFKr z$Y{ipgNgX)Rz=hHX=ID?YN0@wgPP6sHv>WoOj-j9<`;*(TUBz`Had4P7H_XF{&DlW za|Gs5u4f-5ESo*Ls&>0Rr2e{L_V2kWCp2dge!&k%5fNKnxbt2oZt}r#JXp6eObbG` z1wgnn$xYNR@wRo)g)39Pbhm1e`{*7%;^X7n1w`7%7;U>G7HFH+N{m%c%&nQZx#m&Z zgN@D2g8)Q0w(n8?Aa+&x$YbC-TGUxm5*&%3!^+A!BEga$k{HgeTb{6UO7-ehQM8|D zYbv5oE(G$I-rrpi-dZe%q2}-Z>Scf+!gzxCC37k(KYdczaNQ1|hXV!Wlo1IAg#Urm z#Y1dp^a@tWlZ8%8&x3_##^X&RZINlzu@4$9UEf8qZ4)C_xrZ#PLZcM~TFu9Jxx)X@ zx*cVwJG!=8#9=%hANOsl*$XfCX+2k$fR>4zY(<7leIdNR|3fX*`4gQlkl$=Yv!d)x ze7ticHT;}N|HX^m&gTVK{M-@}{;Qzw-;dy-Y=TsVpL99rKC$Y)0(hUX45Z2++Peh* z9pJ3idlXfDBrtFf~Kg5Ra36ohrGV|IDwAfV>oZWopZ5cTnychWGr$9^^AYmCewmxX15 zD*czby1HFhAFH?`!OYV$SO(WOldn!ke?5N|Q~-wDxdUucbwXsr`;|@+*$JS6_V)7j z?kG5|_%LFY-TJ1irjSF!FvJQWB^*GeIndhuj3IyjPi(_Lt z5sWRbCF?Ju68Y>Gnmp_15F0&)-|@seDyL=5+BdVD+dE?}$)_N@k^!gNE%WXj!EJ>j zr|@oVR%d~-7`{ERnaed(^yI4^qJo3F>tJ6ulM+y#kk=d|C)}S$w>ZDty+7rwerXY` zq&MHuaqE6kFxY`=lzF0G&I1H9<*+ewzFopxuu(SueyK4lZu4&|2gf~V#a!ov@i1y2 zUCbX|G6WI)lN*(Y(-j8Onc+z7r~DIUc6j*oM!IFYQK|+tGUHP;?J)u3!}Zx2a_zjR zI-J8BD*R#M*T?+9bl=uR5JB#T#c~1|`yg#uor4nQFPn--8X}a?jdU$6s(erv5qKii zpC)!_fQ`t$6x<))Rjx5Q1p17vC668gT!rbu^`B?5*L!uZz(UH&8=2+PxV!}ZtqbUY z?i#%|exjj5=e=4#0gOZiZM_I%Y8WJ_a%O<#_c-d`eZCqm?20+sP^@AVfLynCBQK@u zSVnVSq`aHNFf|;>&XLpww=yv{E{lF|>W4)S+dqrwnGT3@XOMs#@^EoE{`pn({4lIR zhz@xqvH+dXH1+cGdcXE4`WH%9?zM3%Aer)V0}q-N$LOZ*=#4l%T6rZs0K*)K6P_Ji zEx;h>W3@ZPs|%`gdv1_UHYUz~PqO)N}IAK`&yLRJZ8O$w#-ybUxdh=|{G?nmK%!&xFGH=SEGBpK)fyAOzn z4uyRFOiKNe|M)Xw*D$SHZgfq{zGILLLjKh+(Ynnbm{6!$`tW=X2uS?AH-|3sK$)sb zqJd|@LHQeyc|`*T_hGr;+llI{<@=bqd3S7QWrX{jp@=iZJnR#fPrO{2PmvCKV`QdV z?*lR7J}m3_qG70LqKbZxRv0K<*AmY83F|+NoOW9yVw826ZSu6K0cGK*mD6I+)YY3e zz&Vf5r`rLT%-Gk0*6nq)lF;pIPOXnd6iy=<66R4`(?a$`MjL1?L5szH=%fnrCU|+4HVvPB||}j_+k# z!(SR2QXbCK6q2egb+-ve9Bea|?7qv+b{^Y3qvUeimI8^96;^=_I_?Gvw}$lNoP;`c8Zst%VMD zHg?6a^$A3jEfPs0V~?3Zj@(Iicvta6334i22PuQae32_fE~t zjSqX70=(vcsBF*_IIr`22k^LJ4Q`89FI`>tXP;JLH>?bU5^A*zI74uM`*)E4UJuQ-{F@+nd7`K62s zINf*TH3p)-U|gRykPpz^YIfGGg^kjvk`DCz%a6a zytFbpPK@xjR}TZw3a%qIPe$#|WuVE7L_bCKg{;sfwKG>S%n9N21Iu=`zo*fKg`28m zXz_{9cdO0|Ly$$FJ_HA+7T!=o5V17ypG+1J8M7f2&drFP3wbXbsb?B0Dt-FEtp=)5 z`FfyQ#N#1Ff!>U#AAq2xtMhsHdp#YUY7t^tF)4}Fe--F0AVj#k1}d!ezlvOYLK1I? zTYNKYy=9-r$X_%XC5L_ig)ldX~hivx8M($*k|(yerbJ{F*(`M32#|vDmB`s2(YScwttu7qR12RC_`x$ILt*0o-xFDvimX8*XJ8<(u;4s+r`95|Ya7gG87d%mX zj7?g{X3WsDfZG#~^S#upScW$O^b({)0$h(;?nB0ss8F9_LwmZr_oA~6oZTN#FCVi| zFA_qEUz77ZmGj~LaCFP;w+pge{ck{^X%fD677#R@fvBJMfAJ!{sHsVuQEJ_P?+6!G zg3o$-sXBvNHGl_H*W;nLyB7DC2d#%*)H@V}O@v4^;r`&Sm59O4vrcp(m#%(uZJ9HJ zJdm*`0M*QW^}BcPm}hhgrEiTrkX3!4TnN;JoFT}SSQ{`DN7T`sBckHQjfTQx!m931-$6%=D}^z!gADE;)Qd%LMv)>M2&3~~FXyoyFpNJtwP7x{|vo_6VpoHEF;yPPLa zz?23v1RZq|jVphlM`^&}m~%;*jz$qZ?&R@)c;~$n%NPP9#2fTjImg*#R2=31nwT4P zY|rcwJ+>hy*7%FMxjN#OSxn5(O)xXJvx>1wvA@#1;qi7=@GYXtg-)^8AsXB_8k0{n=QIyeBwCyV;xlBeAOB#@V!^$q?%vPdH}sl2At51&@3%^C1Zu%i zJy+beo76x6aHf<2PvTaeCq0}v&l}l2LQlbFEm|)38h-${Fj&xQt+#pP?^}kOw8622 z*^lB0s+e9XLbwNJo%z=zNk%&4xuILh9bzWk!6wc4K3tcWy^^j_1VNti=-z_C<%mN5 z<;8Y>>qab}Sw03}0spZpXLut(ZuVr;)U>XU(up@(v&UjgtZxJQh===Lm9x{&sn4np zad*2OjvV9nIKv@6nh5Zee*eDt24%ptNkH-*tz-aZ1gPNrGUsa_sBTZgZVj-9J~+!e z96%rY$);kLRi`V*6L0dkVK+_b=kUpVdKg??y%LxcZla?@$w)`UnRR5&nDKy;{%G$93&O&(ddQRsYw#+p2KJ&pKYbo z*w};BZ23ETN!zvLH=&K&$3Hqg-l{*iNKO>^q_IZE)4juZ`0wa6F*1^7Q)x&~&=SGw zBP$9FjKe6fjF5pRTzK3k`-XVaxz{j0$glOmzo!j)#4oYQejQ6zh}54M-RwK^JVZ@u ze%P%MU@W+N61gsP705S>j+H~zyPEWx&L#jMkTX-2QhZ*$%eSH5j+N+Y{tF(zjyN*Y zmTmM-o5RZ;V#uXr_W+qFaC~xJ0$!_&Sn>`(0WUi#WZ9Rfr{GMAU^$x{Sq8qs_9n|v zN)A$P{b777F+>nkjbg&w`0wegUt!5uu;{xvp%1Z61Ft0O3KAPhm{)fPjOcvqhw;YS zqFBAv81TsOuG3ia6=@Md7APv8-PE(j=M)q!tzeI?-GU_UL8gygSCdWt)Kes~DvI=Z z(z(f^I!*Vj#P4!pq8Xo%LW3;;yWTS4@RVnuzkkoD()u}@7&Gr$KW^Qpm=WXO83LPA zdg7U7V&!F~YFct~ayf05^$d)Aq68nAN4lii0H?eC$g=E7*>H0)vlonou|TC(;-B-2{-I7YG0D z8oe2&jG*pOlM-Kpd=d;+T~V7rUIA;Mxm*PJ<%iMbn{PmqZe_DRdvX9QRzm-B$+YHC{#Z}k$N!L~*Y4r| z07#u8z+AToW-|`DTL{hOIHLz{S!KIx9X{9zP4Jl##HwY>?`3^1ENq)7%NW;^4lddD zs~hO_dpI6g*U0W0CUci%$^aZ5`i^Tm>Pk!dn*gQp6=;z=;Be0nNh6hmp}P0pW;3_@ z$8vi-fJLgVSRDJy{3dUr*MQG&g)buByz|-Nw@vY)l{E``$ zTP$Xmw|g{8>%7luzVZmJt*gUzGWB{mPsT#p5*hv$$hu0a0%8T=aLTh#WMs0H z5{{0LX+H@;Ct5u8tzeYDwzwtweS0JN8lJ58AI=l`PqPLYWM--LW=c&$_Q76{wcW#e zZdmW`-ZT$>A{qS5$LU}mvh^h1MP#_WSxPw!W15H)QMLm_iZ#HsTXd4XVKzTAl&9(= z77ZH-J!PC&cw?`EiYj-vsBdzit6*SDp$$*gG~}kMdpe!FRFhX@C!#P2tBdSYJ|E={ zmx^+!jTy=O)SFB18tdnl<6U!gBr57y_T$IXJaOLy*lP(l0a_vg!UyiMD32qq38^cO zUR2DFpLdJIb~f+xg$WL_yVcdx{*wNcngXT0EmZMgAV_KYd$dS(skQ3=TOR{d9c2%K zH{@|&l;pAdK8y&{P|5AO)ka=D6ovg0nG19w?)v)r<>>LoDy|?Uo5~mTnSLR~AEvMzm{AFlPmdTQwLmcFA`&=3GcH8m;PiDIHbc#Ne zpRT61Wo7i7z#XtEB$k}>dL=y|fAZdR?@N2rBX_hQ2TM&eAC#%}-dANdHMU5b7InnA~Xx8lD6m)jJ-V@?^*X$mz zNG3mE=#GgpAor@sk?>dd-K{eulTiWt5N4)o?(9t+JgdWo%3UI{^Scm2PBrSw_*NU(21yMKnz!8yn$N6p9Bz)`;pa{4kUi+;3z0hh zQcN~S2kgqCa#djfpM?J2IY^@~WPSd8-iX0qq|c=2dUei^`Hizh32Cvg5&VT>sM_T!FEUg*p8gD20Hut9;+vIjmfG-Ptf}qjb3B0_3-}dNWeogZUmO~s&|Nvq)aZ$lNJMR``$nE z4dw8Z#_?8 zY(S?Aa^y)3lkiFJi|Oj=)ht?9I=F~1v}H_){daP{2|aD$Uknk|UGO6A{31mxSWA?& zrt^HZZp)Y72Yd2ByuloA0XSN%F3)G}Kz)<$gS!*~ga}KUSz0FXdz$-=N42y0UN^yM zeXq&2)VHIqc8fSHzv!pN4kC+%J z?)=XfVmZEy*;n<<`$h~e-#=x#PuMdbahnLh8u#%cz z-`?0S^74@D3cJ#OoDYIC))U2G0S<^|XYLsyEtJL6h6&DtiGBTDj@HW(BMe|=#2+Ax zOEA#Wr`T*3c2vs?|3cp1Pho@}gid1P$sQ<>MI_M&TSiDz~k)f>{Z{lqQCsuark=`+!~hGeHOqKut7)O z(^nL^CEBSx!p(--S|I6Y)7j=7wZA%Sl1o5hm7}flbN?|E6qB96P}pL zC{f!|TYFN`WnG}>%8F$s5pW&sj^}%Oqv>}#e^UJ<^ljUo9|hu0H=9rU0~rUMBTdzkf8$gvUd80Z z+4|*pNwNHK(;IbGJbf|rPt@)RRid0c!y0)2_WhPv4e9f>6@c`If{L|ixyDRf(E#3^ zk>~0C{ELh0%1lsC#pn;SH5$dN(dQ$!&qb_pkV|boS|N{Lu`9UnvXkSOXM~Uk7?GB! z=W5HGEk(uExz3*G+1jqVWw{WWe>S=)pZw#$Uj}6@Wt5)l+Z8BB9Ze;b_S>-MU*T@N~{w;{+5yw1P(+iP#~O${;s^0tqf|==s9Sy=Iys z0wX+QJkxTI5nH|tGV`E%tNwe4?=AT7?s+%SOh)*?J)y@4AmZ;13=WzBdYga5PP`5G z->vjmR=lpTvi$YS#j7!Ae7(o_+0t(b4jQ*iX-1bS`|+;h0$s=)+v98rGq_l@iwR@(g9|289_tl87rq`L^j1j>Gy~gCFwme7R0bIWfiyQxioKrr%@iexZB^ zx9xfcATSjT{6lB>XwC7@JCITvh%eTX_V)rxOpQiuE~quM0;N&PAX|K`q^p+V`4|?8r#EM0{$?}Cz0Y0o`;HS0TNJ) z64f}M?20}%ZxRav8O=r3VE<=+LhQJuifpX`4EjEG!c}&{5jq6(Q}TDpP2uxTloi9# zZTM{g^S(aG%|%Y(udvX6J4kRAhT7|znoO@dDK%aLk!!ODXf`fYGe5p%x`z|7u9J=V z?z=5IgVDohpW)qT&=U7HtApgRbWYBlPckAA5)r6VtFGPMuTqIKk{F?sxk}JQ@GmMDZ&*j@1egt|P|BibL zp^~xsj#g!S&Fzd!NdR9)6u+&o&)D%_A;uj?JAmTX@V8zG(l1Iae){xjuc$%+qC{_P z6SCMs{{Hv_=S*(tFN)Q5jqf#pxE(n53XddWZ|+$=NEOwEfkSOENZ8VX%7TYhCGj-zR}TVIoEUUNJ-nh= z9}zy@+G5#^sB5k?Ggz`+F@;Y$xjse**T7qdiic(5(CY*6(CN5Voe%Gz2=ivy#byaw z9i6u5{lz3v0TV^VLWyxFxl-+jrk{83efyTr^%%$2oGIF(9%60dQQoB7qnGcBS8mdA zhn2(}8hrjL?m1o*^ya8U#Jke~L`NiV#B>X>Q_g1>WsUVF7c2-$tvd2U(VCiM^f(tSA-R4^ zHenh={u?`2b>(JlV{m2%%zo*NJXLh-%GDc!;l7Bsh03gddMTy~B8wSqv3Hi_3~P%Z1V`imEI|2l%?9S&{Kg0huSY$1=2G0T3_e+MSz zGx+(MRmJwpnr{NX+Xcz}Fef>{Q;`($gJ#DMQ>NZ*~}dJ$rkl8tq{fsCujZ++V6 z7G39uvE=$J)i{LNtxJExAR@b%mGwmsV#HF%PAS`wAu{V}o*5xevJef*Ih3721x@v) z#qC9gCrDV9GD!uhCMPBBM9AebCDslNpGEP{Bs$iw4#^u?}kjd5HDC;rn+9kJbi&g!uyZ@+B04!mEk!KgL5;+OLKLuTNG1#S%UDKRxDMR?q!lYlUV0Q@P{45 zc%)~ShlK@wFT_ll$i4r7-CwBOMoWV)EV|&3I>Y@&6eqMcrYudxBn5;EKZ72oem>xI zH~?#18Mt=+wJ}vKBo*61_y22UyQ@Y=>|ypm7A5Qass!q%a5$GbvWs|*v%u4V3XKC0 z#PE=fP1PI_Wx7MJFU*)JDL)XpiMf7U+t9?8H;B%!JSS-Slt~Nu_LIdW={Yzdh+%AX4wnl#*KrAgjsOK0A?r|nFGKAHF6(tgcpI_get)|A2 z-4{dFsy`KHvE@cGzd_nvuBg33|2l@$`N`qm=W^}+Rhv>XQ+t^IDg~7>L=&e|i?Rs2 z29AO7;1{XJ&?RJqD2T|C^mM=QMQdQ5XF>*CdIt`ZSG!ty{h;$h-Tv^kV6!%G`WCcz z!sn0T3?uwmHt7Ry;UBw*)&Wyf(_k0;^Vr4`@^qGJkv7(}5;40S19Bj>wTi zsqig<@HA_5hwDIFl=K_s*rOv(f?DC%{w0T0?HSnoQROo(Zcua5maBLftFy>f8G(m5 zZxldRVf?>fjJIXzN# z5%aru17^uAZgPie!OrdVI9nQ=Bw|4@?vD;wv@Eexie8A`hVx4Z_Wbnvrm+z9gcmls z1JNjoJe=oWJpQ?o390IN-H=BWD|?n=N?>emQNh+JEcQpD8t^X1|J*4JvHRraLkkn@^b{mZ{?szbUT$q zBFSkeE~U;y6jGbEvhv)$6L`B5$w{imoqix|L?#X8HxcIS@5jo{ zXmhqL>t|y#j;4{^4KOLgX9ZMWd~H^fdPx~CAD?s;AO)I%IlHjTuADL;a~%-2LgX#+y50+M@R08z1H6{z&A%I6qhZ{{#E0>-u4U5V+<=1* z0@7~oHZW{jfvx3DU|EA*5sdy5FyiV}`yE~uZyjMIi6SVQvS*14hTEsj-;F&l)!(mwM{b}Se_=_5-DtTXUnPyIM+ zZq9U4M?*?a%3&n`Kfv!|gRr#re;ZBs7LM{*vij7>z4?W!RTeMkoGip$K>?egavda7 zPm%v{wWy|%$OT*v5|+1NL_N`<_HYY@rLdU2AZ>wdFbekd zs6;)MNw%T@VZ&8y-WnRxCv`e^C^OLy04ErTC`!0j8Xn0i_XU}%DO}?cHxY*<;wq-Z z!ypm=$a4m;?PLzj9|4`{W*?xBi?JgxKiN-=Ge0({U@T1|oId9m+|5JM-4G74B?F7o zIPUOq{@*S^X3=z#@0FC6eEEZUvCe)oxPq_ip#5h5wHlQ9r5!jtT71gLVD5@7FUUG< zTCL%KkST=kvM`sI5rKM5M4RC(__>;cgQEw0@bd6I$Ezt`i_;%(V z)xUq8K_bRaR2`5QVk-@w9E+6G3TzjLMF(Q!q;lQRrF*4+ zEWo0+csd_)*;z6AZO#DfM3N%ln2~W3q1kqIAB`#ZXw!*zGfmd+ zk}Jm++k(pV9p=zV>M|CyBKdEJp{5?ihFiTFC*;06>kZ09VylGv) zx+gjKhR*cbw7}=mwC#B*>de)lHO{(wYCP3io+b62d-%GjcZ;^cvG15en!3omozT%I ziS(V3t=g8iW)vB}zR z`XHc9p0FNaYxPuda;N_zF~FjdXTfbUIh2ic?7L`@M@Of0*KbSXfzCEVrI^xprOeqt+iat-}d^j`*UFA=^MdztTbb4E%OxW zW|>Ht$M|Z?`nvfC&8L&uyvfKSDSK_oC;A*J@ zeSM#E($dmiI1QFwEw;>%d=>sWXs6I|aco&-cW!q4`|n>5r)Bw(n{lO_%wtw@W1WQ% zy`~k38R_eLB*fJD=ZXAS2&wp&3@O-&4?VTk*0Y=@8O~n%DXbYJU0;|kb;t&jA^6VL zxQ7-;t!DFQiEAzvm9*ZXZrt3@ze#pMxGd&F9Sj;hT%Ug3z3T4n{{8Svz)H4Jl^w4I zD4kpZUONeZ+woPN)qICdH&V8|^2Yq9WA$)-d!Ilegq}3AxuYoXl3Sqja@#zNQ8-od zt_M2dEmkop?#*9pn^dtprxm&I@vjQiJ*BAnyOM+-@q4YgZga;`t_sSFgbY|8<%^NC z8j#qnl=7C2+2z@>F>MoLn22cMUqh%pC<3w7jG<|cg+JlJ4!ZL6 z808zwTY{D2mHl_X>ofaX^K#Dn`*jC%V94sPhl?b%(&PatOP8u51rvzQkZFOYf+-WX2HQ^C3^NfoK+VwH zp?`|LzkGXFapj(VGjWKu5^qOAK><|FdxOP#l&!VA%4tDTac$FCUm-YH613k{(=kV1 z>?M!ELT=tnjBb(^f5+NTTe{+?GTw>b&F>Iju@Cp7gMUAj&T=Q8-r3gZTRPpiE2 zc}HGA9Jjz_!L+rRZB+FA_T|X6DWbpng_CGLbrhDn#|+utg%qtXn2E~?R6HkApk`_N zAJJ)ONREZ{_4UQ~4KG9gVaeE_PkgB!d;QtIn$P+s;ro1}@X`rx%gU{Y>)hK5lm*S8 zXViYQ5|R;b?vT|+hvV#|*H0jLfq^#h6t($)&McT_Gf{0sIH)mHgIOpJVZ-zQlm0i< zY;5QVyYL%mtx789c=c&wACOm_A0O$Q02|PDb7Lcg0pPW7e2lW007n9^b+GSpMjD(o z$sgCMeM#E5+*h8+cE7OArTD77bLKe>oANt5xra#kME&%!5mu0==ZKq$b}73OwvaN` zVtN)QAvx%Us9{83bnuf1t2EpX$~ny7&c*7U>on7EgvNmF0)sv6hF2jL4p90o@^868 zVC5K^2UQCa{vhJ8Y4`f|nlWr@A~Q4d0ir2I-=qe+jO*4`t}eXpk?k>$L9GbPn2KU&R)ns8L%3T+V>3AY0ew<-uX&d&%RDOY)kmDx z{__C_VF|>z&+}_91vMj*0xKEXk@RbenNaeEINyO!ygWdP->?7}*q`S`u{18A+)xeZ zm#4|e$vvGpMn_TZ>-MXRs-hU-CUeh19&u?V7=H_aaza=Fu8qvCY4$QI)4W-tQBLTZ z(OPhEsu&<6t0ftHFyeIAY^W*J{!#Epz6~6M%(_q5&7MW61+z_%0ILGKeFWFMQlB+} zN=#PIs+O%Vj_~7OT{P6!ND&$<2X-(rL(eeFQ^4yd0reS9Zhn4#>VTBb1cf;i+>}_m z{Z%o1tJzsu)sOK_ox5nvb`d?kP-yE5bQjJDK(OG``FD(KInPU*`Z?z^!Fam8|zxT%>ciT}*8 zo4|`uN*<*EQk?k_FE8&55MLu0CH(F;9*k@76H=l7l(Mkl*QecFsYhnjWgH~wc8W3Q zLUw@9<%8}QEuB9{kUIJ$g~wsJqoLEQBw~z6`e?w2jw`M{y*5+IpAiQh9tEh5>L2Rs zduBgfVO2@7nJt>GEn&hD$y^tK*EIA0^lz(W>*h?m$cfr*nM}MZ9^Jf_Yd^Ck$3Rvy3&+p zxZ3R4;}jgUXd8WQ#&1Po&7mv#*-42($ZKjB*4v!WG=Hcg_i3cdf-LGu@h=$t_C zKhi`wl_><=Z)0_^4i?w5DkmnVoy^cl2sh95v^g*u@n4|t2CP!^9j&Ld|5vxL@-D;N z>ETG88_4f`FD>N;k5$y(*^Hn?e4awPad3=KcRQ>iuF_VY<>ANLM`k@4Nz10cYIMs| zPhJITEOBtf?b`30`b>rW$G<%lxQ%st{k|$OODlbfC0WVm=(q3ZXYBL%-{xK(e90xE zeSd9v72fdx_pyQ)kfkVV^~&^x!JOIk0Kjl6D9()s9SK|DN$wZDxQ~NA$bTR-JBp$y zht^yj3`vdueA>I7k~zu5Tb>3WUrnLqoAq=Aze}we=-`&YjBCg+KEQkt_gYhdWj2GB z>VoG8Ysb7}7Ns%`0vJmG>AMusRq1H0+`f5PgUdRMwEBTMQU(!zcz#%OBf5JMDS@tS z7fqf^U(p+V0cF5PJV(qC3q4vU@Mo8i30rzjWA^l^goH#oL^3l!NA0DUFvz*RW07PL z7Z-oWH_ATzV6v>n(8YQDBfNgbj>|&Co$1G`jEmP&q}@CGq)b;+k)@^k9JI6<&AfMg zOgMz~6UYa|?jB~?dPqMvX#C17pG(@N?>{(>8}MS+{1wuCezvU42DxYdEG&dk^U zTnyZmfbT!cxT45L?RLSp9Y9=g1%kW`;QjOz6GSD!3j+fCKR$XyV;*2-2Ua8U1S_1C z0?=|01=HUq$MSUf?#jbHAQxRf!|6{+DcYsp(_@1i;CH4pJmEmo2Y2q%F-XK6lAu-G z1?$+K5|Oq$#4!>HW5%e(`55gtK7^H!J7tj8ZwErpF65VP_m-~MedcsO9r`egHr$`4 zxN{PTwLgPxiL9X?;_9!chkDi@(aL2kE?d*W4fOS6_vac8UxUzg8;I2Nw4q)u)o?y| z&^dD0hSeP(A0I`~e$f8qZE~{OSQY0Fob~*{tTdfpN0A@!w42#VYERIaPm(_wRk8K( zS$wg9m2K-V9StIXtRuVcq9SQ&#L#I(B{U~-&gsd3~7#@ zbzGd~?tTr*mR2m*FMD!CR7s8HDkSAz>`)30GHMkt@a82q$-pCr)dGb$`d6=BWdmn> zMBcvOdq#M+SI#4yW+FD#KeI{m;>m|^-uL?+_$6Pe2G2p0WalM)TPXjSJ^*6X>J4G2A>@X0p=^v~@E2dU`Q1v&LGy z@-ILAW8L`{AN{JEAlKFzm z$$`uM)3wuttE1cU8_$*hh+ZSuXsHthniPRH&-y2H`N)1 z%TFIoQ@!Oiq;A5i!u3q<9Z1OG4Kfw|Agr=+?>WJKaG185@kZGFCrSFukY+52{QaT-c*+f<-*(6s+tE>Y$F)Jo^s*^n*z@M} z9GQZmZTw@sv`1@y{K?>*!XI}Mn{<@K_}5?Dvz3Vu9h@Hsh*;i7YkdJG+GE-Ez@-6t z10Liz=631szdqlBsv2#@6u&(LJP{opxe<*sIA-T>vS)_S#6H8n`-Q3Olb{AY_XDWAD%#W@3Ah2>DD>hpW+fmQH(0aO8cIG(ykn6r;d153uHE2K!R z58-m{kt`1CFZaGeqP}~*e|yv^oD)`x-O~%F9-vyE_RM?YH|((FXYAn==E9>zt@`qG z)kr-^uAIKCgt8+*`&`JHpnhddcF|tq#j@Eta&d3OmRf}C)EfHL?w|DwHi>(6Tz6Y}m6x8CMo(;wrJwvNb{Bl-6X=ktC9nP3UPy&Fto zNhtHojl!li3o@rt>SfJRw{K;s3}s1>sYPqLeEkrA?bzL|3Uw>yf0o2`j{RaXj0(!& zw$^l~d|anSz$t{4vjxicoM@eWor3JLx(S zDa?vXYkv~y91doZOmqKp3X{e<7o_M3r)4K&lG&^MTfH1+J9K&>>G!!8rN@jzqO?LM zW1FrwB$my2mBAN{cA^zqp+o+K>;qla;uLfZBeBgk89UfBF9~Qpz$O1qpoIynV4i!l zq#~+-JywI%j6@F)LqpZc8JWrlGs`I)Zd=2Z?Zv2y3xe5w7!7y_KFSV_u4I)THIA6jww!Sp@@MkGdfD>XzUZf;pOUn| zgS^U7_K2OfqI^npGtP?KQ7U$OP6c&!6~(jdw>b}0X7m|xxlcc|Und-n$=iP}?|6+* zJA>y%p&(>>=qR;r$8Zwafn(8Nh_;n3?6I6%r*P3Zl3-r9iSKktcIYgf=CzwPKT5IBgzaBg%07O< zf)i0eu?1AqgjifgtvLOCKV;+3r3s53K*jCxpJv~yrfZ@mTk@@ky89d9&m|+`@R8ip z|DOy#+|zT-gDxaKlL&47Q7eR?FN$WSNj0E??lmMkt|K{cm#Cim-oMdfOyv?=A)(^u zyTupOZdSAKnh7~D8j`50(eeWe_U{j1C9_gtQKHF@#$R{D3ovjMY2F= 4) { + payload.deviceName = deviceName; + invokerUtil.post( + downloadDeviceAPI, + payload, + function (data, textStatus, jqxhr) { + doAction(data); + }, + function (data) { + doAction(data); + } + ); + } else if (deviceName) { + $('.controls').append(''); + $('.control-group').removeClass('success').addClass('error'); + } else { + $('.controls').append(''); + $('.control-group').removeClass('success').addClass('error'); + } + }); + + $("a#download-device-cancel-link").click(function () { + hidePopup(); + }); + + }); +} + +function downloadAgent() { + var deviceName = ""; + $('.new-device-name').each(function () { + if (this.value != "") { + deviceName = this.value; + } + }); + var deviceType = ""; + $('.deviceType').each(function () { + if (this.value != "") { + deviceType = this.value; + } + }); + var sketchType = ""; + $('.sketchType').each(function () { + if (this.value != "") { + sketchType = this.value; + } + }); + var deviceNameFormat = /^[^~?!#$:;%^*`+={}\[\]\\()|<>,'"]{1,30}$/; + if (deviceName && deviceNameFormat.test(deviceName)) { + $(modalPopupContent).html($('#device-agent-downloading-content').html()); + var successCallback = function (data) { + data = JSON.parse(data); + hidePopup(); + window.location = "/devicemgt/api/devices/sketch/download/" + data.responseContent; + }; + var generateLink = "/" + deviceType + "_mgt/manager/device/" + sketchType + + "/generate_link?deviceName=" + deviceName; + invokerUtil.get(generateLink, successCallback, function (message) { + console.log(message.content); + hidePopup(); + doAction(data); + }); + } else { + $("#invalid-username-error-msg span").text("Invalid device name"); + $("#invalid-username-error-msg").removeClass("hidden"); + } +} + +function doAction(data) { + //if it is saml redirection response + if (data.status == null) { + document.write(data); + } + + if (data.status == "401") { + $(modalPopupContent).html($('#device-401-content').html()); + $("#device-401-link").click(function () { + window.location = "/devicemgt/login"; + }); + showPopup(); + } else if (data == "403") { + $(modalPopupContent).html($('#device-403-content').html()); + $("#device-403-link").click(function () { + window.location = "/devicemgt/login"; + }); + showPopup(); + } else { + $(modalPopupContent).html($('#device-unexpected-error-content').html()); + $("a#device-unexpected-error-link").click(function () { + hidePopup(); + }); + } +} \ No newline at end of file diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/js/jquery.validate.js b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/js/jquery.validate.js new file mode 100644 index 00000000..ae92b49e --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/public/js/jquery.validate.js @@ -0,0 +1,1234 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +(function ($) { + + $.extend($.fn, { + // http://docs.jquery.com/Plugins/Validation/validate + validate: function (options) { + + // if nothing is selected, return nothing; can't chain anyway + if (!this.length) { + if (options && options.debug && window.console) { + console.warn("Nothing selected, can't validate, returning nothing."); + } + return; + } + + // check if a validator for this form was already created + var validator = $.data(this[0], "validator"); + if (validator) { + return validator; + } + + // Add novalidate tag if HTML5. + this.attr("novalidate", "novalidate"); + + validator = new $.validator(options, this[0]); + $.data(this[0], "validator", validator); + + if (validator.settings.onsubmit) { + + this.validateDelegate(":submit", "click", function (event) { + if (validator.settings.submitHandler) { + validator.submitButton = event.target; + } + // allow suppressing validation by adding a cancel class to the submit button + if ($(event.target).hasClass("cancel")) { + validator.cancelSubmit = true; + } + }); + + // validate the form on submit + this.submit(function (event) { + if (validator.settings.debug) { + // prevent form submit to be able to see console output + event.preventDefault(); + } + function handle() { + var hidden; + if (validator.settings.submitHandler) { + if (validator.submitButton) { + // insert a hidden input as a replacement for the missing submit button + hidden = $("").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm); + } + validator.settings.submitHandler.call(validator, validator.currentForm, event); + if (validator.submitButton) { + // and clean up afterwards; thanks to no-block-scope, hidden can be referenced + hidden.remove(); + } + return false; + } + return true; + } + + // prevent submit for invalid forms or custom submit handlers + if (validator.cancelSubmit) { + validator.cancelSubmit = false; + return handle(); + } + if (validator.form()) { + if (validator.pendingRequest) { + validator.formSubmitted = true; + return false; + } + return handle(); + } else { + validator.focusInvalid(); + return false; + } + }); + } + + return validator; + }, + // http://docs.jquery.com/Plugins/Validation/valid + valid: function () { + if ($(this[0]).is("form")) { + return this.validate().form(); + } else { + var valid = true; + var validator = $(this[0].form).validate(); + this.each(function () { + valid &= validator.element(this); + }); + return valid; + } + }, + // attributes: space seperated list of attributes to retrieve and remove + removeAttrs: function (attributes) { + var result = {}, + $element = this; + $.each(attributes.split(/\s/), function (index, value) { + result[value] = $element.attr(value); + $element.removeAttr(value); + }); + return result; + }, + // http://docs.jquery.com/Plugins/Validation/rules + rules: function (command, argument) { + var element = this[0]; + + if (command) { + var settings = $.data(element.form, "validator").settings; + var staticRules = settings.rules; + var existingRules = $.validator.staticRules(element); + switch (command) { + case "add": + $.extend(existingRules, $.validator.normalizeRule(argument)); + staticRules[element.name] = existingRules; + if (argument.messages) { + settings.messages[element.name] = $.extend(settings.messages[element.name], argument.messages); + } + break; + case "remove": + if (!argument) { + delete staticRules[element.name]; + return existingRules; + } + var filtered = {}; + $.each(argument.split(/\s/), function (index, method) { + filtered[method] = existingRules[method]; + delete existingRules[method]; + }); + return filtered; + } + } + + var data = $.validator.normalizeRules( + $.extend( + {}, + $.validator.classRules(element), + $.validator.attributeRules(element), + $.validator.dataRules(element), + $.validator.staticRules(element) + ), element); + + // make sure required is at front + if (data.required) { + var param = data.required; + delete data.required; + data = $.extend({required: param}, data); + } + + return data; + } + }); + +// Custom selectors + $.extend($.expr[":"], { + // http://docs.jquery.com/Plugins/Validation/blank + blank: function (a) { + return !$.trim("" + a.value); + }, + // http://docs.jquery.com/Plugins/Validation/filled + filled: function (a) { + return !!$.trim("" + a.value); + }, + // http://docs.jquery.com/Plugins/Validation/unchecked + unchecked: function (a) { + return !a.checked; + } + }); + +// constructor for validator + $.validator = function (options, form) { + this.settings = $.extend(true, {}, $.validator.defaults, options); + this.currentForm = form; + this.init(); + }; + + $.validator.format = function (source, params) { + if (arguments.length === 1) { + return function () { + var args = $.makeArray(arguments); + args.unshift(source); + return $.validator.format.apply(this, args); + }; + } + if (arguments.length > 2 && params.constructor !== Array) { + params = $.makeArray(arguments).slice(1); + } + if (params.constructor !== Array) { + params = [params]; + } + $.each(params, function (i, n) { + source = source.replace(new RegExp("\\{" + i + "\\}", "g"), function () { + return n; + }); + }); + return source; + }; + + $.extend($.validator, { + + defaults: { + messages: {}, + groups: {}, + rules: {}, + errorClass: "error", + validClass: "valid", + errorElement: "label", + focusInvalid: true, + errorContainer: $([]), + errorLabelContainer: $([]), + onsubmit: true, + ignore: ":hidden", + ignoreTitle: false, + onfocusin: function (element, event) { + this.lastActive = element; + + // hide error label and remove error class on focus if enabled + if (this.settings.focusCleanup && !this.blockFocusCleanup) { + if (this.settings.unhighlight) { + this.settings.unhighlight.call(this, element, this.settings.errorClass, this.settings.validClass); + } + this.addWrapper(this.errorsFor(element)).hide(); + } + }, + onfocusout: function (element, event) { + if (!this.checkable(element) && (element.name in this.submitted || !this.optional(element))) { + this.element(element); + } + }, + onkeyup: function (element, event) { + if (event.which === 9 && this.elementValue(element) === "") { + return; + } else if (element.name in this.submitted || element === this.lastElement) { + this.element(element); + } + }, + onclick: function (element, event) { + // click on selects, radiobuttons and checkboxes + if (element.name in this.submitted) { + this.element(element); + } + // or option elements, check parent select in that case + else if (element.parentNode.name in this.submitted) { + this.element(element.parentNode); + } + }, + highlight: function (element, errorClass, validClass) { + if (element.type === "radio") { + this.findByName(element.name).addClass(errorClass).removeClass(validClass); + } else { + $(element).addClass(errorClass).removeClass(validClass); + } + }, + unhighlight: function (element, errorClass, validClass) { + if (element.type === "radio") { + this.findByName(element.name).removeClass(errorClass).addClass(validClass); + } else { + $(element).removeClass(errorClass).addClass(validClass); + } + } + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults + setDefaults: function (settings) { + $.extend($.validator.defaults, settings); + }, + + messages: { + required: "This field is required.", + remote: "Please fix this field.", + email: "Please enter a valid email address.", + url: "Please enter a valid URL.", + date: "Please enter a valid date.", + dateISO: "Please enter a valid date (ISO).", + number: "Please enter a valid number.", + digits: "Please enter only digits.", + creditcard: "Please enter a valid credit card number.", + equalTo: "Please enter the same value again.", + maxlength: $.validator.format("Please enter no more than {0} characters."), + minlength: $.validator.format("Please enter at least {0} characters."), + rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), + range: $.validator.format("Please enter a value between {0} and {1}."), + max: $.validator.format("Please enter a value less than or equal to {0}."), + min: $.validator.format("Please enter a value greater than or equal to {0}.") + }, + + autoCreateRanges: false, + + prototype: { + + init: function () { + this.labelContainer = $(this.settings.errorLabelContainer); + this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); + this.containers = $(this.settings.errorContainer).add(this.settings.errorLabelContainer); + this.submitted = {}; + this.valueCache = {}; + this.pendingRequest = 0; + this.pending = {}; + this.invalid = {}; + this.reset(); + + var groups = (this.groups = {}); + $.each(this.settings.groups, function (key, value) { + if (typeof value === "string") { + value = value.split(/\s/); + } + $.each(value, function (index, name) { + groups[name] = key; + }); + }); + var rules = this.settings.rules; + $.each(rules, function (key, value) { + rules[key] = $.validator.normalizeRule(value); + }); + + function delegate(event) { + var validator = $.data(this[0].form, "validator"), + eventType = "on" + event.type.replace(/^validate/, ""); + if (validator.settings[eventType]) { + validator.settings[eventType].call(validator, this[0], event); + } + } + + $(this.currentForm) + .validateDelegate( ":text, [type='password'], [type='file'], select, textarea, " + + "[type='number'], [type='search'] ,[type='tel'], [type='url'], " + + "[type='email'], [type='datetime'], [type='date'], [type='month'], " + + "[type='week'], [type='time'], [type='datetime-local'], " + + "[type='range'], [type='color'] ", + "focusin focusout keyup", delegate) + .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate); + + if (this.settings.invalidHandler) { + $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); + } + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/form + form: function () { + this.checkForm(); + $.extend(this.submitted, this.errorMap); + this.invalid = $.extend({}, this.errorMap); + if (!this.valid()) { + $(this.currentForm).triggerHandler("invalid-form", [this]); + } + this.showErrors(); + return this.valid(); + }, + + checkForm: function () { + this.prepareForm(); + for (var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++) { + this.check(elements[i]); + } + return this.valid(); + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/element + element: function (element) { + element = this.validationTargetFor(this.clean(element)); + this.lastElement = element; + this.prepareElement(element); + this.currentElements = $(element); + var result = this.check(element) !== false; + if (result) { + delete this.invalid[element.name]; + } else { + this.invalid[element.name] = true; + } + if (!this.numberOfInvalids()) { + // Hide error containers on last error + this.toHide = this.toHide.add(this.containers); + } + this.showErrors(); + return result; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/showErrors + showErrors: function (errors) { + if (errors) { + // add items to error list and map + $.extend(this.errorMap, errors); + this.errorList = []; + for (var name in errors) { + this.errorList.push({ + message: errors[name], + element: this.findByName(name)[0] + }); + } + // remove items from success list + this.successList = $.grep(this.successList, function (element) { + return !(element.name in errors); + }); + } + if (this.settings.showErrors) { + this.settings.showErrors.call(this, this.errorMap, this.errorList); + } else { + this.defaultShowErrors(); + } + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/resetForm + resetForm: function () { + if ($.fn.resetForm) { + $(this.currentForm).resetForm(); + } + this.submitted = {}; + this.lastElement = null; + this.prepareForm(); + this.hideErrors(); + this.elements().removeClass(this.settings.errorClass).removeData("previousValue"); + }, + + numberOfInvalids: function () { + return this.objectLength(this.invalid); + }, + + objectLength: function (obj) { + var count = 0; + for (var i in obj) { + count++; + } + return count; + }, + + hideErrors: function () { + this.addWrapper(this.toHide).hide(); + }, + + valid: function () { + return this.size() === 0; + }, + + size: function () { + return this.errorList.length; + }, + + focusInvalid: function () { + if (this.settings.focusInvalid) { + try { + $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) + .filter(":visible") + .focus() + // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find + .trigger("focusin"); + } catch (e) { + // ignore IE throwing errors when focusing hidden elements + } + } + }, + + findLastActive: function () { + var lastActive = this.lastActive; + return lastActive && $.grep(this.errorList, function (n) { + return n.element.name === lastActive.name; + }).length === 1 && lastActive; + }, + + elements: function () { + var validator = this, + rulesCache = {}; + + // select all valid inputs inside the form (no submit or reset buttons) + return $(this.currentForm) + .find("input, select, textarea") + .not(":submit, :reset, :image, [disabled]") + .not(this.settings.ignore) + .filter(function () { + if (!this.name) { + if (window.console) { + console.error("%o has no name assigned", this); + } + throw new Error("Failed to validate, found an element with no name assigned. See console for element reference."); + } + + // select only the first element for each name, and only those with rules specified + if (this.name in rulesCache || !validator.objectLength($(this).rules())) { + return false; + } + + rulesCache[this.name] = true; + return true; + }); + }, + + clean: function (selector) { + return $(selector)[0]; + }, + + errors: function () { + var errorClass = this.settings.errorClass.replace(" ", "."); + return $(this.settings.errorElement + "." + errorClass, this.errorContext); + }, + + reset: function () { + this.successList = []; + this.errorList = []; + this.errorMap = {}; + this.toShow = $([]); + this.toHide = $([]); + this.currentElements = $([]); + }, + + prepareForm: function () { + this.reset(); + this.toHide = this.errors().add(this.containers); + }, + + prepareElement: function (element) { + this.reset(); + this.toHide = this.errorsFor(element); + }, + + elementValue: function (element) { + var type = $(element).attr("type"), + val = $(element).val(); + + if (type === "radio" || type === "checkbox") { + return $("input[name='" + $(element).attr("name") + "']:checked").val(); + } + + if (typeof val === "string") { + return val.replace(/\r/g, ""); + } + return val; + }, + + check: function (element) { + element = this.validationTargetFor(this.clean(element)); + + var rules = $(element).rules(); + var dependencyMismatch = false; + var val = this.elementValue(element); + var result; + + for (var method in rules) { + var rule = {method: method, parameters: rules[method]}; + try { + + result = $.validator.methods[method].call(this, val, element, rule.parameters); + + // if a method indicates that the field is optional and therefore valid, + // don't mark it as valid when there are no other rules + if (result === "dependency-mismatch") { + dependencyMismatch = true; + continue; + } + dependencyMismatch = false; + + if (result === "pending") { + this.toHide = this.toHide.not(this.errorsFor(element)); + return; + } + + if (!result) { + this.formatAndAdd(element, rule); + return false; + } + } catch (e) { + if (this.settings.debug && window.console) { + console.log("Exception occured when checking element " + element.id + ", check the '" + rule.method + "' method.", e); + } + throw e; + } + } + if (dependencyMismatch) { + return; + } + if (this.objectLength(rules)) { + this.successList.push(element); + } + return true; + }, + + // return the custom message for the given element and validation method + // specified in the element's HTML5 data attribute + customDataMessage: function (element, method) { + return $(element).data("msg-" + method.toLowerCase()) || (element.attributes && $(element).attr("data-msg-" + method.toLowerCase())); + }, + + // return the custom message for the given element name and validation method + customMessage: function (name, method) { + var m = this.settings.messages[name]; + return m && (m.constructor === String ? m : m[method]); + }, + + // return the first defined argument, allowing empty strings + findDefined: function () { + for (var i = 0; i < arguments.length; i++) { + if (arguments[i] !== undefined) { + return arguments[i]; + } + } + return undefined; + }, + + defaultMessage: function (element, method) { + return this.findDefined( + this.customMessage(element.name, method), + this.customDataMessage(element, method), + // title is never undefined, so handle empty string as undefined + !this.settings.ignoreTitle && element.title || undefined, + $.validator.messages[method], + "Warning: No message defined for " + element.name + "" + ); + }, + + formatAndAdd: function (element, rule) { + var message = this.defaultMessage(element, rule.method), + theregex = /\$?\{(\d+)\}/g; + if (typeof message === "function") { + message = message.call(this, rule.parameters, element); + } else if (theregex.test(message)) { + message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters); + } + this.errorList.push({ + message: message, + element: element + }); + + this.errorMap[element.name] = message; + this.submitted[element.name] = message; + }, + + addWrapper: function (toToggle) { + if (this.settings.wrapper) { + toToggle = toToggle.add(toToggle.parent(this.settings.wrapper)); + } + return toToggle; + }, + + defaultShowErrors: function () { + var i, elements; + for (i = 0; this.errorList[i]; i++) { + var error = this.errorList[i]; + if (this.settings.highlight) { + this.settings.highlight.call(this, error.element, this.settings.errorClass, this.settings.validClass); + } + this.showLabel(error.element, error.message); + } + if (this.errorList.length) { + this.toShow = this.toShow.add(this.containers); + } + if (this.settings.success) { + for (i = 0; this.successList[i]; i++) { + this.showLabel(this.successList[i]); + } + } + if (this.settings.unhighlight) { + for (i = 0, elements = this.validElements(); elements[i]; i++) { + this.settings.unhighlight.call(this, elements[i], this.settings.errorClass, this.settings.validClass); + } + } + this.toHide = this.toHide.not(this.toShow); + this.hideErrors(); + this.addWrapper(this.toShow).show(); + }, + + validElements: function () { + return this.currentElements.not(this.invalidElements()); + }, + + invalidElements: function () { + return $(this.errorList).map(function () { + return this.element; + }); + }, + + showLabel: function (element, message) { + var label = this.errorsFor(element); + if (label.length) { + // refresh error/success class + label.removeClass(this.settings.validClass).addClass(this.settings.errorClass); + + // check if we have a generated label, replace the message then + if (label.attr("generated")) { + label.html(message); + } + } else { + // create label + label = $("<" + this.settings.errorElement + "/>") + .attr({"for": this.idOrName(element), generated: true}) + .addClass(this.settings.errorClass) + .html(message || ""); + if (this.settings.wrapper) { + // make sure the element is visible, even in IE + // actually showing the wrapped element is handled elsewhere + label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); + } + if (!this.labelContainer.append(label).length) { + if (this.settings.errorPlacement) { + this.settings.errorPlacement(label, $(element)); + } else { + label.insertAfter(element); + } + } + } + if (!message && this.settings.success) { + label.text(""); + if (typeof this.settings.success === "string") { + label.addClass(this.settings.success); + } else { + this.settings.success(label, element); + } + } + this.toShow = this.toShow.add(label); + }, + + errorsFor: function (element) { + var name = this.idOrName(element); + return this.errors().filter(function () { + return $(this).attr("for") === name; + }); + }, + + idOrName: function (element) { + return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); + }, + + validationTargetFor: function (element) { + // if radio/checkbox, validate first element in group instead + if (this.checkable(element)) { + element = this.findByName(element.name).not(this.settings.ignore)[0]; + } + return element; + }, + + checkable: function (element) { + return (/radio|checkbox/i).test(element.type); + }, + + findByName: function (name) { + return $(this.currentForm).find("[name='" + name + "']"); + }, + + getLength: function (value, element) { + switch (element.nodeName.toLowerCase()) { + case "select": + return $("option:selected", element).length; + case "input": + if (this.checkable(element)) { + return this.findByName(element.name).filter(":checked").length; + } + } + return value.length; + }, + + depend: function (param, element) { + return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true; + }, + + dependTypes: { + "boolean": function (param, element) { + return param; + }, + "string": function (param, element) { + return !!$(param, element.form).length; + }, + "function": function (param, element) { + return param(element); + } + }, + + optional: function (element) { + var val = this.elementValue(element); + return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch"; + }, + + startRequest: function (element) { + if (!this.pending[element.name]) { + this.pendingRequest++; + this.pending[element.name] = true; + } + }, + + stopRequest: function (element, valid) { + this.pendingRequest--; + // sometimes synchronization fails, make sure pendingRequest is never < 0 + if (this.pendingRequest < 0) { + this.pendingRequest = 0; + } + delete this.pending[element.name]; + if (valid && this.pendingRequest === 0 && this.formSubmitted && this.form()) { + $(this.currentForm).submit(); + this.formSubmitted = false; + } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) { + $(this.currentForm).triggerHandler("invalid-form", [this]); + this.formSubmitted = false; + } + }, + + previousValue: function (element) { + return $.data(element, "previousValue") || $.data(element, "previousValue", { + old: null, + valid: true, + message: this.defaultMessage(element, "remote") + }); + } + + }, + + classRuleSettings: { + required: {required: true}, + email: {email: true}, + url: {url: true}, + date: {date: true}, + dateISO: {dateISO: true}, + number: {number: true}, + digits: {digits: true}, + creditcard: {creditcard: true} + }, + + addClassRules: function (className, rules) { + if (className.constructor === String) { + this.classRuleSettings[className] = rules; + } else { + $.extend(this.classRuleSettings, className); + } + }, + + classRules: function (element) { + var rules = {}; + var classes = $(element).attr("class"); + if (classes) { + $.each(classes.split(" "), function () { + if (this in $.validator.classRuleSettings) { + $.extend(rules, $.validator.classRuleSettings[this]); + } + }); + } + return rules; + }, + + attributeRules: function (element) { + var rules = {}; + var $element = $(element); + + for (var method in $.validator.methods) { + var value; + + // support for in both html5 and older browsers + if (method === "required") { + value = $element.get(0).getAttribute(method); + // Some browsers return an empty string for the required attribute + // and non-HTML5 browsers might have required="" markup + if (value === "") { + value = true; + } + // force non-HTML5 browsers to return bool + value = !!value; + } else { + value = $element.attr(method); + } + + if (value) { + rules[method] = value; + } else if ($element[0].getAttribute("type") === method) { + rules[method] = true; + } + } + + // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs + if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) { + delete rules.maxlength; + } + + return rules; + }, + + dataRules: function (element) { + var method, value, + rules = {}, $element = $(element); + for (method in $.validator.methods) { + value = $element.data("rule-" + method.toLowerCase()); + if (value !== undefined) { + rules[method] = value; + } + } + return rules; + }, + + staticRules: function (element) { + var rules = {}; + var validator = $.data(element.form, "validator"); + if (validator.settings.rules) { + rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; + } + return rules; + }, + + normalizeRules: function (rules, element) { + // handle dependency check + $.each(rules, function (prop, val) { + // ignore rule when param is explicitly false, eg. required:false + if (val === false) { + delete rules[prop]; + return; + } + if (val.param || val.depends) { + var keepRule = true; + switch (typeof val.depends) { + case "string": + keepRule = !!$(val.depends, element.form).length; + break; + case "function": + keepRule = val.depends.call(element, element); + break; + } + if (keepRule) { + rules[prop] = val.param !== undefined ? val.param : true; + } else { + delete rules[prop]; + } + } + }); + + // evaluate parameters + $.each(rules, function (rule, parameter) { + rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; + }); + + // clean number parameters + $.each(["minlength", "maxlength", "min", "max"], function () { + if (rules[this]) { + rules[this] = Number(rules[this]); + } + }); + $.each(["rangelength", "range"], function () { + var parts; + if (rules[this]) { + if ($.isArray(rules[this])) { + rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; + } else if (typeof rules[this] === "string") { + parts = rules[this].split(/[\s,]+/); + rules[this] = [Number(parts[0]), Number(parts[1])]; + } + } + }); + + if ($.validator.autoCreateRanges) { + // auto-create ranges + if (rules.min && rules.max) { + rules.range = [rules.min, rules.max]; + delete rules.min; + delete rules.max; + } + if (rules.minlength && rules.maxlength) { + rules.rangelength = [rules.minlength, rules.maxlength]; + delete rules.minlength; + delete rules.maxlength; + } + } + + return rules; + }, + + // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} + normalizeRule: function (data) { + if (typeof data === "string") { + var transformed = {}; + $.each(data.split(/\s/), function () { + transformed[this] = true; + }); + data = transformed; + } + return data; + }, + + // http://docs.jquery.com/Plugins/Validation/Validator/addMethod + addMethod: function (name, method, message) { + $.validator.methods[name] = method; + $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name]; + if (method.length < 3) { + $.validator.addClassRules(name, $.validator.normalizeRule(name)); + } + }, + + methods: { + + // http://docs.jquery.com/Plugins/Validation/Methods/required + required: function (value, element, param) { + // check if dependency is met + if (!this.depend(param, element)) { + return "dependency-mismatch"; + } + if (element.nodeName.toLowerCase() === "select") { + // could be an array for select-multiple or a string, both are fine this way + var val = $(element).val(); + return val && val.length > 0; + } + if (this.checkable(element)) { + return this.getLength(value, element) > 0; + } + return $.trim(value).length > 0; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/remote + remote: function (value, element, param) { + if (this.optional(element)) { + return "dependency-mismatch"; + } + + var previous = this.previousValue(element); + if (!this.settings.messages[element.name]) { + this.settings.messages[element.name] = {}; + } + previous.originalMessage = this.settings.messages[element.name].remote; + this.settings.messages[element.name].remote = previous.message; + + param = typeof param === "string" && {url: param} || param; + + if (previous.old === value) { + return previous.valid; + } + + previous.old = value; + var validator = this; + this.startRequest(element); + var data = {}; + data[element.name] = value; + $.ajax($.extend(true, { + url: param, + mode: "abort", + port: "validate" + element.name, + dataType: "json", + data: data, + success: function (response) { + validator.settings.messages[element.name].remote = previous.originalMessage; + var valid = response === true || response === "true"; + if (valid) { + var submitted = validator.formSubmitted; + validator.prepareElement(element); + validator.formSubmitted = submitted; + validator.successList.push(element); + delete validator.invalid[element.name]; + validator.showErrors(); + } else { + var errors = {}; + var message = response || validator.defaultMessage(element, "remote"); + errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; + validator.invalid[element.name] = true; + validator.showErrors(errors); + } + previous.valid = valid; + validator.stopRequest(element, valid); + } + }, param)); + return "pending"; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/minlength + minlength: function (value, element, param) { + var length = $.isArray(value) ? value.length : this.getLength($.trim(value), element); + return this.optional(element) || length >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/maxlength + maxlength: function (value, element, param) { + var length = $.isArray(value) ? value.length : this.getLength($.trim(value), element); + return this.optional(element) || length <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/rangelength + rangelength: function (value, element, param) { + var length = $.isArray(value) ? value.length : this.getLength($.trim(value), element); + return this.optional(element) || ( length >= param[0] && length <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/min + min: function (value, element, param) { + return this.optional(element) || value >= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/max + max: function (value, element, param) { + return this.optional(element) || value <= param; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/range + range: function (value, element, param) { + return this.optional(element) || ( value >= param[0] && value <= param[1] ); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/email + email: function (value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/ + return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/url + url: function (value, element) { + // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ + return this.optional(element) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/date + date: function (value, element) { + return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString()); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/dateISO + dateISO: function (value, element) { + return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/number + number: function (value, element) { + return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/digits + digits: function (value, element) { + return this.optional(element) || /^\d+$/.test(value); + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/creditcard + // based on http://en.wikipedia.org/wiki/Luhn + creditcard: function (value, element) { + if (this.optional(element)) { + return "dependency-mismatch"; + } + // accept only spaces, digits and dashes + if (/[^0-9 \-]+/.test(value)) { + return false; + } + var nCheck = 0, + nDigit = 0, + bEven = false; + + value = value.replace(/\D/g, ""); + + for (var n = value.length - 1; n >= 0; n--) { + var cDigit = value.charAt(n); + nDigit = parseInt(cDigit, 10); + if (bEven) { + if ((nDigit *= 2) > 9) { + nDigit -= 9; + } + } + nCheck += nDigit; + bEven = !bEven; + } + + return (nCheck % 10) === 0; + }, + + // http://docs.jquery.com/Plugins/Validation/Methods/equalTo + equalTo: function (value, element, param) { + // bind to the blur event of the target in order to revalidate whenever the target field is updated + // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead + var target = $(param); + if (this.settings.onfocusout) { + target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function () { + $(element).valid(); + }); + } + return value === target.val(); + } + + } + + }); + +// deprecated, use $.validator.format instead + $.format = $.validator.format; + +}(jQuery)); + +// ajax mode: abort +// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); +// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() +(function ($) { + var pendingRequests = {}; + // Use a prefilter if available (1.5+) + if ($.ajaxPrefilter) { + $.ajaxPrefilter(function (settings, _, xhr) { + var port = settings.port; + if (settings.mode === "abort") { + if (pendingRequests[port]) { + pendingRequests[port].abort(); + } + pendingRequests[port] = xhr; + } + }); + } else { + // Proxy ajax + var ajax = $.ajax; + $.ajax = function (settings) { + var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, + port = ( "port" in settings ? settings : $.ajaxSettings ).port; + if (mode === "abort") { + if (pendingRequests[port]) { + pendingRequests[port].abort(); + } + return (pendingRequests[port] = ajax.apply(this, arguments)); + } + return ajax.apply(this, arguments); + }; + } +}(jQuery)); + +// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation +// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target +(function ($) { + $.extend($.fn, { + validateDelegate: function (delegate, type, handler) { + return this.bind(type, function (event) { + var target = $(event.target); + if (target.is(delegate)) { + return handler.apply(target, arguments); + } + }); + } + }); +}(jQuery)); diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/type-view.hbs b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/type-view.hbs new file mode 100644 index 00000000..8299b21e --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/type-view.hbs @@ -0,0 +1,378 @@ +

+ +
+ +
+ +
+ +

What it Does

+
+

Connect your Fire Alarm to WSO2 IoT Server.

+
+

An ESP8266 based fire alarm device. Once run, the Fire alarm will connect to WSO2 IoTServer + and push Temperature and Humidity readings via MQTT. You can also on/off fire alarm buzzer + remotely with IoTServer. +

+
+

What You Need

+
+
+
+ View API
  + Download + Agent + +
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +

+
+ +
+

Prepare

+
+
    +
  • + 01 +    Connect USB to TTL converter and other component with ESP8266 201 + module + as schematic in FIRE ALARM SETUP. +
  • +
  • + 02 +    Download Agent files from [Download Agent] link above. +
  • +
  • + 03 +    Unzip the downloaded Fire Alarm Agent +
  • +
  • + 04 +    Open wifi-connect.lua and provide appropriate values for + [SSID] and + [Password] + variables according to your network. +
  • +
  • + 05 +    Upload all .lua files to ESP8266 using ESPlorer in following order. + Then restart the ESP8266. +
    +                + + + + +    dht_lib.lua +
    +                + + + + +    wifi-connect.lua +
    +                + + + + +    read-sensor.lua +
    +                + + + + +    init.lua +

    +
  • +
  • + 06 +    Now you can remove USB to TTL module and fix fire alarm device in any + place you want. +

    +                + + + + +    ESP8266 will publish temperature and humidity from DHT11 to + WSO2-IoT-Server +

    +                + + + + +    Buzzer can be controlled from Device Management page. +
  • +
+
+
+ +
+

Fire alarm Setup

+
+

Click on the image to zoom

+
+ + + +
+
+
+ +
+

Try Out

+
+
    +
  • 01   You can view + all your connected + devices at [Device + Management] + page. +
  • +
  • 02   Select one of + connected devices and check for + available control operations. +
  • +
+
+ +
+ + + +{{#zone "bottomJs"}} + {{js "/js/download.js"}} + {{js "/js/jquery.validate.js"}} +{{/zone}} + diff --git a/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/type-view.json b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/type-view.json new file mode 100644 index 00000000..688e9398 --- /dev/null +++ b/modules/samples/firealarm/component/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.firealarm.type-view/type-view.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/modules/samples/firealarm/feature/feature/pom.xml b/modules/samples/firealarm/feature/feature/pom.xml new file mode 100644 index 00000000..aa60607d --- /dev/null +++ b/modules/samples/firealarm/feature/feature/pom.xml @@ -0,0 +1,244 @@ + + + + + + + org.homeautomation + firealarm-feature + 1.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + 1.0.0-SNAPSHOT + ${groupId}.firealarm.feature + pom + ${project.artifactId} + http://wso2.org + + + org.homeautomation + ${project-base-package}.plugin + 1.0.0-SNAPSHOT + + + org.homeautomation + ${project-base-package}.manager + 1.0.0-SNAPSHOT + war + + + org.homeautomation + ${project-base-package}.controller + 1.0.0-SNAPSHOT + war + + + com.h2database.wso2 + h2-database-engine + 1.2.140.wso2v3 + + + + + + maven-resources-plugin + + + copy-resources + generate-resources + + copy-resources + + + src/main/resources + + + resources + + build.properties + p2.inf + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack + package + + unpack + + + + + org.homeautomation + ${project-base-package}.analytics + 1.0.0-SNAPSHOT + zip + true + + ${project.build.directory}/maven-shared-archive-resources/carbonapps + + **/* + + + org.homeautomation + ${project-base-package}.ui + + ${project.version} + zip + true + + ${project.build.directory}/maven-shared-archive-resources/jaggeryapps + + **/* + + + + + + copy-jaxrs-manager-war + package + + copy + + + + + org.homeautomation + ${project-base-package}.manager + war + true + + + ${project.build.directory}/maven-shared-archive-resources/webapps/ + + firealarm_mgt.war + + + + + + copy-jaxrs-controller-war + package + + copy + + + + + org.homeautomation + ${project-base-package}.controller + war + true + + + ${project.build.directory}/maven-shared-archive-resources/webapps/ + + firealarm.war + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${maven-antrun-plugin.version} + + + create-firealarm-plugin-mgt-schema + package + + run + + + + + + + + + + + + + + + + + + + + + org.wso2.maven + carbon-p2-plugin + + + p2-feature-generation + package + + p2-feature-gen + + + ${project-base-package} + ../../../features/etc/feature.properties + + + + org.wso2.carbon.p2.category.type:server + + org.eclipse.equinox.p2.type.group:false + + + + + + org.homeautomation:${project-base-package}.plugin:1.0.0-SNAPSHOT + + + + + org.wso2.carbon.core.server:${carbon.kernel.version} + + + org.wso2.carbon.device.mgt.server:${carbon.device.mgt.version} + + + + + + + + + diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/agent/dht_lib.lua b/modules/samples/firealarm/feature/feature/src/main/resources/agent/dht_lib.lua new file mode 100644 index 00000000..643cd05d --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/agent/dht_lib.lua @@ -0,0 +1,65 @@ +local dht_lib = {} + +local humidity +local temperature + +local bitStream = {} + +function dht_lib.read(pin) + for j = 1, 40, 1 do + bitStream[j]=0 + end + bitlength=0 + + gpio.mode(pin, gpio.OUTPUT) + gpio.write(pin, gpio.LOW) + tmr.delay(20000) + + gpio_read=gpio.read + gpio_write=gpio.write + + gpio.mode(pin, gpio.INPUT) + + while (gpio_read(pin)==0 ) do end + + c=0 + while (gpio_read(pin)==1 and c<100) do c=c+1 end + + while (gpio_read(pin)==0 ) do end + + c=0 + while (gpio_read(pin)==1 and c<100) do c=c+1 end + + for j = 1, 40, 1 do + while (gpio_read(pin)==1 and bitlength<10 ) do + bitlength=bitlength+1 + end + bitStream[j]=bitlength + bitlength=0 + while (gpio_read(pin)==0) do end + end + + humidity = 0 + temperature = 0 + + for i = 1, 8, 1 do + if (bitStream[i+0] > 2) then + humidity = humidity+2^(8-i) + end + end + for i = 1, 8, 1 do + if (bitStream[i+16] > 2) then + temperature = temperature+2^(8-i) + end + end +end + +function dht_lib.getTemperature() + return temperature +end + +function dht_lib.getHumidity() + return humidity +end + +return dht_lib diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/agent/init.lua b/modules/samples/firealarm/feature/feature/src/main/resources/agent/init.lua new file mode 100644 index 00000000..31ece4ba --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/agent/init.lua @@ -0,0 +1,4 @@ +tmr.alarm(0,1000,0,function() + dofile("wifi-connect.lua"); + dofile("read-sensor.lua"); +end) diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/agent/read-sensor.lua b/modules/samples/firealarm/feature/feature/src/main/resources/agent/read-sensor.lua new file mode 100644 index 00000000..99727b9e --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/agent/read-sensor.lua @@ -0,0 +1,74 @@ +DHT= require("dht_lib") + +dht_data = 2 +buzzer = 1 +gpio.mode(buzzer, gpio.OUTPUT) +client_connected = false +m = mqtt.Client("ESP8266-"..node.chipid(), 120, "", "") + +tmr.alarm(0,10000,1,function() + DHT.read(dht_data) + + t = DHT.getTemperature() + h = DHT.getHumidity() + + if t == nil then + print("Error reading from DHTxx") + else + if (client_connected) then + m:publish("wso2/iot/${DEVICE_OWNER}/firealarm/${DEVICE_ID}/publisher", "Temperature:"..t..":Humidity:"..h, 0, 0, function(client) + print("Published> Temperature: "..t.."C Humidity: "..h.."%") + end) + else + connectMQTTClient() + end + end +end) + +function connectMQTTClient() + ip = wifi.sta.getip() + if ip == nil then + print("Waiting for network") + else + print("Client IP: "..ip) + print("Trying to connect MQTT client") + m:connect("${SERVER_IP}", 1883, 0, function(client) + client_connected = true + print("MQTT client connected") + subscribeToMQTTQueue() + end) + end +end + +function subscribeToMQTTQueue() + m:subscribe("wso2/iot/${DEVICE_OWNER}/firealarm/${DEVICE_ID}/subscriber", 0, function(client, topic, message) + print("Subscribed to MQTT Queue") + end) + m:on("message", function(client, topic, message) + print("MQTT message received") + print(message) + buzz(message == "buzzer:ON") + end) + m:on("offline", function(client) + print("Disconnected") + client_connected = false + end) +end + +function buzz(status) + buzzerOn=true + if (status) then + tmr.alarm(1,500,1,function() + if buzzerOn then + buzzerOn=false + gpio.write(buzzer, gpio.HIGH) + else + buzzerOn=true + gpio.write(buzzer, gpio.LOW) + end + end) + else + tmr.stop(1) + gpio.write(buzzer, gpio.LOW) + end +end \ No newline at end of file diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/agent/sketch.properties b/modules/samples/firealarm/feature/feature/src/main/resources/agent/sketch.properties new file mode 100644 index 00000000..5485808b --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/agent/sketch.properties @@ -0,0 +1,16 @@ +#/* +# * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +# * WSO2 Inc. licenses this file to you under the Apache License, +# * Version 2.0 (the "License"); you may not use this file except +# * in compliance with the License. +# * You may obtain a copy of the License at +# * http://www.apache.org/licenses/LICENSE-2.0 +# * Unless required by applicable law or agreed to in writing, +# * software distributed under the License is distributed on an +# * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# * KIND, either express or implied. See the License for the +# * specific language governing permissions and limitations +# * under the License. +# */ +templates=read-sensor.lua +zipfilename=firealarm.zip diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/agent/wifi-connect.lua b/modules/samples/firealarm/feature/feature/src/main/resources/agent/wifi-connect.lua new file mode 100644 index 00000000..1c4498b9 --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/agent/wifi-connect.lua @@ -0,0 +1,2 @@ +wifi.setmode(wifi.STATION) +wifi.sta.config("SSID","Password") \ No newline at end of file diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/build.properties b/modules/samples/firealarm/feature/feature/src/main/resources/build.properties new file mode 100644 index 00000000..a7e289bc --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/build.properties @@ -0,0 +1,18 @@ +# +custom = true diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/configs/firealarm.json b/modules/samples/firealarm/feature/feature/src/main/resources/configs/firealarm.json new file mode 100644 index 00000000..b627d223 --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/configs/firealarm.json @@ -0,0 +1,54 @@ +{ + "deviceType": { + "label": "Fire Alarm", + "category": "iot" + }, + "analyticStreams": [ + { + "name": "Temperature", + "table": "DEVICE_TEMPERATURE_SUMMARY", + "ui_unit": { + "name": "cdmf.unit.analytics.line-chart", + "data": [ + { + "column": { + "name": "TIME", + "label": "time", + "ui-mapping": "x-axis" + } + }, + { + "column": { + "name": "TEMPERATURE", + "label": "Temperature", + "ui-mapping": "y-axis" + } + } + ] + } + }, + { + "name": "Humidity", + "table": "DEVICE_HUMIDITY_SUMMARY", + "ui_unit": { + "name": "cdmf.unit.analytics.line-chart", + "data": [ + { + "column": { + "name": "TIME", + "label": "time", + "ui-mapping": "x-axis" + } + }, + { + "column": { + "name": "HUMIDITY", + "label": "Humidity", + "ui-mapping": "y-axis" + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/configs/firealarm.xml b/modules/samples/firealarm/feature/feature/src/main/resources/configs/firealarm.xml new file mode 100644 index 00000000..b505b3ff --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/configs/firealarm.xml @@ -0,0 +1,25 @@ + + + + + + + jdbc/firealarmDM_DB + + diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/datasources/firealarm-datasources.xml b/modules/samples/firealarm/feature/feature/src/main/resources/datasources/firealarm-datasources.xml new file mode 100644 index 00000000..7d219601 --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/datasources/firealarm-datasources.xml @@ -0,0 +1,48 @@ + + + + + + + org.wso2.carbon.ndatasource.rdbms.RDBMSDataSourceReader + + + + firealarmDM_DB + The datasource used for the this device type + + jdbc/firealarmDM_DB + + + + jdbc:h2:repository/database/firealarmDM_DB;DB_CLOSE_ON_EXIT=FALSE + + wso2carbon + wso2carbon + org.h2.Driver + 50 + 60000 + true + SELECT 1 + 30000 + + + + + diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/dbscripts/h2.sql b/modules/samples/firealarm/feature/feature/src/main/resources/dbscripts/h2.sql new file mode 100644 index 00000000..df4b2214 --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/dbscripts/h2.sql @@ -0,0 +1,13 @@ + +-- ----------------------------------------------------- +-- Agent Database +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `firealarm_DEVICE` ( + `firealarm_DEVICE_ID` VARCHAR(45) NOT NULL , + `DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL, + `ACCESS_TOKEN` VARCHAR(50) NOT NULL, + `REFRESH_TOKEN` VARCHAR(50) NOT NULL, + PRIMARY KEY (`firealarm_DEVICE_ID`) ); + + + diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/dbscripts/mysql.sql b/modules/samples/firealarm/feature/feature/src/main/resources/dbscripts/mysql.sql new file mode 100644 index 00000000..344812ba --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/dbscripts/mysql.sql @@ -0,0 +1,12 @@ + +CREATE TABLE IF NOT EXISTS `firealarm_DEVICE` ( + `firealarm_DEVICE_ID` VARCHAR(45) NOT NULL , + `DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL, + `ACCESS_TOKEN` VARCHAR(50) NOT NULL, + `REFRESH_TOKEN` VARCHAR(50) NOT NULL, + PRIMARY KEY (`firealarm_DEVICE_ID`) ) +ENGINE = InnoDB; + + + + diff --git a/modules/samples/firealarm/feature/feature/src/main/resources/p2.inf b/modules/samples/firealarm/feature/feature/src/main/resources/p2.inf new file mode 100644 index 00000000..f747e63a --- /dev/null +++ b/modules/samples/firealarm/feature/feature/src/main/resources/p2.inf @@ -0,0 +1,16 @@ +instructions.configure = \ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../conf/device-types/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.firealarm_${feature.version}/configs/,target:${installFolder}/../../conf/device-types/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.firealarm_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/firealarm/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.firealarm_${feature.version}/agent/,target:${installFolder}/../../resources/sketches/firealarm/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.firealarm_${feature.version}/dbscripts/,target:${installFolder}/../../../dbscripts/cdm/plugins/firealarm,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.firealarm_${feature.version}/datasources/,target:${installFolder}/../../conf/datasources/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/jaggeryapps/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.firealarm_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../database/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.firealarm_${feature.version}/database/,target:${installFolder}/../../database/,overwrite:true);\ +org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/carbonapps/);\ +org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.homeautomation.firealarm_${feature.version}/carbonapps/,target:${installFolder}/../../deployment/server/carbonapps/,overwrite:true);\ diff --git a/modules/samples/firealarm/feature/pom.xml b/modules/samples/firealarm/feature/pom.xml new file mode 100644 index 00000000..86265530 --- /dev/null +++ b/modules/samples/firealarm/feature/pom.xml @@ -0,0 +1,37 @@ + + + + + + + org.homeautomation + firealarm + 1.0.0-SNAPSHOT + ../pom.xml + + firealarm-feature + 4.0.0 + pom + 1.0.0-SNAPSHOT + + feature + + \ No newline at end of file diff --git a/modules/samples/firealarm/pom.xml b/modules/samples/firealarm/pom.xml new file mode 100644 index 00000000..4d5c36dd --- /dev/null +++ b/modules/samples/firealarm/pom.xml @@ -0,0 +1,257 @@ + + + + + + + org.wso2 + wso2 + 1 + + org.homeautomation + firealarm + 1.0.0-SNAPSHOT + pom + 4.0.0 + http://wso2.com + + component + feature + + + + + org.eclipse.osgi + org.eclipse.osgi + ${eclipse.osgi.version} + provided + + + org.eclipse.equinox + org.eclipse.equinox.common + ${eclipse.equinox.common.version} + provided + + + org.testng + testng + ${testng.version} + + + junit + junit + + + org.beanshell + bsh + + + org.yaml + snakeyaml + + + provided + + + org.eclipse.osgi + org.eclipse.osgi.services + 3.3.100.v20120522-1822 + provided + + + org.wso2.carbon + org.wso2.carbon.logging + ${carbon.kernel.version} + + + org.apache.log4j.wso2 + log4j + + + commons-logging + commons-logging + + + org.wso2.carbon + org.wso2.carbon.bootstrap + + + provided + + + + org.apache.cxf + cxf-rt-frontend-jaxws + ${cxf.version} + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + ${cxf.version} + provided + + + org.apache.cxf + cxf-rt-transports-http + ${cxf.version} + provided + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + ${paho.mqtt.version} + provided + + + org.codehaus.jackson + jackson-core-asl + ${jackson.version} + + + org.codehaus.jackson + jackson-jaxrs + ${jackson.version} + + + javax + javaee-web-api + 6.0 + provided + + + javax.ws.rs + jsr311-api + ${javax.ws.rs.version} + provided + + + org.apache.httpcomponents + httpasyncclient + 4.1 + provided + + + + + + wso2.releases + WSO2 internal Repository + http://maven.wso2.org/nexus/content/repositories/releases/ + + true + daily + ignore + + + + wso2.snapshots + Apache Snapshot Repository + http://maven.wso2.org/nexus/content/repositories/snapshots/ + + true + daily + + + false + + + + wso2-nexus + WSO2 internal Repository + http://maven.wso2.org/nexus/content/groups/wso2-public/ + + true + daily + ignore + + + + + + wso2-nexus + WSO2 internal Repository + http://maven.wso2.org/nexus/content/groups/wso2-public/ + + true + daily + ignore + + + + wso2.releases + WSO2 internal Repository + http://maven.wso2.org/nexus/content/repositories/releases/ + + true + daily + ignore + + + + wso2.snapshots + WSO2 Snapshot Repository + http://maven.wso2.org/nexus/content/repositories/snapshots/ + + true + daily + + + false + + + + gcm-server-repository + GCM Server repository - GitHub + https://github.com/slorber/gcm-server-repository/raw/master/releases/ + + + + 4.4.3 + 1.1.0-SNAPSHOT + 1.1.0.SNAPSHOT + 1.0.2 + 3.0.0.wso2v1 + 3.8.1.v20120830-144521 + 2.0.4-SNAPSHOT + 2.0.4.SNAPSHOT + 1.1.1 + 2.4 + + 3.0.4.wso2v1 + 3.0.4.wso2v1 + 2.6.1 + 1.9.0 + 3.1.0.wso2v2 + 3.6.100.v20120522-1841 + 1.7 + 1.7 + org.homeautomation.firealarm + 3.8.1 + 1.4.0 + 2.4.1 + 2.3.2 + 2.6 + 1.8 + 1.7.2 + 2.5.5 + + \ No newline at end of file diff --git a/modules/samples/installer/device-deployer.xml b/modules/samples/installer/device-deployer.xml index efb3575e..4a437faa 100644 --- a/modules/samples/installer/device-deployer.xml +++ b/modules/samples/installer/device-deployer.xml @@ -35,6 +35,7 @@ samples/connectedcup samples/currentsensor + samples/firealarm @@ -64,6 +65,9 @@ org.homeautomation:org.homeautomation.currentsensor.feature:2.0.4-SNAPSHOT + + org.homeautomation:org.homeautomation.firealarm.feature:1.0.0-SNAPSHOT + @@ -97,6 +101,10 @@ org.homeautomation.currentsensor.feature.group 2.0.4-SNAPSHOT + + org.homeautomation.firealarm.feature.group + 1.0.0-SNAPSHOT +